|
|
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: /* ! 217: if (strcmp(id, "co")==0 || strcmp(id, "li")==0) { ! 218: #include "/usr/jerq/include/jioctl.h" ! 219: struct winsize jwin; ! 220: ! 221: if (ioctl(0, JWINSIZE, &jwin) >= 0) { ! 222: if (id[0] == 'l') ! 223: return(jwin.bytesy); ! 224: else ! 225: return(jwin.bytesx); ! 226: } ! 227: } ! 228: */ ! 229: for (;;) { ! 230: bp = tskip(bp); ! 231: if (*bp == 0) ! 232: return (-1); ! 233: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) ! 234: continue; ! 235: if (*bp == '@') ! 236: return(-1); ! 237: if (*bp != '#') ! 238: continue; ! 239: bp++; ! 240: base = 10; ! 241: if (*bp == '0') ! 242: base = 8; ! 243: i = 0; ! 244: while (isdigit(*bp)) ! 245: i *= base, i += *bp++ - '0'; ! 246: return (i); ! 247: } ! 248: } ! 249: ! 250: /* ! 251: * Handle a flag option. ! 252: * Flag options are given "naked", i.e. followed by a : or the end ! 253: * of the buffer. Return 1 if we find the option, or 0 if it is ! 254: * not given. ! 255: */ ! 256: tgetflag(id) ! 257: char *id; ! 258: { ! 259: register char *bp = tbuf; ! 260: ! 261: for (;;) { ! 262: bp = tskip(bp); ! 263: if (!*bp) ! 264: return (0); ! 265: if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { ! 266: if (!*bp || *bp == ':') ! 267: return (1); ! 268: else if (*bp == '@') ! 269: return(0); ! 270: } ! 271: } ! 272: } ! 273: ! 274: /* ! 275: * Get a string valued option. ! 276: * These are given as ! 277: * cl=^Z ! 278: * Much decoding is done on the strings, and the strings are ! 279: * placed in area, which is a ref parameter which is updated. ! 280: * No checking on area overflow. ! 281: */ ! 282: char * ! 283: tgetstr(id, area) ! 284: char *id, **area; ! 285: { ! 286: register char *bp = tbuf; ! 287: ! 288: for (;;) { ! 289: bp = tskip(bp); ! 290: if (!*bp) ! 291: return (0); ! 292: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) ! 293: continue; ! 294: if (*bp == '@') ! 295: return(0); ! 296: if (*bp != '=') ! 297: continue; ! 298: bp++; ! 299: return (tdecode(bp, area)); ! 300: } ! 301: } ! 302: ! 303: /* ! 304: * Tdecode does the grung work to decode the ! 305: * string capability escapes. ! 306: */ ! 307: static char * ! 308: tdecode(str, area) ! 309: register char *str; ! 310: char **area; ! 311: { ! 312: register char *cp; ! 313: register int c; ! 314: register char *dp; ! 315: int i; ! 316: ! 317: cp = *area; ! 318: while ((c = *str++) && c != ':') { ! 319: switch (c) { ! 320: ! 321: case '^': ! 322: c = *str++ & 037; ! 323: break; ! 324: ! 325: case '\\': ! 326: dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; ! 327: c = *str++; ! 328: nextc: ! 329: if (*dp++ == c) { ! 330: c = *dp++; ! 331: break; ! 332: } ! 333: dp++; ! 334: if (*dp) ! 335: goto nextc; ! 336: if (isdigit(c)) { ! 337: c -= '0', i = 2; ! 338: do ! 339: c <<= 3, c |= *str++ - '0'; ! 340: while (--i && isdigit(*str)); ! 341: } ! 342: break; ! 343: } ! 344: *cp++ = c; ! 345: } ! 346: *cp++ = 0; ! 347: str = *area; ! 348: *area = cp; ! 349: return (str); ! 350: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.