vms.termcap.c revision 232633
1139804Simp/* $Header: /p/tcsh/cvsroot/tcsh/vms.termcap.c,v 1.12 2011/01/09 16:25:29 christos Exp $ */ 21541Srgrimes/* 31541Srgrimes * termcap.c 1.1 20/7/87 agc Joypace Ltd 41541Srgrimes * 51541Srgrimes * Copyright Joypace Ltd, London, UK, 1987. All rights reserved. 61541Srgrimes * This file may be freely distributed provided that this notice 71541Srgrimes * remains attached. 81541Srgrimes * 91541Srgrimes * A public domain implementation of the termcap(3) routines. 101541Srgrimes */ 111541Srgrimes#include "sh.h" 121541SrgrimesRCSID("$tcsh: vms.termcap.c,v 1.12 2011/01/09 16:25:29 christos Exp $") 131541Srgrimes#if defined(_VMS_POSIX) || defined(_OSD_POSIX) || defined(__ANDROID__) 141541Srgrimes/* efth 1988-Apr-29 151541Srgrimes 161541Srgrimes - Correct when TERM != name and TERMCAP is defined [tgetent] 171541Srgrimes - Correct the comparison for the terminal name [tgetent] 181541Srgrimes - Correct the value of ^x escapes [tgetstr] 191541Srgrimes - Added %r to reverse row/column [tgoto] 201541Srgrimes 211541Srgrimes Paul Gillingwater <paul@actrix.gen.nz> July 1992 221541Srgrimes - Modified to allow terminal aliases in termcap file 231541Srgrimes - Uses TERMCAP environment variable for file only 241541Srgrimes*/ 251541Srgrimes 261541Srgrimes#include <stdio.h> 271541Srgrimes#include <string.h> 281541Srgrimes 291541Srgrimes#define CAPABLEN 2 301541Srgrimes 311541Srgrimes#define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') 321541Srgrimes#define ISDIGIT(x) ((x) >= '0' && (x) <= '9') 331541Srgrimes 341541Srgrimeschar *capab; /* the capability itself */ 351541Srgrimes 361541Srgrimesextern char *getenv(); /* new, improved getenv */ 37116182Sobrien#ifndef fopen 38116182Sobrienextern FILE *fopen(); /* old fopen */ 39116182Sobrien#endif 4098849Sken 4198849Sken/* 421541Srgrimes * tgetent - get the termcap entry for terminal name, and put it 431541Srgrimes * in bp (which must be an array of 1024 chars). Returns 1 if 4444218Sbde * termcap entry found, 0 if not found, and -1 if file not found. 45120665Snectar */ 4676166Smarkmint 47220100Skibtgetent(char *bp, char *name) 4876166Smarkm{ 491541Srgrimes#ifdef __ANDROID__ 50220100Skib /* Use static termcap entry since termcap file usually doesn't exist. */ 51104964Sjeff capab = bp; 5278431Swollman strcpy(bp, 5332702Sdyson "linux|linux console:" 541541Srgrimes ":am:eo:mi:ms:xn:xo:" 5531853Sdyson ":it#8:" 56240238Skib ":AL=\\E[%dL:DC=\\E[%dP:DL=\\E[%dM:IC=\\E[%d@:K2=\\E[G:al=\\E[L:" 57220100Skib ":bl=^G:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:cr=^M:" 5831853Sdyson ":cs=\\E[%i%d;%dr:ct=\\E[3g:dc=\\E[P:dl=\\E[M:do=^J:ec=\\E[%dX:" 5931853Sdyson ":ei=\\E[4l:ho=\\E[H:ic=\\E[@:im=\\E[4h:k1=\\E[[A:k2=\\E[[B:" 6099848Sken ":k3=\\E[[C:k4=\\E[[D:k5=\\E[[E:k6=\\E[17~:k7=\\E[18~:k8=\\E[19~:" 6199848Sken ":k9=\\E[20~:kD=\\E[3~:kI=\\E[2~:kN=\\E[6~:kP=\\E[5~:kb=\\177:" 6299848Sken ":kd=\\E[B:kh=\\E[1~:kl=\\E[D:kr=\\E[C:ku=\\E[A:le=^H:mb=\\E[5m:" 6331853Sdyson ":md=\\E[1m:me=\\E[0m:mh=\\E[2m:mr=\\E[7m:nd=\\E[C:nw=^M^J:" 64111737Sdes ":rc=\\E8:sc=\\E7:se=\\E[27m:sf=^J:so=\\E[7m:sr=\\EM:st=\\EH:ta=^I:" 6578431Swollman ":ue=\\E[24m:up=\\E[A:us=\\E[4m:vb=200\\E[?5h\\E[?5l:" 6678431Swollman ":ve=\\E[?25h\\E[?0c:vi=\\E[?25l\\E[?1c:vs=\\E[?25h\\E[?0c:" 67223889Skib ); 68223889Skib return(1); 6998849Sken#else 7098849Sken FILE *fp; 7198849Sken char *termfile; 7298849Sken char *cp, 73138781Salc *ptr, /* temporary pointer */ 74138781Salc tmp[1024]; /* buffer for terminal name *//*FIXBUF*/ 75138781Salc size_t len = strlen(name); 76138781Salc 77138781Salc capab = bp; 78138781Salc 7998849Sken /* Use TERMCAP to override default. */ 80137377Salc 8198849Sken termfile = getenv("TERMCAP"); 8298849Sken if (termfile == NULL ) termfile = "/etc/termcap"; 8398849Sken 8498849Sken if ((fp = fopen(termfile, "r")) == (FILE *) NULL) { 8598849Sken fprintf(stderr, CGETS(31, 1, 86137244Salc "Can't open TERMCAP: [%s]\n"), termfile); 8798849Sken fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile); 8898849Sken sleep(1); 8998849Sken return(-1); 90138781Salc } 91138781Salc 92138781Salc while (fgets(bp, 1024, fp) != NULL) { 9398849Sken /* Any line starting with # or NL is skipped as a comment */ 94138781Salc if ((*bp == '#') || (*bp == '\n')) continue; 95138781Salc 9698849Sken /* Look for lines which end with two backslashes, 9798849Sken and then append the next line. */ 98138781Salc while (*(cp = &bp[strlen(bp) - 2]) == '\\') 99138781Salc fgets(cp, 1024, fp); 100138781Salc 101138424Salc /* Skip over any spaces or tabs */ 10298849Sken for (++cp ; ISSPACE(*cp) ; cp++); 103111977Sken 10498849Sken /* Make sure "name" matches exactly (efth) */ 10598849Sken 10698849Sken/* Here we might want to look at any aliases as well. We'll use 107116110Salcsscanf to look at aliases. These are delimited by '|'. */ 108138781Salc 10998849Sken sscanf(bp,"%[^|]",tmp); 110161252Salc if (strncmp(name, tmp, len) == 0) { 111161252Salc fclose(fp); 112207669Salc#ifdef DEBUG 113107371Salc fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 11498849Sken sleep(1); 115207669Salc#endif /* DEBUG */ 116138781Salc return(1); 117138781Salc } 118138781Salc ptr = bp; 119138781Salc while ((ptr = strchr(ptr,'|')) != NULL) { 120138781Salc ptr++; 121138781Salc if (strchr(ptr,'|') == NULL) break; 122138781Salc sscanf(ptr,"%[^|]",tmp); 123138781Salc if (strncmp(name, tmp, len) == 0) { 12498849Sken fclose(fp); 125138424Salc#ifdef DEBUG 126138424Salc fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 127116110Salc sleep(1); 12898849Sken#endif /* DEBUG */ 12998849Sken return(1); 13098849Sken } 13198849Sken } 13298849Sken } 1331549Srgrimes /* If we get here, then we haven't found a match. */ 134223889Skib fclose(fp); 135223889Skib#ifdef DEBUG 136223889Skib fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"), 137223889Skib name, termfile); 138223889Skib sleep(1); 139223889Skib#endif /* DEBUG */ 140223889Skib return(0); 141223889Skib#endif /* ANDROID */ 142223889Skib} 143223889Skib 144223889Skib/* 145223889Skib * tgetnum - get the numeric terminal capability corresponding 146223889Skib * to id. Returns the value, -1 if invalid. 147223889Skib */ 148223889Skibint 149223889Skibtgetnum(char *id) 150223889Skib{ 151223889Skib char *cp; 152223889Skib int ret; 153223889Skib 154223889Skib if ((cp = capab) == NULL || id == NULL) 155251874Sscottl return(-1); 156251874Sscottl while (*++cp != ':') 157223889Skib ; 158251874Sscottl for (++cp ; *cp ; cp++) { 159251874Sscottl while (ISSPACE(*cp)) 160251874Sscottl cp++; 161251874Sscottl if (strncmp(cp, id, CAPABLEN) == 0) { 162251874Sscottl while (*cp && *cp != ':' && *cp != '#') 163251874Sscottl cp++; 164251874Sscottl if (*cp != '#') 165251874Sscottl return(-1); 166251874Sscottl for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++) 167251874Sscottl ret = ret * 10 + *cp - '0'; 168251874Sscottl return(ret); 169251874Sscottl } 170251874Sscottl while (*cp && *cp != ':') 171251874Sscottl cp++; 172251874Sscottl } 173251874Sscottl return(-1); 174251874Sscottl} 175251874Sscottl 176251874Sscottl/* 177251874Sscottl * tgetflag - get the boolean flag corresponding to id. Returns -1 178251874Sscottl * if invalid, 0 if the flag is not in termcap entry, or 1 if it is 179251874Sscottl * present. 180251874Sscottl */ 181251874Sscottlint 182251874Sscottltgetflag(char *id) 183251874Sscottl{ 184251874Sscottl char *cp; 185251874Sscottl 186251874Sscottl if ((cp = capab) == NULL || id == NULL) 187251874Sscottl return(-1); 188251874Sscottl while (*++cp != ':') 189251874Sscottl ; 190251874Sscottl for (++cp ; *cp ; cp++) { 191251874Sscottl while (ISSPACE(*cp)) 192251874Sscottl cp++; 193251874Sscottl if (strncmp(cp, id, CAPABLEN) == 0) 194251874Sscottl return(1); 195251874Sscottl while (*cp && *cp != ':') 196251874Sscottl cp++; 197251874Sscottl } 198251874Sscottl return(0); 199251874Sscottl} 200251874Sscottl 201251874Sscottl/* 202111739Sdes * tgetstr - get the string capability corresponding to id and place 2031541Srgrimes * it in area (advancing area at same time). Expand escape sequences 204223889Skib * etc. Returns the string, or NULL if it can't do it. 205223889Skib */ 206223889Skibchar * 207223889Skibtgetstr(char *id, char **area) 208223889Skib{ 209223889Skib char *cp; 210223889Skib char *ret; 211223889Skib int i; 212223889Skib 213223889Skib if ((cp = capab) == NULL || id == NULL) 214223889Skib return(NULL); 215223889Skib while (*++cp != ':') 216223889Skib ; 217223889Skib for (++cp ; *cp ; cp++) { 218223889Skib while (ISSPACE(*cp)) 219111737Sdes cp++; 220233353Skib if (strncmp(cp, id, CAPABLEN) == 0) { 221223889Skib while (*cp && *cp != ':' && *cp != '=') 2221541Srgrimes cp++; 223223889Skib if (*cp != '=') 224223889Skib return(NULL); 225223889Skib for (ret = *area, cp++; *cp && *cp != ':' ; 22642408Seivind (*area)++, cp++) 22742453Seivind switch(*cp) { 228223889Skib case '^' : 22942453Seivind **area = *++cp - '@'; /* fix (efth)*/ 230223889Skib break; 231223889Skib case '\\' : 232223889Skib switch(*++cp) { 23342408Seivind case 'E' : 234223889Skib **area = CTL_ESC('\033'); 235223889Skib break; 236233647Salc case 'n' : 237233647Salc **area = '\n'; 238233647Salc break; 239233647Salc case 'r' : 240233647Salc **area = '\r'; 241233647Salc break; 242223889Skib case 't' : 24344681Sjulian **area = '\t'; 2441541Srgrimes break; 2451541Srgrimes case 'b' : 2461541Srgrimes **area = '\b'; 2471541Srgrimes break; 2481541Srgrimes case 'f' : 2491541Srgrimes **area = '\f'; 2501541Srgrimes break; 2511541Srgrimes case '0' : 2521541Srgrimes case '1' : 2531541Srgrimes case '2' : 2546324Sdg case '3' : 2551541Srgrimes for (i=0 ; *cp && ISDIGIT(*cp) ; 2561541Srgrimes cp++) 2571541Srgrimes i = i * 8 + *cp - '0'; 258218195Smdf **area = i; 2591541Srgrimes cp--; 2601541Srgrimes break; 2611541Srgrimes case '^' : 2621541Srgrimes case '\\' : 2631541Srgrimes **area = *cp; 26490413Stmm break; 2651541Srgrimes } 2661541Srgrimes break; 2671541Srgrimes default : 2681541Srgrimes **area = *cp; 26998998Salfred } 2701541Srgrimes *(*area)++ = '\0'; 27198998Salfred return(ret); 2721541Srgrimes } 2737611Sdg while (*cp && *cp != ':') 2747611Sdg cp++; 2751541Srgrimes } 276104908Smike return(NULL); 2771541Srgrimes} 2781541Srgrimes 2791541Srgrimes/* 280111739Sdes * tgoto - given the cursor motion string cm, make up the string 2811541Srgrimes * for the cursor to go to (destcol, destline), and return the string. 2821541Srgrimes * Returns "OOPS" if something's gone wrong, or the string otherwise. 28390413Stmm */ 284223889Skibchar * 28544681Sjuliantgoto(char *cm, int destcol, int destline) 2861541Srgrimes{ 2871541Srgrimes char *rp; 288120665Snectar static char ret[24]; 289120665Snectar int incr = 0; 290120665Snectar int argno = 0, numval; 291120665Snectar 292120665Snectar for (rp = ret ; *cm ; cm++) { 293120665Snectar switch(*cm) { 294120665Snectar case '%' : 295120665Snectar switch(*++cm) { 296120665Snectar case '+' : 297120665Snectar numval = (argno == 0 ? destline : destcol); 298233353Skib argno = 1 - argno; 299120665Snectar *rp++ = numval + incr + *++cm; 300120665Snectar break; 301120665Snectar 302120665Snectar case '%' : 303120665Snectar *rp++ = '%'; 304120665Snectar break; 305233353Skib 306120665Snectar case 'i' : 307120665Snectar incr = 1; 308120665Snectar break; 309120665Snectar 310111937Salc case 'd' : 31196080Salc numval = (argno == 0 ? destline : destcol); 31296080Salc numval += incr; 31396080Salc argno = 1 - argno; 31498849Sken *rp++ = '0' + (numval/10); 315138539Salc *rp++ = '0' + (numval%10); 31698849Sken break; 31798849Sken 31898849Sken case 'r' : 31998849Sken argno = 1; 32098849Sken break; 32198849Sken } 32298849Sken 32398849Sken break; 32498849Sken default : 32598849Sken *rp++ = *cm; 32698849Sken } 32798849Sken } 32898849Sken *rp = '\0'; 32998849Sken return(ret); 33098849Sken} 33198849Sken 33298849Sken/* 33398849Sken * tputs - put the string cp out onto the terminal, using the function 33498849Sken * outc. This should do padding for the terminal, but I can't find a 335137377Salc * terminal that needs padding at the moment... 33698849Sken */ 33798849Skenint 33898849Skentputs(char *cp, int affcnt, int (*outc)()) 33998849Sken{ 34098849Sken unsigned long delay = 0; 34198849Sken 34298849Sken if (cp == NULL) 34398849Sken return(1); 34498849Sken /* do any padding interpretation - left null for MINIX just now */ 34598849Sken for (delay = 0; *cp && ISDIGIT(*cp) ; cp++) 34698849Sken delay = delay * 10 + *cp - '0'; 34798849Sken while (*cp) 34898849Sken (*outc)(*cp++); 34998849Sken#ifdef _OSD_POSIX 35098849Sken usleep(delay*100); /* strictly spoken, it should be *1000 */ 35198849Sken#endif 35298849Sken return(1); 35398849Sken} 35498849Sken#endif /* _VMS_POSIX || _OSD_POSIX */ 35531853Sdyson