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