1 /* 2 * termcap.c 1.1 20/7/87 agc Joypace Ltd 3 * 4 * Copyright Joypace Ltd, London, UK, 1987. All rights reserved. 5 * This file may be freely distributed provided that this notice 6 * remains attached. 7 * 8 * A public domain implementation of the termcap(3) routines. 9 */ 10 #include "sh.h" 11 12 #if defined(_VMS_POSIX) || defined(_OSD_POSIX) || defined(__ANDROID__) 13 /* efth 1988-Apr-29 14 15 - Correct when TERM != name and TERMCAP is defined [tgetent] 16 - Correct the comparison for the terminal name [tgetent] 17 - Correct the value of ^x escapes [tgetstr] 18 - Added %r to reverse row/column [tgoto] 19 20 Paul Gillingwater <paul@actrix.gen.nz> July 1992 21 - Modified to allow terminal aliases in termcap file 22 - Uses TERMCAP environment variable for file only 23 */ 24 25 #include <stdio.h> 26 #include <string.h> 27 28 #define CAPABLEN 2 29 30 #define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') 31 #define ISDIGIT(x) ((x) >= '0' && (x) <= '9') 32 33 char *capab; /* the capability itself */ 34 35 extern char *getenv(); /* new, improved getenv */ 36 #ifndef fopen 37 extern FILE *fopen(); /* old fopen */ 38 #endif 39 40 /* 41 * tgetent - get the termcap entry for terminal name, and put it 42 * in bp (which must be an array of 1024 chars). Returns 1 if 43 * termcap entry found, 0 if not found, and -1 if file not found. 44 */ 45 int 46 tgetent(char *bp, char *name) 47 { 48 #ifdef __ANDROID__ 49 /* Use static termcap entry since termcap file usually doesn't exist. */ 50 capab = bp; 51 strcpy(bp, 52 "linux|linux console:" 53 ":am:eo:mi:ms:xn:xo:" 54 ":it#8:" 55 ":AL=\\E[%dL:DC=\\E[%dP:DL=\\E[%dM:IC=\\E[%d@:K2=\\E[G:al=\\E[L:" 56 ":bl=^G:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:cr=^M:" 57 ":cs=\\E[%i%d;%dr:ct=\\E[3g:dc=\\E[P:dl=\\E[M:do=^J:ec=\\E[%dX:" 58 ":ei=\\E[4l:ho=\\E[H:ic=\\E[@:im=\\E[4h:k1=\\E[[A:k2=\\E[[B:" 59 ":k3=\\E[[C:k4=\\E[[D:k5=\\E[[E:k6=\\E[17~:k7=\\E[18~:k8=\\E[19~:" 60 ":k9=\\E[20~:kD=\\E[3~:kI=\\E[2~:kN=\\E[6~:kP=\\E[5~:kb=\\177:" 61 ":kd=\\E[B:kh=\\E[1~:kl=\\E[D:kr=\\E[C:ku=\\E[A:le=^H:mb=\\E[5m:" 62 ":md=\\E[1m:me=\\E[0m:mh=\\E[2m:mr=\\E[7m:nd=\\E[C:nw=^M^J:" 63 ":rc=\\E8:sc=\\E7:se=\\E[27m:sf=^J:so=\\E[7m:sr=\\EM:st=\\EH:ta=^I:" 64 ":ue=\\E[24m:up=\\E[A:us=\\E[4m:vb=200\\E[?5h\\E[?5l:" 65 ":ve=\\E[?25h\\E[?0c:vi=\\E[?25l\\E[?1c:vs=\\E[?25h\\E[?0c:" 66 ); 67 return(1); 68 #else 69 FILE *fp; 70 char *termfile; 71 char *cp, 72 *ptr, /* temporary pointer */ 73 tmp[1024]; /* buffer for terminal name *//*FIXBUF*/ 74 size_t len = strlen(name); 75 76 capab = bp; 77 78 /* Use TERMCAP to override default. */ 79 80 termfile = getenv("TERMCAP"); 81 if (termfile == NULL ) termfile = "/etc/termcap"; 82 83 if ((fp = fopen(termfile, "r")) == (FILE *) NULL) { 84 fprintf(stderr, CGETS(31, 1, 85 "Can't open TERMCAP: [%s]\n"), termfile); 86 fprintf(stderr, CGETS(31, 2, "Can't open %s.\n"), termfile); 87 sleep(1); 88 return(-1); 89 } 90 91 while (fgets(bp, 1024, fp) != NULL) { 92 /* Any line starting with # or NL is skipped as a comment */ 93 if ((*bp == '#') || (*bp == '\n')) continue; 94 95 /* Look for lines which end with two backslashes, 96 and then append the next line. */ 97 while (*(cp = &bp[strlen(bp) - 2]) == '\\') 98 fgets(cp, 1024, fp); 99 100 /* Skip over any spaces or tabs */ 101 for (++cp ; ISSPACE(*cp) ; cp++); 102 103 /* Make sure "name" matches exactly (efth) */ 104 105 /* Here we might want to look at any aliases as well. We'll use 106 sscanf to look at aliases. These are delimited by '|'. */ 107 108 sscanf(bp,"%[^|]",tmp); 109 if (strncmp(name, tmp, len) == 0) { 110 fclose(fp); 111 #ifdef DEBUG 112 fprintf(stderr, CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 113 sleep(1); 114 #endif /* DEBUG */ 115 return(1); 116 } 117 ptr = bp; 118 while ((ptr = strchr(ptr,'|')) != NULL) { 119 ptr++; 120 if (strchr(ptr,'|') == NULL) break; 121 sscanf(ptr,"%[^|]",tmp); 122 if (strncmp(name, tmp, len) == 0) { 123 fclose(fp); 124 #ifdef DEBUG 125 fprintf(stderr,CGETS(31, 3, "Found %s in %s.\n"), name, termfile); 126 sleep(1); 127 #endif /* DEBUG */ 128 return(1); 129 } 130 } 131 } 132 /* If we get here, then we haven't found a match. */ 133 fclose(fp); 134 #ifdef DEBUG 135 fprintf(stderr,CGETS(31, 4, "No match found for %s in file %s\n"), 136 name, termfile); 137 sleep(1); 138 #endif /* DEBUG */ 139 return(0); 140 #endif /* ANDROID */ 141 } 142 143 /* 144 * tgetnum - get the numeric terminal capability corresponding 145 * to id. Returns the value, -1 if invalid. 146 */ 147 int 148 tgetnum(char *id) 149 { 150 char *cp; 151 int ret; 152 153 if ((cp = capab) == NULL || id == NULL) 154 return(-1); 155 while (*++cp != ':') 156 ; 157 for (++cp ; *cp ; cp++) { 158 while (ISSPACE(*cp)) 159 cp++; 160 if (strncmp(cp, id, CAPABLEN) == 0) { 161 while (*cp && *cp != ':' && *cp != '#') 162 cp++; 163 if (*cp != '#') 164 return(-1); 165 for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++) 166 ret = ret * 10 + *cp - '0'; 167 return(ret); 168 } 169 while (*cp && *cp != ':') 170 cp++; 171 } 172 return(-1); 173 } 174 175 /* 176 * tgetflag - get the boolean flag corresponding to id. Returns -1 177 * if invalid, 0 if the flag is not in termcap entry, or 1 if it is 178 * present. 179 */ 180 int 181 tgetflag(char *id) 182 { 183 char *cp; 184 185 if ((cp = capab) == NULL || id == NULL) 186 return(-1); 187 while (*++cp != ':') 188 ; 189 for (++cp ; *cp ; cp++) { 190 while (ISSPACE(*cp)) 191 cp++; 192 if (strncmp(cp, id, CAPABLEN) == 0) 193 return(1); 194 while (*cp && *cp != ':') 195 cp++; 196 } 197 return(0); 198 } 199 200 /* 201 * tgetstr - get the string capability corresponding to id and place 202 * it in area (advancing area at same time). Expand escape sequences 203 * etc. Returns the string, or NULL if it can't do it. 204 */ 205 char * 206 tgetstr(char *id, char **area) 207 { 208 char *cp; 209 char *ret; 210 int i; 211 212 if ((cp = capab) == NULL || id == NULL) 213 return(NULL); 214 while (*++cp != ':') 215 ; 216 for (++cp ; *cp ; cp++) { 217 while (ISSPACE(*cp)) 218 cp++; 219 if (strncmp(cp, id, CAPABLEN) == 0) { 220 while (*cp && *cp != ':' && *cp != '=') 221 cp++; 222 if (*cp != '=') 223 return(NULL); 224 for (ret = *area, cp++; *cp && *cp != ':' ; 225 (*area)++, cp++) 226 switch(*cp) { 227 case '^' : 228 **area = *++cp - '@'; /* fix (efth)*/ 229 break; 230 case '\\' : 231 switch(*++cp) { 232 case 'E' : 233 **area = CTL_ESC('\033'); 234 break; 235 case 'n' : 236 **area = '\n'; 237 break; 238 case 'r' : 239 **area = '\r'; 240 break; 241 case 't' : 242 **area = '\t'; 243 break; 244 case 'b' : 245 **area = '\b'; 246 break; 247 case 'f' : 248 **area = '\f'; 249 break; 250 case '0' : 251 case '1' : 252 case '2' : 253 case '3' : 254 for (i=0 ; *cp && ISDIGIT(*cp) ; 255 cp++) 256 i = i * 8 + *cp - '0'; 257 **area = i; 258 cp--; 259 break; 260 case '^' : 261 case '\\' : 262 **area = *cp; 263 break; 264 } 265 break; 266 default : 267 **area = *cp; 268 } 269 *(*area)++ = '\0'; 270 return(ret); 271 } 272 while (*cp && *cp != ':') 273 cp++; 274 } 275 return(NULL); 276 } 277 278 /* 279 * tgoto - given the cursor motion string cm, make up the string 280 * for the cursor to go to (destcol, destline), and return the string. 281 * Returns "OOPS" if something's gone wrong, or the string otherwise. 282 */ 283 char * 284 tgoto(char *cm, int destcol, int destline) 285 { 286 char *rp; 287 static char ret[24]; 288 int incr = 0; 289 int argno = 0, numval; 290 291 for (rp = ret ; *cm ; cm++) { 292 switch(*cm) { 293 case '%' : 294 switch(*++cm) { 295 case '+' : 296 numval = (argno == 0 ? destline : destcol); 297 argno = 1 - argno; 298 *rp++ = numval + incr + *++cm; 299 break; 300 301 case '%' : 302 *rp++ = '%'; 303 break; 304 305 case 'i' : 306 incr = 1; 307 break; 308 309 case 'd' : 310 numval = (argno == 0 ? destline : destcol); 311 numval += incr; 312 argno = 1 - argno; 313 *rp++ = '0' + (numval/10); 314 *rp++ = '0' + (numval%10); 315 break; 316 317 case 'r' : 318 argno = 1; 319 break; 320 } 321 322 break; 323 default : 324 *rp++ = *cm; 325 } 326 } 327 *rp = '\0'; 328 return(ret); 329 } 330 331 /* 332 * tputs - put the string cp out onto the terminal, using the function 333 * outc. This should do padding for the terminal, but I can't find a 334 * terminal that needs padding at the moment... 335 */ 336 int 337 tputs(char *cp, int affcnt, int (*outc)()) 338 { 339 unsigned long delay = 0; 340 341 if (cp == NULL) 342 return(1); 343 /* do any padding interpretation - left null for MINIX just now */ 344 for (delay = 0; *cp && ISDIGIT(*cp) ; cp++) 345 delay = delay * 10 + *cp - '0'; 346 while (*cp) 347 (*outc)(*cp++); 348 #ifdef _OSD_POSIX 349 usleep(delay*100); /* strictly spoken, it should be *1000 */ 350 #endif 351 return(1); 352 } 353 #endif /* _VMS_POSIX || _OSD_POSIX */ 354