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