|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that the above copyright notice and this paragraph are ! 7: * duplicated in all such forms and that any documentation, ! 8: * advertising materials, and other materials related to such ! 9: * distribution and use acknowledge that the software was developed ! 10: * by the University of California, Berkeley. The name of the ! 11: * University may not be used to endorse or promote products derived ! 12: * from this software without specific prior written permission. ! 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 16: */ ! 17: ! 18: #ifndef lint ! 19: static char sccsid[] = "@(#)printcap.c 5.3 (Berkeley) 6/30/88"; ! 20: #endif /* not lint */ ! 21: ! 22: #define BUFSIZ 1024 ! 23: #define MAXHOP 32 /* max number of tc= indirections */ ! 24: ! 25: #include <ctype.h> ! 26: #include <stdio.h> ! 27: /* ! 28: * termcap - routines for dealing with the terminal capability data base ! 29: * ! 30: * BUG: Should use a "last" pointer in tbuf, so that searching ! 31: * for capabilities alphabetically would not be a n**2/2 ! 32: * process when large numbers of capabilities are given. ! 33: * Note: If we add a last pointer now we will screw up the ! 34: * tc capability. We really should compile termcap. ! 35: * ! 36: * Essentially all the work here is scanning and decoding escapes ! 37: * in string capabilities. We don't use stdio because the editor ! 38: * doesn't, and because living w/o it is not hard. ! 39: */ ! 40: ! 41: #define PRINTCAP ! 42: ! 43: #ifdef PRINTCAP ! 44: #define tgetent pgetent ! 45: #define tskip pskip ! 46: #define tgetstr pgetstr ! 47: #define tdecode pdecode ! 48: #define tgetnum pgetnum ! 49: #define tgetflag pgetflag ! 50: #define tdecode pdecode ! 51: #define tnchktc pnchktc ! 52: #define tnamatch pnamatch ! 53: #undef E_TERMCAP ! 54: #define E_TERMCAP "/etc/printcap" ! 55: #define V6 ! 56: #endif ! 57: ! 58: static FILE *pfp = NULL; /* printcap data base file pointer */ ! 59: static char *tbuf; ! 60: static int hopcount; /* detect infinite loops in termcap, init 0 */ ! 61: char *tskip(); ! 62: char *tgetstr(); ! 63: char *tdecode(); ! 64: char *getenv(); ! 65: ! 66: /* ! 67: * Similar to tgetent except it returns the next enrty instead of ! 68: * doing a lookup. ! 69: */ ! 70: getprent(bp) ! 71: register char *bp; ! 72: { ! 73: register int c, skip = 0; ! 74: ! 75: if (pfp == NULL && (pfp = fopen(E_TERMCAP, "r")) == NULL) ! 76: return(-1); ! 77: tbuf = bp; ! 78: for (;;) { ! 79: switch (c = getc(pfp)) { ! 80: case EOF: ! 81: fclose(pfp); ! 82: pfp = NULL; ! 83: return(0); ! 84: case '\n': ! 85: if (bp == tbuf) { ! 86: skip = 0; ! 87: continue; ! 88: } ! 89: if (bp[-1] == '\\') { ! 90: bp--; ! 91: continue; ! 92: } ! 93: *bp = '\0'; ! 94: return(1); ! 95: case '#': ! 96: if (bp == tbuf) ! 97: skip++; ! 98: default: ! 99: if (skip) ! 100: continue; ! 101: if (bp >= tbuf+BUFSIZ) { ! 102: write(2, "Termcap entry too long\n", 23); ! 103: *bp = '\0'; ! 104: return(1); ! 105: } ! 106: *bp++ = c; ! 107: } ! 108: } ! 109: } ! 110: ! 111: endprent() ! 112: { ! 113: if (pfp != NULL) ! 114: fclose(pfp); ! 115: } ! 116: ! 117: /* ! 118: * Get an entry for terminal name in buffer bp, ! 119: * from the termcap file. Parse is very rudimentary; ! 120: * we just notice escaped newlines. ! 121: */ ! 122: tgetent(bp, name) ! 123: char *bp, *name; ! 124: { ! 125: register char *cp; ! 126: register int c; ! 127: register int i = 0, cnt = 0; ! 128: char ibuf[BUFSIZ]; ! 129: char *cp2; ! 130: int tf; ! 131: ! 132: tbuf = bp; ! 133: tf = 0; ! 134: #ifndef V6 ! 135: cp = getenv("TERMCAP"); ! 136: /* ! 137: * TERMCAP can have one of two things in it. It can be the ! 138: * name of a file to use instead of /etc/termcap. In this ! 139: * case it better start with a "/". Or it can be an entry to ! 140: * use so we don't have to read the file. In this case it ! 141: * has to already have the newlines crunched out. ! 142: */ ! 143: if (cp && *cp) { ! 144: if (*cp!='/') { ! 145: cp2 = getenv("TERM"); ! 146: if (cp2==(char *) 0 || strcmp(name,cp2)==0) { ! 147: strcpy(bp,cp); ! 148: return(tnchktc()); ! 149: } else { ! 150: tf = open(E_TERMCAP, 0); ! 151: } ! 152: } else ! 153: tf = open(cp, 0); ! 154: } ! 155: if (tf==0) ! 156: tf = open(E_TERMCAP, 0); ! 157: #else ! 158: tf = open(E_TERMCAP, 0); ! 159: #endif ! 160: if (tf < 0) ! 161: return (-1); ! 162: for (;;) { ! 163: cp = bp; ! 164: for (;;) { ! 165: if (i == cnt) { ! 166: cnt = read(tf, ibuf, BUFSIZ); ! 167: if (cnt <= 0) { ! 168: close(tf); ! 169: return (0); ! 170: } ! 171: i = 0; ! 172: } ! 173: c = ibuf[i++]; ! 174: if (c == '\n') { ! 175: if (cp > bp && cp[-1] == '\\'){ ! 176: cp--; ! 177: continue; ! 178: } ! 179: break; ! 180: } ! 181: if (cp >= bp+BUFSIZ) { ! 182: write(2,"Termcap entry too long\n", 23); ! 183: break; ! 184: } else ! 185: *cp++ = c; ! 186: } ! 187: *cp = 0; ! 188: ! 189: /* ! 190: * The real work for the match. ! 191: */ ! 192: if (tnamatch(name)) { ! 193: close(tf); ! 194: return(tnchktc()); ! 195: } ! 196: } ! 197: } ! 198: ! 199: /* ! 200: * tnchktc: check the last entry, see if it's tc=xxx. If so, ! 201: * recursively find xxx and append that entry (minus the names) ! 202: * to take the place of the tc=xxx entry. This allows termcap ! 203: * entries to say "like an HP2621 but doesn't turn on the labels". ! 204: * Note that this works because of the left to right scan. ! 205: */ ! 206: tnchktc() ! 207: { ! 208: register char *p, *q; ! 209: char tcname[16]; /* name of similar terminal */ ! 210: char tcbuf[BUFSIZ]; ! 211: char *holdtbuf = tbuf; ! 212: int l; ! 213: ! 214: p = tbuf + strlen(tbuf) - 2; /* before the last colon */ ! 215: while (*--p != ':') ! 216: if (p<tbuf) { ! 217: write(2, "Bad termcap entry\n", 18); ! 218: return (0); ! 219: } ! 220: p++; ! 221: /* p now points to beginning of last field */ ! 222: if (p[0] != 't' || p[1] != 'c') ! 223: return(1); ! 224: strcpy(tcname,p+3); ! 225: q = tcname; ! 226: while (q && *q != ':') ! 227: q++; ! 228: *q = 0; ! 229: if (++hopcount > MAXHOP) { ! 230: write(2, "Infinite tc= loop\n", 18); ! 231: return (0); ! 232: } ! 233: if (tgetent(tcbuf, tcname) != 1) ! 234: return(0); ! 235: for (q=tcbuf; *q != ':'; q++) ! 236: ; ! 237: l = p - holdtbuf + strlen(q); ! 238: if (l > BUFSIZ) { ! 239: write(2, "Termcap entry too long\n", 23); ! 240: q[BUFSIZ - (p-tbuf)] = 0; ! 241: } ! 242: strcpy(p, q+1); ! 243: tbuf = holdtbuf; ! 244: return(1); ! 245: } ! 246: ! 247: /* ! 248: * Tnamatch deals with name matching. The first field of the termcap ! 249: * entry is a sequence of names separated by |'s, so we compare ! 250: * against each such name. The normal : terminator after the last ! 251: * name (before the first field) stops us. ! 252: */ ! 253: tnamatch(np) ! 254: char *np; ! 255: { ! 256: register char *Np, *Bp; ! 257: ! 258: Bp = tbuf; ! 259: if (*Bp == '#') ! 260: return(0); ! 261: for (;;) { ! 262: for (Np = np; *Np && *Bp == *Np; Bp++, Np++) ! 263: continue; ! 264: if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) ! 265: return (1); ! 266: while (*Bp && *Bp != ':' && *Bp != '|') ! 267: Bp++; ! 268: if (*Bp == 0 || *Bp == ':') ! 269: return (0); ! 270: Bp++; ! 271: } ! 272: } ! 273: ! 274: /* ! 275: * Skip to the next field. Notice that this is very dumb, not ! 276: * knowing about \: escapes or any such. If necessary, :'s can be put ! 277: * into the termcap file in octal. ! 278: */ ! 279: static char * ! 280: tskip(bp) ! 281: register char *bp; ! 282: { ! 283: ! 284: while (*bp && *bp != ':') ! 285: bp++; ! 286: if (*bp == ':') ! 287: bp++; ! 288: return (bp); ! 289: } ! 290: ! 291: /* ! 292: * Return the (numeric) option id. ! 293: * Numeric options look like ! 294: * li#80 ! 295: * i.e. the option string is separated from the numeric value by ! 296: * a # character. If the option is not found we return -1. ! 297: * Note that we handle octal numbers beginning with 0. ! 298: */ ! 299: tgetnum(id) ! 300: char *id; ! 301: { ! 302: register int i, base; ! 303: register char *bp = tbuf; ! 304: ! 305: for (;;) { ! 306: bp = tskip(bp); ! 307: if (*bp == 0) ! 308: return (-1); ! 309: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) ! 310: continue; ! 311: if (*bp == '@') ! 312: return(-1); ! 313: if (*bp != '#') ! 314: continue; ! 315: bp++; ! 316: base = 10; ! 317: if (*bp == '0') ! 318: base = 8; ! 319: i = 0; ! 320: while (isdigit(*bp)) ! 321: i *= base, i += *bp++ - '0'; ! 322: return (i); ! 323: } ! 324: } ! 325: ! 326: /* ! 327: * Handle a flag option. ! 328: * Flag options are given "naked", i.e. followed by a : or the end ! 329: * of the buffer. Return 1 if we find the option, or 0 if it is ! 330: * not given. ! 331: */ ! 332: tgetflag(id) ! 333: char *id; ! 334: { ! 335: register char *bp = tbuf; ! 336: ! 337: for (;;) { ! 338: bp = tskip(bp); ! 339: if (!*bp) ! 340: return (0); ! 341: if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { ! 342: if (!*bp || *bp == ':') ! 343: return (1); ! 344: else if (*bp == '@') ! 345: return(0); ! 346: } ! 347: } ! 348: } ! 349: ! 350: /* ! 351: * Get a string valued option. ! 352: * These are given as ! 353: * cl=^Z ! 354: * Much decoding is done on the strings, and the strings are ! 355: * placed in area, which is a ref parameter which is updated. ! 356: * No checking on area overflow. ! 357: */ ! 358: char * ! 359: tgetstr(id, area) ! 360: char *id, **area; ! 361: { ! 362: register char *bp = tbuf; ! 363: ! 364: for (;;) { ! 365: bp = tskip(bp); ! 366: if (!*bp) ! 367: return (0); ! 368: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) ! 369: continue; ! 370: if (*bp == '@') ! 371: return(0); ! 372: if (*bp != '=') ! 373: continue; ! 374: bp++; ! 375: return (tdecode(bp, area)); ! 376: } ! 377: } ! 378: ! 379: /* ! 380: * Tdecode does the grung work to decode the ! 381: * string capability escapes. ! 382: */ ! 383: static char * ! 384: tdecode(str, area) ! 385: register char *str; ! 386: char **area; ! 387: { ! 388: register char *cp; ! 389: register int c; ! 390: register char *dp; ! 391: int i; ! 392: ! 393: cp = *area; ! 394: while ((c = *str++) && c != ':') { ! 395: switch (c) { ! 396: ! 397: case '^': ! 398: c = *str++ & 037; ! 399: break; ! 400: ! 401: case '\\': ! 402: dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; ! 403: c = *str++; ! 404: nextc: ! 405: if (*dp++ == c) { ! 406: c = *dp++; ! 407: break; ! 408: } ! 409: dp++; ! 410: if (*dp) ! 411: goto nextc; ! 412: if (isdigit(c)) { ! 413: c -= '0', i = 2; ! 414: do ! 415: c <<= 3, c |= *str++ - '0'; ! 416: while (--i && isdigit(*str)); ! 417: } ! 418: break; ! 419: } ! 420: *cp++ = c; ! 421: } ! 422: *cp++ = 0; ! 423: str = *area; ! 424: *area = cp; ! 425: return (str); ! 426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.