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