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