|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char sccsid[] = "@(#)termcap.c 5.1 (Berkeley) 6/5/85"; ! 9: #endif not lint ! 10: ! 11: #define BUFSIZ 1024 ! 12: #define MAXHOP 32 /* max number of tc= indirections */ ! 13: #define E_TERMCAP "/etc/termcap" ! 14: ! 15: #include <ctype.h> ! 16: /* ! 17: * termcap - routines for dealing with the terminal capability data base ! 18: * ! 19: * BUG: Should use a "last" pointer in tbuf, so that searching ! 20: * for capabilities alphabetically would not be a n**2/2 ! 21: * process when large numbers of capabilities are given. ! 22: * Note: If we add a last pointer now we will screw up the ! 23: * tc capability. We really should compile termcap. ! 24: * ! 25: * Essentially all the work here is scanning and decoding escapes ! 26: * in string capabilities. We don't use stdio because the editor ! 27: * doesn't, and because living w/o it is not hard. ! 28: */ ! 29: ! 30: static char *tbuf; ! 31: static int hopcount; /* detect infinite loops in termcap, init 0 */ ! 32: char *tskip(); ! 33: char *tgetstr(); ! 34: char *tdecode(); ! 35: char *getenv(); ! 36: ! 37: /* ! 38: * Get an entry for terminal name in buffer bp, ! 39: * from the termcap file. Parse is very rudimentary; ! 40: * we just notice escaped newlines. ! 41: */ ! 42: tgetent(bp, name) ! 43: char *bp, *name; ! 44: { ! 45: register char *cp; ! 46: register int c; ! 47: register int i = 0, cnt = 0; ! 48: char ibuf[BUFSIZ]; ! 49: int tf; ! 50: ! 51: tbuf = bp; ! 52: tf = -1; ! 53: #ifndef V6 ! 54: cp = getenv("TERMCAP"); ! 55: /* ! 56: * TERMCAP can have one of two things in it. It can be the ! 57: * name of a file to use instead of /etc/termcap. In this ! 58: * case it better start with a "/". Or it can be an entry to ! 59: * use so we don't have to read the file. In this case it ! 60: * has to already have the newlines crunched out. ! 61: */ ! 62: if (cp && *cp) { ! 63: if (*cp == '/') { ! 64: tf = open(cp, 0); ! 65: } else { ! 66: tbuf = cp; ! 67: c = tnamatch(name); ! 68: tbuf = bp; ! 69: if (c) { ! 70: strcpy(bp,cp); ! 71: return(tnchktc()); ! 72: } ! 73: } ! 74: } ! 75: if (tf < 0) ! 76: tf = open(E_TERMCAP, 0); ! 77: #else ! 78: tf = open(E_TERMCAP, 0); ! 79: #endif ! 80: if (tf < 0) ! 81: return (-1); ! 82: for (;;) { ! 83: cp = bp; ! 84: for (;;) { ! 85: if (i == cnt) { ! 86: cnt = read(tf, ibuf, BUFSIZ); ! 87: if (cnt <= 0) { ! 88: close(tf); ! 89: return (0); ! 90: } ! 91: i = 0; ! 92: } ! 93: c = ibuf[i++]; ! 94: if (c == '\n') { ! 95: if (cp > bp && cp[-1] == '\\'){ ! 96: cp--; ! 97: continue; ! 98: } ! 99: break; ! 100: } ! 101: if (cp >= bp+BUFSIZ) { ! 102: write(2,"Termcap entry too long\n", 23); ! 103: break; ! 104: } else ! 105: *cp++ = c; ! 106: } ! 107: *cp = 0; ! 108: ! 109: /* ! 110: * The real work for the match. ! 111: */ ! 112: if (tnamatch(name)) { ! 113: close(tf); ! 114: return(tnchktc()); ! 115: } ! 116: } ! 117: } ! 118: ! 119: /* ! 120: * tnchktc: check the last entry, see if it's tc=xxx. If so, ! 121: * recursively find xxx and append that entry (minus the names) ! 122: * to take the place of the tc=xxx entry. This allows termcap ! 123: * entries to say "like an HP2621 but doesn't turn on the labels". ! 124: * Note that this works because of the left to right scan. ! 125: */ ! 126: tnchktc() ! 127: { ! 128: register char *p, *q; ! 129: char tcname[16]; /* name of similar terminal */ ! 130: char tcbuf[BUFSIZ]; ! 131: char *holdtbuf = tbuf; ! 132: int l; ! 133: ! 134: p = tbuf + strlen(tbuf) - 2; /* before the last colon */ ! 135: while (*--p != ':') ! 136: if (p<tbuf) { ! 137: write(2, "Bad termcap entry\n", 18); ! 138: return (0); ! 139: } ! 140: p++; ! 141: /* p now points to beginning of last field */ ! 142: if (p[0] != 't' || p[1] != 'c') ! 143: return(1); ! 144: strcpy(tcname,p+3); ! 145: q = tcname; ! 146: while (*q && *q != ':') ! 147: q++; ! 148: *q = 0; ! 149: if (++hopcount > MAXHOP) { ! 150: write(2, "Infinite tc= loop\n", 18); ! 151: return (0); ! 152: } ! 153: if (tgetent(tcbuf, tcname) != 1) { ! 154: hopcount = 0; /* unwind recursion */ ! 155: return(0); ! 156: } ! 157: for (q=tcbuf; *q != ':'; q++) ! 158: ; ! 159: l = p - holdtbuf + strlen(q); ! 160: if (l > BUFSIZ) { ! 161: write(2, "Termcap entry too long\n", 23); ! 162: q[BUFSIZ - (p-tbuf)] = 0; ! 163: } ! 164: strcpy(p, q+1); ! 165: tbuf = holdtbuf; ! 166: hopcount = 0; /* unwind recursion */ ! 167: return(1); ! 168: } ! 169: ! 170: /* ! 171: * Tnamatch deals with name matching. The first field of the termcap ! 172: * entry is a sequence of names separated by |'s, so we compare ! 173: * against each such name. The normal : terminator after the last ! 174: * name (before the first field) stops us. ! 175: */ ! 176: tnamatch(np) ! 177: char *np; ! 178: { ! 179: register char *Np, *Bp; ! 180: ! 181: Bp = tbuf; ! 182: if (*Bp == '#') ! 183: return(0); ! 184: for (;;) { ! 185: for (Np = np; *Np && *Bp == *Np; Bp++, Np++) ! 186: continue; ! 187: if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) ! 188: return (1); ! 189: while (*Bp && *Bp != ':' && *Bp != '|') ! 190: Bp++; ! 191: if (*Bp == 0 || *Bp == ':') ! 192: return (0); ! 193: Bp++; ! 194: } ! 195: } ! 196: ! 197: /* ! 198: * Skip to the next field. Notice that this is very dumb, not ! 199: * knowing about \: escapes or any such. If necessary, :'s can be put ! 200: * into the termcap file in octal. ! 201: */ ! 202: static char * ! 203: tskip(bp) ! 204: register char *bp; ! 205: { ! 206: ! 207: while (*bp && *bp != ':') ! 208: bp++; ! 209: if (*bp == ':') ! 210: bp++; ! 211: return (bp); ! 212: } ! 213: ! 214: /* ! 215: * Return the (numeric) option id. ! 216: * Numeric options look like ! 217: * li#80 ! 218: * i.e. the option string is separated from the numeric value by ! 219: * a # character. If the option is not found we return -1. ! 220: * Note that we handle octal numbers beginning with 0. ! 221: */ ! 222: tgetnum(id) ! 223: char *id; ! 224: { ! 225: register int i, base; ! 226: register char *bp = tbuf; ! 227: ! 228: for (;;) { ! 229: bp = tskip(bp); ! 230: if (*bp == 0) ! 231: return (-1); ! 232: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) ! 233: continue; ! 234: if (*bp == '@') ! 235: return(-1); ! 236: if (*bp != '#') ! 237: continue; ! 238: bp++; ! 239: base = 10; ! 240: if (*bp == '0') ! 241: base = 8; ! 242: i = 0; ! 243: while (isdigit(*bp)) ! 244: i *= base, i += *bp++ - '0'; ! 245: return (i); ! 246: } ! 247: } ! 248: ! 249: /* ! 250: * Handle a flag option. ! 251: * Flag options are given "naked", i.e. followed by a : or the end ! 252: * of the buffer. Return 1 if we find the option, or 0 if it is ! 253: * not given. ! 254: */ ! 255: tgetflag(id) ! 256: char *id; ! 257: { ! 258: register char *bp = tbuf; ! 259: ! 260: for (;;) { ! 261: bp = tskip(bp); ! 262: if (!*bp) ! 263: return (0); ! 264: if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { ! 265: if (!*bp || *bp == ':') ! 266: return (1); ! 267: else if (*bp == '@') ! 268: return(0); ! 269: } ! 270: } ! 271: } ! 272: ! 273: /* ! 274: * Get a string valued option. ! 275: * These are given as ! 276: * cl=^Z ! 277: * Much decoding is done on the strings, and the strings are ! 278: * placed in area, which is a ref parameter which is updated. ! 279: * No checking on area overflow. ! 280: */ ! 281: char * ! 282: tgetstr(id, area) ! 283: char *id, **area; ! 284: { ! 285: register char *bp = tbuf; ! 286: ! 287: for (;;) { ! 288: bp = tskip(bp); ! 289: if (!*bp) ! 290: return (0); ! 291: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) ! 292: continue; ! 293: if (*bp == '@') ! 294: return(0); ! 295: if (*bp != '=') ! 296: continue; ! 297: bp++; ! 298: return (tdecode(bp, area)); ! 299: } ! 300: } ! 301: ! 302: /* ! 303: * Tdecode does the grung work to decode the ! 304: * string capability escapes. ! 305: */ ! 306: static char * ! 307: tdecode(str, area) ! 308: register char *str; ! 309: char **area; ! 310: { ! 311: register char *cp; ! 312: register int c; ! 313: register char *dp; ! 314: int i; ! 315: ! 316: cp = *area; ! 317: while ((c = *str++) && c != ':') { ! 318: switch (c) { ! 319: ! 320: case '^': ! 321: c = *str++ & 037; ! 322: break; ! 323: ! 324: case '\\': ! 325: dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; ! 326: c = *str++; ! 327: nextc: ! 328: if (*dp++ == c) { ! 329: c = *dp++; ! 330: break; ! 331: } ! 332: dp++; ! 333: if (*dp) ! 334: goto nextc; ! 335: if (isdigit(c)) { ! 336: c -= '0', i = 2; ! 337: do ! 338: c <<= 3, c |= *str++ - '0'; ! 339: while (--i && isdigit(*str)); ! 340: } ! 341: break; ! 342: } ! 343: *cp++ = c; ! 344: } ! 345: *cp++ = 0; ! 346: str = *area; ! 347: *area = cp; ! 348: return (str); ! 349: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.