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