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