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