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