vms.termcap.c revision 69408
169408Sache/* $Header: /src/pub/tcsh/vms.termcap.c,v 1.6 2000/06/10 23:32:42 kim Exp $ */ 259243Sobrien/* 359243Sobrien * termcap.c 1.1 20/7/87 agc Joypace Ltd 459243Sobrien * 559243Sobrien * Copyright Joypace Ltd, London, UK, 1987. All rights reserved. 659243Sobrien * This file may be freely distributed provided that this notice 759243Sobrien * remains attached. 859243Sobrien * 959243Sobrien * A public domain implementation of the termcap(3) routines. 1059243Sobrien */ 1159243Sobrien#include "sh.h" 1269408SacheRCSID("$Id: vms.termcap.c,v 1.6 2000/06/10 23:32:42 kim Exp $") 1359243Sobrien#if defined(_VMS_POSIX) || defined(_OSD_POSIX) 1459243Sobrien/* efth 1988-Apr-29 1559243Sobrien 1659243Sobrien - Correct when TERM != name and TERMCAP is defined [tgetent] 1759243Sobrien - Correct the comparison for the terminal name [tgetent] 1859243Sobrien - Correct the value of ^x escapes [tgetstr] 1959243Sobrien - Added %r to reverse row/column [tgoto] 2059243Sobrien 2159243Sobrien Paul Gillingwater <paul@actrix.gen.nz> July 1992 2259243Sobrien - Modified to allow terminal aliases in termcap file 2359243Sobrien - Uses TERMCAP environment variable for file only 2459243Sobrien*/ 2559243Sobrien 2659243Sobrien#include <stdio.h> 2759243Sobrien#include <string.h> 2859243Sobrien 2959243Sobrien#define CAPABLEN 2 3059243Sobrien 3159243Sobrien#define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') 3259243Sobrien#define ISDIGIT(x) ((x) >= '0' && (x) <= '9') 3359243Sobrien 3459243Sobrienchar *capab; /* the capability itself */ 3559243Sobrien 3659243Sobrienextern char *getenv(); /* new, improved getenv */ 3759243Sobrienextern FILE *fopen(); /* old fopen */ 3859243Sobrien 3959243Sobrien/* 4059243Sobrien * tgetent - get the termcap entry for terminal name, and put it 4159243Sobrien * in bp (which must be an array of 1024 chars). Returns 1 if 4259243Sobrien * termcap entry found, 0 if not found, and -1 if file not found. 4359243Sobrien */ 4459243Sobrien 4559243Sobrienint 4659243Sobrientgetent(bp, name) 4759243Sobrienchar *bp; 4859243Sobrienchar *name; 4959243Sobrien{ 5059243Sobrien FILE *fp; 5159243Sobrien char *termfile; 5259243Sobrien char *cp, 5359243Sobrien *ptr, /* temporary pointer */ 5459243Sobrien tmp[1024]; /* buffer for terminal name */ 5559243Sobrien short len = strlen(name); 5659243Sobrien 5759243Sobrien capab = bp; 5859243Sobrien 5959243Sobrien /* Use TERMCAP to override default. */ 6059243Sobrien 6159243Sobrien termfile = getenv("TERMCAP"); 6259243Sobrien if (termfile == NULL ) termfile = "/etc/termcap"; 6359243Sobrien 6459243Sobrien if ((fp = fopen(termfile, "r")) == (FILE *) NULL) { 6559243Sobrien fprintf(stderr, CGETS(31, 1, 6659243Sobrien "Can't open TERMCAP: [%s]\n"), termfile); 6759243Sobrien fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile); 6859243Sobrien sleep(1); 6959243Sobrien return(-1); 7059243Sobrien } 7159243Sobrien 7259243Sobrien while (fgets(bp, 1024, fp) != NULL) { 7359243Sobrien /* Any line starting with # or NL is skipped as a comment */ 7459243Sobrien if ((*bp == '#') || (*bp == '\n')) continue; 7559243Sobrien 7659243Sobrien /* Look for lines which end with two backslashes, 7759243Sobrien and then append the next line. */ 7859243Sobrien while (*(cp = &bp[strlen(bp) - 2]) == '\\') 7959243Sobrien fgets(cp, 1024, fp); 8059243Sobrien 8159243Sobrien /* Skip over any spaces or tabs */ 8259243Sobrien for (++cp ; ISSPACE(*cp) ; cp++); 8359243Sobrien 8459243Sobrien /* Make sure "name" matches exactly (efth) */ 8559243Sobrien 8659243Sobrien/* Here we might want to look at any aliases as well. We'll use 8759243Sobriensscanf to look at aliases. These are delimited by '|'. */ 8859243Sobrien 8959243Sobrien sscanf(bp,"%[^|]",tmp); 9059243Sobrien if (strncmp(name, tmp, len) == 0) { 9159243Sobrien fclose(fp); 9259243Sobrien#ifdef DEBUG 9359243Sobrien fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 9459243Sobrien sleep(1); 9559243Sobrien#endif /* DEBUG */ 9659243Sobrien return(1); 9759243Sobrien } 9859243Sobrien ptr = bp; 9959243Sobrien while ((ptr = strchr(ptr,'|')) != NULL) { 10059243Sobrien ptr++; 10159243Sobrien if (strchr(ptr,'|') == NULL) break; 10259243Sobrien sscanf(ptr,"%[^|]",tmp); 10359243Sobrien if (strncmp(name, tmp, len) == 0) { 10459243Sobrien fclose(fp); 10559243Sobrien#ifdef DEBUG 10659243Sobrien fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 10759243Sobrien sleep(1); 10859243Sobrien#endif /* DEBUG */ 10959243Sobrien return(1); 11059243Sobrien } 11159243Sobrien } 11259243Sobrien } 11359243Sobrien /* If we get here, then we haven't found a match. */ 11459243Sobrien fclose(fp); 11559243Sobrien#ifdef DEBUG 11659243Sobrien fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"), 11759243Sobrien name, termfile); 11859243Sobrien sleep(1); 11959243Sobrien#endif /* DEBUG */ 12059243Sobrien return(0); 12159243Sobrien 12259243Sobrien} 12359243Sobrien 12459243Sobrien/* 12559243Sobrien * tgetnum - get the numeric terminal capability corresponding 12659243Sobrien * to id. Returns the value, -1 if invalid. 12759243Sobrien */ 12859243Sobrienint 12959243Sobrientgetnum(id) 13059243Sobrienchar *id; 13159243Sobrien{ 13259243Sobrien char *cp; 13359243Sobrien int ret; 13459243Sobrien 13559243Sobrien if ((cp = capab) == NULL || id == NULL) 13659243Sobrien return(-1); 13759243Sobrien while (*++cp != ':') 13859243Sobrien ; 13959243Sobrien for (++cp ; *cp ; cp++) { 14059243Sobrien while (ISSPACE(*cp)) 14159243Sobrien cp++; 14259243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) { 14359243Sobrien while (*cp && *cp != ':' && *cp != '#') 14459243Sobrien cp++; 14559243Sobrien if (*cp != '#') 14659243Sobrien return(-1); 14759243Sobrien for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++) 14859243Sobrien ret = ret * 10 + *cp - '0'; 14959243Sobrien return(ret); 15059243Sobrien } 15159243Sobrien while (*cp && *cp != ':') 15259243Sobrien cp++; 15359243Sobrien } 15459243Sobrien return(-1); 15559243Sobrien} 15659243Sobrien 15759243Sobrien/* 15859243Sobrien * tgetflag - get the boolean flag corresponding to id. Returns -1 15959243Sobrien * if invalid, 0 if the flag is not in termcap entry, or 1 if it is 16059243Sobrien * present. 16159243Sobrien */ 16259243Sobrienint 16359243Sobrientgetflag(id) 16459243Sobrienchar *id; 16559243Sobrien{ 16659243Sobrien char *cp; 16759243Sobrien 16859243Sobrien if ((cp = capab) == NULL || id == NULL) 16959243Sobrien return(-1); 17059243Sobrien while (*++cp != ':') 17159243Sobrien ; 17259243Sobrien for (++cp ; *cp ; cp++) { 17359243Sobrien while (ISSPACE(*cp)) 17459243Sobrien cp++; 17559243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) 17659243Sobrien return(1); 17759243Sobrien while (*cp && *cp != ':') 17859243Sobrien cp++; 17959243Sobrien } 18059243Sobrien return(0); 18159243Sobrien} 18259243Sobrien 18359243Sobrien/* 18459243Sobrien * tgetstr - get the string capability corresponding to id and place 18559243Sobrien * it in area (advancing area at same time). Expand escape sequences 18659243Sobrien * etc. Returns the string, or NULL if it can't do it. 18759243Sobrien */ 18859243Sobrienchar * 18959243Sobrientgetstr(id, area) 19059243Sobrienchar *id; 19159243Sobrienchar **area; 19259243Sobrien{ 19359243Sobrien char *cp; 19459243Sobrien char *ret; 19559243Sobrien int i; 19659243Sobrien 19759243Sobrien if ((cp = capab) == NULL || id == NULL) 19859243Sobrien return(NULL); 19959243Sobrien while (*++cp != ':') 20059243Sobrien ; 20159243Sobrien for (++cp ; *cp ; cp++) { 20259243Sobrien while (ISSPACE(*cp)) 20359243Sobrien cp++; 20459243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) { 20559243Sobrien while (*cp && *cp != ':' && *cp != '=') 20659243Sobrien cp++; 20759243Sobrien if (*cp != '=') 20859243Sobrien return(NULL); 20959243Sobrien for (ret = *area, cp++; *cp && *cp != ':' ; 21059243Sobrien (*area)++, cp++) 21159243Sobrien switch(*cp) { 21259243Sobrien case '^' : 21359243Sobrien **area = *++cp - '@'; /* fix (efth)*/ 21459243Sobrien break; 21559243Sobrien case '\\' : 21659243Sobrien switch(*++cp) { 21759243Sobrien case 'E' : 21859243Sobrien **area = CTL_ESC('\033'); 21959243Sobrien break; 22059243Sobrien case 'n' : 22159243Sobrien **area = '\n'; 22259243Sobrien break; 22359243Sobrien case 'r' : 22459243Sobrien **area = '\r'; 22559243Sobrien break; 22659243Sobrien case 't' : 22759243Sobrien **area = '\t'; 22859243Sobrien break; 22959243Sobrien case 'b' : 23059243Sobrien **area = '\b'; 23159243Sobrien break; 23259243Sobrien case 'f' : 23359243Sobrien **area = '\f'; 23459243Sobrien break; 23559243Sobrien case '0' : 23659243Sobrien case '1' : 23759243Sobrien case '2' : 23859243Sobrien case '3' : 23959243Sobrien for (i=0 ; *cp && ISDIGIT(*cp) ; 24059243Sobrien cp++) 24159243Sobrien i = i * 8 + *cp - '0'; 24259243Sobrien **area = i; 24359243Sobrien cp--; 24459243Sobrien break; 24559243Sobrien case '^' : 24659243Sobrien case '\\' : 24759243Sobrien **area = *cp; 24859243Sobrien break; 24959243Sobrien } 25059243Sobrien break; 25159243Sobrien default : 25259243Sobrien **area = *cp; 25359243Sobrien } 25459243Sobrien *(*area)++ = '\0'; 25559243Sobrien return(ret); 25659243Sobrien } 25759243Sobrien while (*cp && *cp != ':') 25859243Sobrien cp++; 25959243Sobrien } 26059243Sobrien return(NULL); 26159243Sobrien} 26259243Sobrien 26359243Sobrien/* 26459243Sobrien * tgoto - given the cursor motion string cm, make up the string 26559243Sobrien * for the cursor to go to (destcol, destline), and return the string. 26659243Sobrien * Returns "OOPS" if something's gone wrong, or the string otherwise. 26759243Sobrien */ 26859243Sobrienchar * 26959243Sobrientgoto(cm, destcol, destline) 27059243Sobrienchar *cm; 27159243Sobrienint destcol; 27259243Sobrienint destline; 27359243Sobrien{ 27459243Sobrien register char *rp; 27559243Sobrien static char ret[24]; 27659243Sobrien int incr = 0; 27759243Sobrien int argno = 0, numval; 27859243Sobrien 27959243Sobrien for (rp = ret ; *cm ; cm++) { 28059243Sobrien switch(*cm) { 28159243Sobrien case '%' : 28259243Sobrien switch(*++cm) { 28359243Sobrien case '+' : 28459243Sobrien numval = (argno == 0 ? destline : destcol); 28559243Sobrien argno = 1 - argno; 28659243Sobrien *rp++ = numval + incr + *++cm; 28759243Sobrien break; 28859243Sobrien 28959243Sobrien case '%' : 29059243Sobrien *rp++ = '%'; 29159243Sobrien break; 29259243Sobrien 29359243Sobrien case 'i' : 29459243Sobrien incr = 1; 29559243Sobrien break; 29659243Sobrien 29759243Sobrien case 'd' : 29859243Sobrien numval = (argno == 0 ? destline : destcol); 29959243Sobrien numval += incr; 30059243Sobrien argno = 1 - argno; 30159243Sobrien *rp++ = '0' + (numval/10); 30259243Sobrien *rp++ = '0' + (numval%10); 30359243Sobrien break; 30459243Sobrien 30559243Sobrien case 'r' : 30659243Sobrien argno = 1; 30759243Sobrien break; 30859243Sobrien } 30959243Sobrien 31059243Sobrien break; 31159243Sobrien default : 31259243Sobrien *rp++ = *cm; 31359243Sobrien } 31459243Sobrien } 31559243Sobrien *rp = '\0'; 31659243Sobrien return(ret); 31759243Sobrien} 31859243Sobrien 31959243Sobrien/* 32059243Sobrien * tputs - put the string cp out onto the terminal, using the function 32159243Sobrien * outc. This should do padding for the terminal, but I can't find a 32259243Sobrien * terminal that needs padding at the moment... 32359243Sobrien */ 32459243Sobrienint 32559243Sobrientputs(cp, affcnt, outc) 32659243Sobrienregister char *cp; 32759243Sobrienint affcnt; 32859243Sobrienint (*outc)(); 32959243Sobrien{ 33059243Sobrien if (cp == NULL) 33159243Sobrien return(1); 33259243Sobrien /* do any padding interpretation - left null for MINIX just now */ 33359243Sobrien while (*cp) 33459243Sobrien (*outc)(*cp++); 33559243Sobrien return(1); 33659243Sobrien} 33769408Sache#endif /* _VMS_POSIX || _OSD_POSIX */ 338