Annotation of src/usr.bin/vgrind/vgrindefs.c, Revision 1.1
1.1 ! deraadt 1: /* $NetBSD: vgrindefs.c,v 1.5 1994/12/20 12:05:29 cgd Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1980, 1993
! 5: * The Regents of the University of California. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by the University of
! 18: * California, Berkeley and its contributors.
! 19: * 4. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: */
! 35:
! 36: #ifndef lint
! 37: #if 0
! 38: static char sccsid[] = "@(#)vgrindefs.c 8.1 (Berkeley) 6/6/93";
! 39: #endif
! 40: static char rcsid[] = "$NetBSD: vgrindefs.c,v 1.5 1994/12/20 12:05:29 cgd Exp $";
! 41: #endif /* not lint */
! 42:
! 43: #define BUFSIZ 1024
! 44: #define MAXHOP 32 /* max number of tc= indirections */
! 45:
! 46: #include <stdlib.h>
! 47: #include <string.h>
! 48: #include <ctype.h>
! 49: /*
! 50: * grindcap - routines for dealing with the language definitions data base
! 51: * (code stolen almost totally from termcap)
! 52: *
! 53: * BUG: Should use a "last" pointer in tbuf, so that searching
! 54: * for capabilities alphabetically would not be a n**2/2
! 55: * process when large numbers of capabilities are given.
! 56: * Note: If we add a last pointer now we will screw up the
! 57: * tc capability. We really should compile termcap.
! 58: *
! 59: * Essentially all the work here is scanning and decoding escapes
! 60: * in string capabilities. We don't use stdio because the editor
! 61: * doesn't, and because living w/o it is not hard.
! 62: */
! 63:
! 64: static char *tbuf;
! 65: static char *filename;
! 66: static int hopcount; /* detect infinite loops in termcap, init 0 */
! 67: static char *tskip();
! 68: static char *tdecode();
! 69: char *tgetstr();
! 70:
! 71: /*
! 72: * Get an entry for terminal name in buffer bp,
! 73: * from the termcap file. Parse is very rudimentary;
! 74: * we just notice escaped newlines.
! 75: */
! 76: tgetent(bp, name, file)
! 77: char *bp, *name, *file;
! 78: {
! 79: register char *cp;
! 80: register int c;
! 81: register int i = 0, cnt = 0;
! 82: char ibuf[BUFSIZ];
! 83: char *cp2;
! 84: int tf;
! 85:
! 86: tbuf = bp;
! 87: tf = 0;
! 88: filename = file;
! 89: tf = open(filename, 0);
! 90: if (tf < 0)
! 91: return (-1);
! 92: for (;;) {
! 93: cp = bp;
! 94: for (;;) {
! 95: if (i == cnt) {
! 96: cnt = read(tf, ibuf, BUFSIZ);
! 97: if (cnt <= 0) {
! 98: close(tf);
! 99: return (0);
! 100: }
! 101: i = 0;
! 102: }
! 103: c = ibuf[i++];
! 104: if (c == '\n') {
! 105: if (cp > bp && cp[-1] == '\\'){
! 106: cp--;
! 107: continue;
! 108: }
! 109: break;
! 110: }
! 111: if (cp >= bp+BUFSIZ) {
! 112: write(2,"Vgrind entry too long\n", 23);
! 113: break;
! 114: } else
! 115: *cp++ = c;
! 116: }
! 117: *cp = 0;
! 118:
! 119: /*
! 120: * The real work for the match.
! 121: */
! 122: if (tnamatch(name)) {
! 123: close(tf);
! 124: return(tnchktc());
! 125: }
! 126: }
! 127: }
! 128:
! 129: /*
! 130: * tnchktc: check the last entry, see if it's tc=xxx. If so,
! 131: * recursively find xxx and append that entry (minus the names)
! 132: * to take the place of the tc=xxx entry. This allows termcap
! 133: * entries to say "like an HP2621 but doesn't turn on the labels".
! 134: * Note that this works because of the left to right scan.
! 135: */
! 136: tnchktc()
! 137: {
! 138: register char *p, *q;
! 139: char tcname[16]; /* name of similar terminal */
! 140: char tcbuf[BUFSIZ];
! 141: char *holdtbuf = tbuf;
! 142: int l;
! 143:
! 144: p = tbuf + strlen(tbuf) - 2; /* before the last colon */
! 145: while (*--p != ':')
! 146: if (p<tbuf) {
! 147: write(2, "Bad vgrind entry\n", 18);
! 148: return (0);
! 149: }
! 150: p++;
! 151: /* p now points to beginning of last field */
! 152: if (p[0] != 't' || p[1] != 'c')
! 153: return(1);
! 154: strcpy(tcname,p+3);
! 155: q = tcname;
! 156: while (q && *q != ':')
! 157: q++;
! 158: *q = 0;
! 159: if (++hopcount > MAXHOP) {
! 160: write(2, "Infinite tc= loop\n", 18);
! 161: return (0);
! 162: }
! 163: if (tgetent(tcbuf, tcname, filename) != 1)
! 164: return(0);
! 165: for (q=tcbuf; *q != ':'; q++)
! 166: ;
! 167: l = p - holdtbuf + strlen(q);
! 168: if (l > BUFSIZ) {
! 169: write(2, "Vgrind entry too long\n", 23);
! 170: q[BUFSIZ - (p-tbuf)] = 0;
! 171: }
! 172: strcpy(p, q+1);
! 173: tbuf = holdtbuf;
! 174: return(1);
! 175: }
! 176:
! 177: /*
! 178: * Tnamatch deals with name matching. The first field of the termcap
! 179: * entry is a sequence of names separated by |'s, so we compare
! 180: * against each such name. The normal : terminator after the last
! 181: * name (before the first field) stops us.
! 182: */
! 183: tnamatch(np)
! 184: char *np;
! 185: {
! 186: register char *Np, *Bp;
! 187:
! 188: Bp = tbuf;
! 189: if (*Bp == '#')
! 190: return(0);
! 191: for (;;) {
! 192: for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
! 193: continue;
! 194: if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
! 195: return (1);
! 196: while (*Bp && *Bp != ':' && *Bp != '|')
! 197: Bp++;
! 198: if (*Bp == 0 || *Bp == ':')
! 199: return (0);
! 200: Bp++;
! 201: }
! 202: }
! 203:
! 204: /*
! 205: * Skip to the next field. Notice that this is very dumb, not
! 206: * knowing about \: escapes or any such. If necessary, :'s can be put
! 207: * into the termcap file in octal.
! 208: */
! 209: static char *
! 210: tskip(bp)
! 211: register char *bp;
! 212: {
! 213:
! 214: while (*bp && *bp != ':')
! 215: bp++;
! 216: if (*bp == ':')
! 217: bp++;
! 218: return (bp);
! 219: }
! 220:
! 221: /*
! 222: * Return the (numeric) option id.
! 223: * Numeric options look like
! 224: * li#80
! 225: * i.e. the option string is separated from the numeric value by
! 226: * a # character. If the option is not found we return -1.
! 227: * Note that we handle octal numbers beginning with 0.
! 228: */
! 229: tgetnum(id)
! 230: char *id;
! 231: {
! 232: register int i, base;
! 233: register char *bp = tbuf;
! 234:
! 235: for (;;) {
! 236: bp = tskip(bp);
! 237: if (*bp == 0)
! 238: return (-1);
! 239: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
! 240: continue;
! 241: if (*bp == '@')
! 242: return(-1);
! 243: if (*bp != '#')
! 244: continue;
! 245: bp++;
! 246: base = 10;
! 247: if (*bp == '0')
! 248: base = 8;
! 249: i = 0;
! 250: while (isdigit(*bp))
! 251: i *= base, i += *bp++ - '0';
! 252: return (i);
! 253: }
! 254: }
! 255:
! 256: /*
! 257: * Handle a flag option.
! 258: * Flag options are given "naked", i.e. followed by a : or the end
! 259: * of the buffer. Return 1 if we find the option, or 0 if it is
! 260: * not given.
! 261: */
! 262: tgetflag(id)
! 263: char *id;
! 264: {
! 265: register char *bp = tbuf;
! 266:
! 267: for (;;) {
! 268: bp = tskip(bp);
! 269: if (!*bp)
! 270: return (0);
! 271: if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
! 272: if (!*bp || *bp == ':')
! 273: return (1);
! 274: else if (*bp == '@')
! 275: return(0);
! 276: }
! 277: }
! 278: }
! 279:
! 280: /*
! 281: * Get a string valued option.
! 282: * These are given as
! 283: * cl=^Z
! 284: * Much decoding is done on the strings, and the strings are
! 285: * placed in area, which is a ref parameter which is updated.
! 286: * No checking on area overflow.
! 287: */
! 288: char *
! 289: tgetstr(id, area)
! 290: char *id, **area;
! 291: {
! 292: register char *bp = tbuf;
! 293:
! 294: for (;;) {
! 295: bp = tskip(bp);
! 296: if (!*bp)
! 297: return (0);
! 298: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
! 299: continue;
! 300: if (*bp == '@')
! 301: return(0);
! 302: if (*bp != '=')
! 303: continue;
! 304: bp++;
! 305: return (tdecode(bp, area));
! 306: }
! 307: }
! 308:
! 309: /*
! 310: * Tdecode does the grung work to decode the
! 311: * string capability escapes.
! 312: */
! 313: static char *
! 314: tdecode(str, area)
! 315: register char *str;
! 316: char **area;
! 317: {
! 318: register char *cp;
! 319: register int c;
! 320: int i;
! 321:
! 322: cp = *area;
! 323: while (c = *str++) {
! 324: if (c == ':' && *(cp-1) != '\\')
! 325: break;
! 326: *cp++ = c;
! 327: }
! 328: *cp++ = 0;
! 329: str = *area;
! 330: *area = cp;
! 331: return (str);
! 332: }