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