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