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