159243Sobrien/* 259243Sobrien * termcap.c 1.1 20/7/87 agc Joypace Ltd 359243Sobrien * 459243Sobrien * Copyright Joypace Ltd, London, UK, 1987. All rights reserved. 559243Sobrien * This file may be freely distributed provided that this notice 659243Sobrien * remains attached. 759243Sobrien * 859243Sobrien * A public domain implementation of the termcap(3) routines. 959243Sobrien */ 1059243Sobrien#include "sh.h" 11354195Sbrooks 12231990Smp#if defined(_VMS_POSIX) || defined(_OSD_POSIX) || defined(__ANDROID__) 1359243Sobrien/* efth 1988-Apr-29 1459243Sobrien 1559243Sobrien - Correct when TERM != name and TERMCAP is defined [tgetent] 1659243Sobrien - Correct the comparison for the terminal name [tgetent] 1759243Sobrien - Correct the value of ^x escapes [tgetstr] 1859243Sobrien - Added %r to reverse row/column [tgoto] 1959243Sobrien 2059243Sobrien Paul Gillingwater <paul@actrix.gen.nz> July 1992 2159243Sobrien - Modified to allow terminal aliases in termcap file 2259243Sobrien - Uses TERMCAP environment variable for file only 2359243Sobrien*/ 2459243Sobrien 2559243Sobrien#include <stdio.h> 2659243Sobrien#include <string.h> 2759243Sobrien 2859243Sobrien#define CAPABLEN 2 2959243Sobrien 3059243Sobrien#define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') 3159243Sobrien#define ISDIGIT(x) ((x) >= '0' && (x) <= '9') 3259243Sobrien 3359243Sobrienchar *capab; /* the capability itself */ 3459243Sobrien 3559243Sobrienextern char *getenv(); /* new, improved getenv */ 36145479Smp#ifndef fopen 3759243Sobrienextern FILE *fopen(); /* old fopen */ 38145479Smp#endif 3959243Sobrien 4059243Sobrien/* 4159243Sobrien * tgetent - get the termcap entry for terminal name, and put it 4259243Sobrien * in bp (which must be an array of 1024 chars). Returns 1 if 4359243Sobrien * termcap entry found, 0 if not found, and -1 if file not found. 4459243Sobrien */ 4559243Sobrienint 46167465Smptgetent(char *bp, char *name) 4759243Sobrien{ 48231990Smp#ifdef __ANDROID__ 49231990Smp /* Use static termcap entry since termcap file usually doesn't exist. */ 50231990Smp capab = bp; 51231990Smp strcpy(bp, 52231990Smp "linux|linux console:" 53231990Smp ":am:eo:mi:ms:xn:xo:" 54231990Smp ":it#8:" 55231990Smp ":AL=\\E[%dL:DC=\\E[%dP:DL=\\E[%dM:IC=\\E[%d@:K2=\\E[G:al=\\E[L:" 56231990Smp ":bl=^G:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:cr=^M:" 57231990Smp ":cs=\\E[%i%d;%dr:ct=\\E[3g:dc=\\E[P:dl=\\E[M:do=^J:ec=\\E[%dX:" 58231990Smp ":ei=\\E[4l:ho=\\E[H:ic=\\E[@:im=\\E[4h:k1=\\E[[A:k2=\\E[[B:" 59231990Smp ":k3=\\E[[C:k4=\\E[[D:k5=\\E[[E:k6=\\E[17~:k7=\\E[18~:k8=\\E[19~:" 60231990Smp ":k9=\\E[20~:kD=\\E[3~:kI=\\E[2~:kN=\\E[6~:kP=\\E[5~:kb=\\177:" 61231990Smp ":kd=\\E[B:kh=\\E[1~:kl=\\E[D:kr=\\E[C:ku=\\E[A:le=^H:mb=\\E[5m:" 62231990Smp ":md=\\E[1m:me=\\E[0m:mh=\\E[2m:mr=\\E[7m:nd=\\E[C:nw=^M^J:" 63231990Smp ":rc=\\E8:sc=\\E7:se=\\E[27m:sf=^J:so=\\E[7m:sr=\\EM:st=\\EH:ta=^I:" 64231990Smp ":ue=\\E[24m:up=\\E[A:us=\\E[4m:vb=200\\E[?5h\\E[?5l:" 65231990Smp ":ve=\\E[?25h\\E[?0c:vi=\\E[?25l\\E[?1c:vs=\\E[?25h\\E[?0c:" 66231990Smp ); 67231990Smp return(1); 68231990Smp#else 6959243Sobrien FILE *fp; 7059243Sobrien char *termfile; 7159243Sobrien char *cp, 7259243Sobrien *ptr, /* temporary pointer */ 73167465Smp tmp[1024]; /* buffer for terminal name *//*FIXBUF*/ 74167465Smp size_t len = strlen(name); 7559243Sobrien 7659243Sobrien capab = bp; 7759243Sobrien 7859243Sobrien /* Use TERMCAP to override default. */ 7959243Sobrien 8059243Sobrien termfile = getenv("TERMCAP"); 8159243Sobrien if (termfile == NULL ) termfile = "/etc/termcap"; 8259243Sobrien 8359243Sobrien if ((fp = fopen(termfile, "r")) == (FILE *) NULL) { 8459243Sobrien fprintf(stderr, CGETS(31, 1, 8559243Sobrien "Can't open TERMCAP: [%s]\n"), termfile); 8659243Sobrien fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile); 8759243Sobrien sleep(1); 8859243Sobrien return(-1); 8959243Sobrien } 9059243Sobrien 9159243Sobrien while (fgets(bp, 1024, fp) != NULL) { 9259243Sobrien /* Any line starting with # or NL is skipped as a comment */ 9359243Sobrien if ((*bp == '#') || (*bp == '\n')) continue; 9459243Sobrien 9559243Sobrien /* Look for lines which end with two backslashes, 9659243Sobrien and then append the next line. */ 9759243Sobrien while (*(cp = &bp[strlen(bp) - 2]) == '\\') 9859243Sobrien fgets(cp, 1024, fp); 99167465Smp 10059243Sobrien /* Skip over any spaces or tabs */ 10159243Sobrien for (++cp ; ISSPACE(*cp) ; cp++); 10259243Sobrien 10359243Sobrien /* Make sure "name" matches exactly (efth) */ 10459243Sobrien 10559243Sobrien/* Here we might want to look at any aliases as well. We'll use 10659243Sobriensscanf to look at aliases. These are delimited by '|'. */ 10759243Sobrien 10859243Sobrien sscanf(bp,"%[^|]",tmp); 10959243Sobrien if (strncmp(name, tmp, len) == 0) { 11059243Sobrien fclose(fp); 11159243Sobrien#ifdef DEBUG 11259243Sobrien fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 11359243Sobrien sleep(1); 11459243Sobrien#endif /* DEBUG */ 11559243Sobrien return(1); 11659243Sobrien } 11759243Sobrien ptr = bp; 11859243Sobrien while ((ptr = strchr(ptr,'|')) != NULL) { 11959243Sobrien ptr++; 12059243Sobrien if (strchr(ptr,'|') == NULL) break; 12159243Sobrien sscanf(ptr,"%[^|]",tmp); 12259243Sobrien if (strncmp(name, tmp, len) == 0) { 12359243Sobrien fclose(fp); 12459243Sobrien#ifdef DEBUG 12559243Sobrien fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 12659243Sobrien sleep(1); 12759243Sobrien#endif /* DEBUG */ 12859243Sobrien return(1); 12959243Sobrien } 13059243Sobrien } 13159243Sobrien } 13259243Sobrien /* If we get here, then we haven't found a match. */ 13359243Sobrien fclose(fp); 13459243Sobrien#ifdef DEBUG 13559243Sobrien fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"), 13659243Sobrien name, termfile); 13759243Sobrien sleep(1); 13859243Sobrien#endif /* DEBUG */ 13959243Sobrien return(0); 140231990Smp#endif /* ANDROID */ 14159243Sobrien} 14259243Sobrien 14359243Sobrien/* 14459243Sobrien * tgetnum - get the numeric terminal capability corresponding 14559243Sobrien * to id. Returns the value, -1 if invalid. 14659243Sobrien */ 14759243Sobrienint 148167465Smptgetnum(char *id) 14959243Sobrien{ 15059243Sobrien char *cp; 15159243Sobrien int ret; 15259243Sobrien 15359243Sobrien if ((cp = capab) == NULL || id == NULL) 15459243Sobrien return(-1); 15559243Sobrien while (*++cp != ':') 15659243Sobrien ; 15759243Sobrien for (++cp ; *cp ; cp++) { 15859243Sobrien while (ISSPACE(*cp)) 15959243Sobrien cp++; 16059243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) { 16159243Sobrien while (*cp && *cp != ':' && *cp != '#') 16259243Sobrien cp++; 16359243Sobrien if (*cp != '#') 16459243Sobrien return(-1); 16559243Sobrien for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++) 16659243Sobrien ret = ret * 10 + *cp - '0'; 16759243Sobrien return(ret); 16859243Sobrien } 16959243Sobrien while (*cp && *cp != ':') 17059243Sobrien cp++; 17159243Sobrien } 17259243Sobrien return(-1); 17359243Sobrien} 17459243Sobrien 17559243Sobrien/* 17659243Sobrien * tgetflag - get the boolean flag corresponding to id. Returns -1 17759243Sobrien * if invalid, 0 if the flag is not in termcap entry, or 1 if it is 17859243Sobrien * present. 17959243Sobrien */ 18059243Sobrienint 181167465Smptgetflag(char *id) 18259243Sobrien{ 18359243Sobrien char *cp; 18459243Sobrien 18559243Sobrien if ((cp = capab) == NULL || id == NULL) 18659243Sobrien return(-1); 18759243Sobrien while (*++cp != ':') 18859243Sobrien ; 18959243Sobrien for (++cp ; *cp ; cp++) { 19059243Sobrien while (ISSPACE(*cp)) 19159243Sobrien cp++; 19259243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) 19359243Sobrien return(1); 19459243Sobrien while (*cp && *cp != ':') 19559243Sobrien cp++; 19659243Sobrien } 19759243Sobrien return(0); 19859243Sobrien} 19959243Sobrien 20059243Sobrien/* 20159243Sobrien * tgetstr - get the string capability corresponding to id and place 20259243Sobrien * it in area (advancing area at same time). Expand escape sequences 20359243Sobrien * etc. Returns the string, or NULL if it can't do it. 20459243Sobrien */ 20559243Sobrienchar * 206167465Smptgetstr(char *id, char **area) 20759243Sobrien{ 20859243Sobrien char *cp; 20959243Sobrien char *ret; 21059243Sobrien int i; 21159243Sobrien 21259243Sobrien if ((cp = capab) == NULL || id == NULL) 21359243Sobrien return(NULL); 21459243Sobrien while (*++cp != ':') 21559243Sobrien ; 21659243Sobrien for (++cp ; *cp ; cp++) { 21759243Sobrien while (ISSPACE(*cp)) 21859243Sobrien cp++; 21959243Sobrien if (strncmp(cp, id, CAPABLEN) == 0) { 22059243Sobrien while (*cp && *cp != ':' && *cp != '=') 22159243Sobrien cp++; 22259243Sobrien if (*cp != '=') 22359243Sobrien return(NULL); 22459243Sobrien for (ret = *area, cp++; *cp && *cp != ':' ; 22559243Sobrien (*area)++, cp++) 22659243Sobrien switch(*cp) { 22759243Sobrien case '^' : 22859243Sobrien **area = *++cp - '@'; /* fix (efth)*/ 22959243Sobrien break; 23059243Sobrien case '\\' : 23159243Sobrien switch(*++cp) { 23259243Sobrien case 'E' : 23359243Sobrien **area = CTL_ESC('\033'); 23459243Sobrien break; 23559243Sobrien case 'n' : 23659243Sobrien **area = '\n'; 23759243Sobrien break; 23859243Sobrien case 'r' : 23959243Sobrien **area = '\r'; 24059243Sobrien break; 24159243Sobrien case 't' : 24259243Sobrien **area = '\t'; 24359243Sobrien break; 24459243Sobrien case 'b' : 24559243Sobrien **area = '\b'; 24659243Sobrien break; 24759243Sobrien case 'f' : 24859243Sobrien **area = '\f'; 24959243Sobrien break; 25059243Sobrien case '0' : 25159243Sobrien case '1' : 25259243Sobrien case '2' : 25359243Sobrien case '3' : 25459243Sobrien for (i=0 ; *cp && ISDIGIT(*cp) ; 25559243Sobrien cp++) 25659243Sobrien i = i * 8 + *cp - '0'; 25759243Sobrien **area = i; 25859243Sobrien cp--; 25959243Sobrien break; 26059243Sobrien case '^' : 26159243Sobrien case '\\' : 26259243Sobrien **area = *cp; 26359243Sobrien break; 26459243Sobrien } 26559243Sobrien break; 26659243Sobrien default : 26759243Sobrien **area = *cp; 26859243Sobrien } 26959243Sobrien *(*area)++ = '\0'; 27059243Sobrien return(ret); 27159243Sobrien } 27259243Sobrien while (*cp && *cp != ':') 27359243Sobrien cp++; 27459243Sobrien } 27559243Sobrien return(NULL); 27659243Sobrien} 27759243Sobrien 27859243Sobrien/* 27959243Sobrien * tgoto - given the cursor motion string cm, make up the string 28059243Sobrien * for the cursor to go to (destcol, destline), and return the string. 28159243Sobrien * Returns "OOPS" if something's gone wrong, or the string otherwise. 28259243Sobrien */ 28359243Sobrienchar * 284167465Smptgoto(char *cm, int destcol, int destline) 28559243Sobrien{ 286145479Smp char *rp; 28759243Sobrien static char ret[24]; 28859243Sobrien int incr = 0; 28959243Sobrien int argno = 0, numval; 29059243Sobrien 29159243Sobrien for (rp = ret ; *cm ; cm++) { 29259243Sobrien switch(*cm) { 29359243Sobrien case '%' : 29459243Sobrien switch(*++cm) { 29559243Sobrien case '+' : 29659243Sobrien numval = (argno == 0 ? destline : destcol); 29759243Sobrien argno = 1 - argno; 29859243Sobrien *rp++ = numval + incr + *++cm; 29959243Sobrien break; 30059243Sobrien 30159243Sobrien case '%' : 30259243Sobrien *rp++ = '%'; 30359243Sobrien break; 30459243Sobrien 30559243Sobrien case 'i' : 30659243Sobrien incr = 1; 30759243Sobrien break; 30859243Sobrien 30959243Sobrien case 'd' : 31059243Sobrien numval = (argno == 0 ? destline : destcol); 31159243Sobrien numval += incr; 31259243Sobrien argno = 1 - argno; 31359243Sobrien *rp++ = '0' + (numval/10); 31459243Sobrien *rp++ = '0' + (numval%10); 31559243Sobrien break; 31659243Sobrien 31759243Sobrien case 'r' : 31859243Sobrien argno = 1; 31959243Sobrien break; 32059243Sobrien } 32159243Sobrien 32259243Sobrien break; 32359243Sobrien default : 32459243Sobrien *rp++ = *cm; 32559243Sobrien } 32659243Sobrien } 32759243Sobrien *rp = '\0'; 32859243Sobrien return(ret); 32959243Sobrien} 33059243Sobrien 33159243Sobrien/* 33259243Sobrien * tputs - put the string cp out onto the terminal, using the function 33359243Sobrien * outc. This should do padding for the terminal, but I can't find a 33459243Sobrien * terminal that needs padding at the moment... 33559243Sobrien */ 33659243Sobrienint 337167465Smptputs(char *cp, int affcnt, int (*outc)()) 33859243Sobrien{ 339145479Smp unsigned long delay = 0; 340145479Smp 34159243Sobrien if (cp == NULL) 34259243Sobrien return(1); 34359243Sobrien /* do any padding interpretation - left null for MINIX just now */ 344145479Smp for (delay = 0; *cp && ISDIGIT(*cp) ; cp++) 345145479Smp delay = delay * 10 + *cp - '0'; 34659243Sobrien while (*cp) 34759243Sobrien (*outc)(*cp++); 348145479Smp#ifdef _OSD_POSIX 349145479Smp usleep(delay*100); /* strictly spoken, it should be *1000 */ 350145479Smp#endif 35159243Sobrien return(1); 35259243Sobrien} 35369408Sache#endif /* _VMS_POSIX || _OSD_POSIX */ 354