1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/vms.termcap.c,v 1.12 2011/01/09 16:25:29 christos 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" 12232633SmpRCSID("$tcsh: vms.termcap.c,v 1.12 2011/01/09 16:25:29 christos Exp $") 13232633Smp#if defined(_VMS_POSIX) || defined(_OSD_POSIX) || defined(__ANDROID__) 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 */ 37145479Smp#ifndef fopen 3859243Sobrienextern FILE *fopen(); /* old fopen */ 39145479Smp#endif 4059243Sobrien 4159243Sobrien/* 4259243Sobrien * tgetent - get the termcap entry for terminal name, and put it 4359243Sobrien * in bp (which must be an array of 1024 chars). Returns 1 if 4459243Sobrien * termcap entry found, 0 if not found, and -1 if file not found. 4559243Sobrien */ 4659243Sobrienint 47167465Smptgetent(char *bp, char *name) 4859243Sobrien{ 49232633Smp#ifdef __ANDROID__ 50232633Smp /* Use static termcap entry since termcap file usually doesn't exist. */ 51232633Smp capab = bp; 52232633Smp strcpy(bp, 53232633Smp "linux|linux console:" 54232633Smp ":am:eo:mi:ms:xn:xo:" 55232633Smp ":it#8:" 56232633Smp ":AL=\\E[%dL:DC=\\E[%dP:DL=\\E[%dM:IC=\\E[%d@:K2=\\E[G:al=\\E[L:" 57232633Smp ":bl=^G:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:cr=^M:" 58232633Smp ":cs=\\E[%i%d;%dr:ct=\\E[3g:dc=\\E[P:dl=\\E[M:do=^J:ec=\\E[%dX:" 59232633Smp ":ei=\\E[4l:ho=\\E[H:ic=\\E[@:im=\\E[4h:k1=\\E[[A:k2=\\E[[B:" 60232633Smp ":k3=\\E[[C:k4=\\E[[D:k5=\\E[[E:k6=\\E[17~:k7=\\E[18~:k8=\\E[19~:" 61232633Smp ":k9=\\E[20~:kD=\\E[3~:kI=\\E[2~:kN=\\E[6~:kP=\\E[5~:kb=\\177:" 62232633Smp ":kd=\\E[B:kh=\\E[1~:kl=\\E[D:kr=\\E[C:ku=\\E[A:le=^H:mb=\\E[5m:" 63232633Smp ":md=\\E[1m:me=\\E[0m:mh=\\E[2m:mr=\\E[7m:nd=\\E[C:nw=^M^J:" 64232633Smp ":rc=\\E8:sc=\\E7:se=\\E[27m:sf=^J:so=\\E[7m:sr=\\EM:st=\\EH:ta=^I:" 65232633Smp ":ue=\\E[24m:up=\\E[A:us=\\E[4m:vb=200\\E[?5h\\E[?5l:" 66232633Smp ":ve=\\E[?25h\\E[?0c:vi=\\E[?25l\\E[?1c:vs=\\E[?25h\\E[?0c:" 67232633Smp ); 68232633Smp return(1); 69232633Smp#else 7059243Sobrien FILE *fp; 7159243Sobrien char *termfile; 7259243Sobrien char *cp, 7359243Sobrien *ptr, /* temporary pointer */ 74167465Smp tmp[1024]; /* buffer for terminal name *//*FIXBUF*/ 75167465Smp size_t len = strlen(name); 7659243Sobrien 7759243Sobrien capab = bp; 7859243Sobrien 7959243Sobrien /* Use TERMCAP to override default. */ 8059243Sobrien 8159243Sobrien termfile = getenv("TERMCAP"); 8259243Sobrien if (termfile == NULL ) termfile = "/etc/termcap"; 8359243Sobrien 8459243Sobrien if ((fp = fopen(termfile, "r")) == (FILE *) NULL) { 8559243Sobrien fprintf(stderr, CGETS(31, 1, 8659243Sobrien "Can't open TERMCAP: [%s]\n"), termfile); 8759243Sobrien fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile); 8859243Sobrien sleep(1); 8959243Sobrien return(-1); 9059243Sobrien } 9159243Sobrien 9259243Sobrien while (fgets(bp, 1024, fp) != NULL) { 9359243Sobrien /* Any line starting with # or NL is skipped as a comment */ 9459243Sobrien if ((*bp == '#') || (*bp == '\n')) continue; 9559243Sobrien 9659243Sobrien /* Look for lines which end with two backslashes, 9759243Sobrien and then append the next line. */ 9859243Sobrien while (*(cp = &bp[strlen(bp) - 2]) == '\\') 9959243Sobrien fgets(cp, 1024, fp); 100167465Smp 10159243Sobrien /* Skip over any spaces or tabs */ 10259243Sobrien for (++cp ; ISSPACE(*cp) ; cp++); 10359243Sobrien 10459243Sobrien /* Make sure "name" matches exactly (efth) */ 10559243Sobrien 10659243Sobrien/* Here we might want to look at any aliases as well. We'll use 10759243Sobriensscanf to look at aliases. These are delimited by '|'. */ 10859243Sobrien 10959243Sobrien sscanf(bp,"%[^|]",tmp); 11059243Sobrien if (strncmp(name, tmp, len) == 0) { 11159243Sobrien fclose(fp); 11259243Sobrien#ifdef DEBUG 11359243Sobrien fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 11459243Sobrien sleep(1); 11559243Sobrien#endif /* DEBUG */ 11659243Sobrien return(1); 11759243Sobrien } 11859243Sobrien ptr = bp; 11959243Sobrien while ((ptr = strchr(ptr,'|')) != NULL) { 12059243Sobrien ptr++; 12159243Sobrien if (strchr(ptr,'|') == NULL) break; 12259243Sobrien sscanf(ptr,"%[^|]",tmp); 12359243Sobrien if (strncmp(name, tmp, len) == 0) { 12459243Sobrien fclose(fp); 12559243Sobrien#ifdef DEBUG 12659243Sobrien fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 12759243Sobrien sleep(1); 12859243Sobrien#endif /* DEBUG */ 12959243Sobrien return(1); 13059243Sobrien } 13159243Sobrien } 13259243Sobrien } 13359243Sobrien /* If we get here, then we haven't found a match. */ 13459243Sobrien fclose(fp); 13559243Sobrien#ifdef DEBUG 13659243Sobrien fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"), 13759243Sobrien name, termfile); 13859243Sobrien sleep(1); 13959243Sobrien#endif /* DEBUG */ 14059243Sobrien return(0); 141232633Smp#endif /* ANDROID */ 14259243Sobrien} 14359243Sobrien 14459243Sobrien/* 14559243Sobrien * tgetnum - get the numeric terminal capability corresponding 14659243Sobrien * to id. Returns the value, -1 if invalid. 14759243Sobrien */ 14859243Sobrienint 149167465Smptgetnum(char *id) 15059243Sobrien{ 15159243Sobrien char *cp; 15259243Sobrien int ret; 15359243Sobrien 15459243Sobrien if ((cp = capab) == NULL || id == NULL) 15559243Sobrien return(-1); 15659243Sobrien while (*++cp != ':') 15759243Sobrien ; 15859243Sobrien for (++cp ; *cp ; cp++) { 15959243Sobrien while (ISSPACE(*cp)) 16059243Sobrien cp++; 16159243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) { 16259243Sobrien while (*cp && *cp != ':' && *cp != '#') 16359243Sobrien cp++; 16459243Sobrien if (*cp != '#') 16559243Sobrien return(-1); 16659243Sobrien for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++) 16759243Sobrien ret = ret * 10 + *cp - '0'; 16859243Sobrien return(ret); 16959243Sobrien } 17059243Sobrien while (*cp && *cp != ':') 17159243Sobrien cp++; 17259243Sobrien } 17359243Sobrien return(-1); 17459243Sobrien} 17559243Sobrien 17659243Sobrien/* 17759243Sobrien * tgetflag - get the boolean flag corresponding to id. Returns -1 17859243Sobrien * if invalid, 0 if the flag is not in termcap entry, or 1 if it is 17959243Sobrien * present. 18059243Sobrien */ 18159243Sobrienint 182167465Smptgetflag(char *id) 18359243Sobrien{ 18459243Sobrien char *cp; 18559243Sobrien 18659243Sobrien if ((cp = capab) == NULL || id == NULL) 18759243Sobrien return(-1); 18859243Sobrien while (*++cp != ':') 18959243Sobrien ; 19059243Sobrien for (++cp ; *cp ; cp++) { 19159243Sobrien while (ISSPACE(*cp)) 19259243Sobrien cp++; 19359243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) 19459243Sobrien return(1); 19559243Sobrien while (*cp && *cp != ':') 19659243Sobrien cp++; 19759243Sobrien } 19859243Sobrien return(0); 19959243Sobrien} 20059243Sobrien 20159243Sobrien/* 20259243Sobrien * tgetstr - get the string capability corresponding to id and place 20359243Sobrien * it in area (advancing area at same time). Expand escape sequences 20459243Sobrien * etc. Returns the string, or NULL if it can't do it. 20559243Sobrien */ 20659243Sobrienchar * 207167465Smptgetstr(char *id, char **area) 20859243Sobrien{ 20959243Sobrien char *cp; 21059243Sobrien char *ret; 21159243Sobrien int i; 21259243Sobrien 21359243Sobrien if ((cp = capab) == NULL || id == NULL) 21459243Sobrien return(NULL); 21559243Sobrien while (*++cp != ':') 21659243Sobrien ; 21759243Sobrien for (++cp ; *cp ; cp++) { 21859243Sobrien while (ISSPACE(*cp)) 21959243Sobrien cp++; 22059243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) { 22159243Sobrien while (*cp && *cp != ':' && *cp != '=') 22259243Sobrien cp++; 22359243Sobrien if (*cp != '=') 22459243Sobrien return(NULL); 22559243Sobrien for (ret = *area, cp++; *cp && *cp != ':' ; 22659243Sobrien (*area)++, cp++) 22759243Sobrien switch(*cp) { 22859243Sobrien case '^' : 22959243Sobrien **area = *++cp - '@'; /* fix (efth)*/ 23059243Sobrien break; 23159243Sobrien case '\\' : 23259243Sobrien switch(*++cp) { 23359243Sobrien case 'E' : 23459243Sobrien **area = CTL_ESC('\033'); 23559243Sobrien break; 23659243Sobrien case 'n' : 23759243Sobrien **area = '\n'; 23859243Sobrien break; 23959243Sobrien case 'r' : 24059243Sobrien **area = '\r'; 24159243Sobrien break; 24259243Sobrien case 't' : 24359243Sobrien **area = '\t'; 24459243Sobrien break; 24559243Sobrien case 'b' : 24659243Sobrien **area = '\b'; 24759243Sobrien break; 24859243Sobrien case 'f' : 24959243Sobrien **area = '\f'; 25059243Sobrien break; 25159243Sobrien case '0' : 25259243Sobrien case '1' : 25359243Sobrien case '2' : 25459243Sobrien case '3' : 25559243Sobrien for (i=0 ; *cp && ISDIGIT(*cp) ; 25659243Sobrien cp++) 25759243Sobrien i = i * 8 + *cp - '0'; 25859243Sobrien **area = i; 25959243Sobrien cp--; 26059243Sobrien break; 26159243Sobrien case '^' : 26259243Sobrien case '\\' : 26359243Sobrien **area = *cp; 26459243Sobrien break; 26559243Sobrien } 26659243Sobrien break; 26759243Sobrien default : 26859243Sobrien **area = *cp; 26959243Sobrien } 27059243Sobrien *(*area)++ = '\0'; 27159243Sobrien return(ret); 27259243Sobrien } 27359243Sobrien while (*cp && *cp != ':') 27459243Sobrien cp++; 27559243Sobrien } 27659243Sobrien return(NULL); 27759243Sobrien} 27859243Sobrien 27959243Sobrien/* 28059243Sobrien * tgoto - given the cursor motion string cm, make up the string 28159243Sobrien * for the cursor to go to (destcol, destline), and return the string. 28259243Sobrien * Returns "OOPS" if something's gone wrong, or the string otherwise. 28359243Sobrien */ 28459243Sobrienchar * 285167465Smptgoto(char *cm, int destcol, int destline) 28659243Sobrien{ 287145479Smp char *rp; 28859243Sobrien static char ret[24]; 28959243Sobrien int incr = 0; 29059243Sobrien int argno = 0, numval; 29159243Sobrien 29259243Sobrien for (rp = ret ; *cm ; cm++) { 29359243Sobrien switch(*cm) { 29459243Sobrien case '%' : 29559243Sobrien switch(*++cm) { 29659243Sobrien case '+' : 29759243Sobrien numval = (argno == 0 ? destline : destcol); 29859243Sobrien argno = 1 - argno; 29959243Sobrien *rp++ = numval + incr + *++cm; 30059243Sobrien break; 30159243Sobrien 30259243Sobrien case '%' : 30359243Sobrien *rp++ = '%'; 30459243Sobrien break; 30559243Sobrien 30659243Sobrien case 'i' : 30759243Sobrien incr = 1; 30859243Sobrien break; 30959243Sobrien 31059243Sobrien case 'd' : 31159243Sobrien numval = (argno == 0 ? destline : destcol); 31259243Sobrien numval += incr; 31359243Sobrien argno = 1 - argno; 31459243Sobrien *rp++ = '0' + (numval/10); 31559243Sobrien *rp++ = '0' + (numval%10); 31659243Sobrien break; 31759243Sobrien 31859243Sobrien case 'r' : 31959243Sobrien argno = 1; 32059243Sobrien break; 32159243Sobrien } 32259243Sobrien 32359243Sobrien break; 32459243Sobrien default : 32559243Sobrien *rp++ = *cm; 32659243Sobrien } 32759243Sobrien } 32859243Sobrien *rp = '\0'; 32959243Sobrien return(ret); 33059243Sobrien} 33159243Sobrien 33259243Sobrien/* 33359243Sobrien * tputs - put the string cp out onto the terminal, using the function 33459243Sobrien * outc. This should do padding for the terminal, but I can't find a 33559243Sobrien * terminal that needs padding at the moment... 33659243Sobrien */ 33759243Sobrienint 338167465Smptputs(char *cp, int affcnt, int (*outc)()) 33959243Sobrien{ 340145479Smp unsigned long delay = 0; 341145479Smp 34259243Sobrien if (cp == NULL) 34359243Sobrien return(1); 34459243Sobrien /* do any padding interpretation - left null for MINIX just now */ 345145479Smp for (delay = 0; *cp && ISDIGIT(*cp) ; cp++) 346145479Smp delay = delay * 10 + *cp - '0'; 34759243Sobrien while (*cp) 34859243Sobrien (*outc)(*cp++); 349145479Smp#ifdef _OSD_POSIX 350145479Smp usleep(delay*100); /* strictly spoken, it should be *1000 */ 351145479Smp#endif 35259243Sobrien return(1); 35359243Sobrien} 35469408Sache#endif /* _VMS_POSIX || _OSD_POSIX */ 355