1/* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31 32__FBSDID("$FreeBSD$"); 33 34#define BUFSIZ 1024 35#define MAXHOP 32 /* max number of tc= indirections */ 36 37#include <ctype.h> 38#include <unistd.h> 39 40/* 41 * grindcap - routines for dealing with the language definitions data base 42 * (code stolen almost totally from termcap) 43 * 44 * BUG: Should use a "last" pointer in tbuf, so that searching 45 * for capabilities alphabetically would not be a n**2/2 46 * process when large numbers of capabilities are given. 47 * Note: If we add a last pointer now we will screw up the 48 * tc capability. We really should compile termcap. 49 * 50 * Essentially all the work here is scanning and decoding escapes 51 * in string capabilities. We don't use stdio because the editor 52 * doesn't, and because living w/o it is not hard. 53 */ 54 55static char *tbuf; 56static char *filename; 57static int hopcount; /* detect infinite loops in termcap, init 0 */ 58char *tskip(); 59char *tgetstr(); 60char *tdecode(); 61char *getenv(); 62 63/* 64 * Get an entry for terminal name in buffer bp, 65 * from the termcap file. Parse is very rudimentary; 66 * we just notice escaped newlines. 67 */ 68tgetent(bp, name, file) 69 char *bp, *name, *file; 70{ 71 register char *cp; 72 register int c; 73 register int i = 0, cnt = 0; 74 char ibuf[BUFSIZ]; 75 char *cp2; 76 int tf; 77 78 tbuf = bp; 79 tf = 0; 80 filename = file; 81 tf = open(filename, 0); 82 if (tf < 0) 83 return (-1); 84 for (;;) { 85 cp = bp; 86 for (;;) { 87 if (i == cnt) { 88 cnt = read(tf, ibuf, BUFSIZ); 89 if (cnt <= 0) { 90 close(tf); 91 return (0); 92 } 93 i = 0; 94 } 95 c = ibuf[i++]; 96 if (c == '\n') { 97 if (cp > bp && cp[-1] == '\\'){ 98 cp--; 99 continue; 100 } 101 break; 102 } 103 if (cp >= bp+BUFSIZ) { 104 write(STDERR_FILENO, "Vgrind entry too long\n", 23); 105 break; 106 } else 107 *cp++ = c; 108 } 109 *cp = 0; 110 111 /* 112 * The real work for the match. 113 */ 114 if (tnamatch(name)) { 115 close(tf); 116 return(tnchktc()); 117 } 118 } 119} 120 121/* 122 * tnchktc: check the last entry, see if it's tc=xxx. If so, 123 * recursively find xxx and append that entry (minus the names) 124 * to take the place of the tc=xxx entry. This allows termcap 125 * entries to say "like an HP2621 but doesn't turn on the labels". 126 * Note that this works because of the left to right scan. 127 */ 128tnchktc() 129{ 130 register char *p, *q; 131 char tcname[16]; /* name of similar terminal */ 132 char tcbuf[BUFSIZ]; 133 char *holdtbuf = tbuf; 134 int l; 135 136 p = tbuf + strlen(tbuf) - 2; /* before the last colon */ 137 while (*--p != ':') 138 if (p<tbuf) { 139 write(STDERR_FILENO, "Bad vgrind entry\n", 18); 140 return (0); 141 } 142 p++; 143 /* p now points to beginning of last field */ 144 if (p[0] != 't' || p[1] != 'c') 145 return(1); 146 strcpy(tcname,p+3); 147 q = tcname; 148 while (q && *q != ':') 149 q++; 150 *q = 0; 151 if (++hopcount > MAXHOP) { 152 write(STDERR_FILENO, "Infinite tc= loop\n", 18); 153 return (0); 154 } 155 if (tgetent(tcbuf, tcname, filename) != 1) 156 return(0); 157 for (q=tcbuf; *q != ':'; q++) 158 ; 159 l = p - holdtbuf + strlen(q); 160 if (l > BUFSIZ) { 161 write(STDERR_FILENO, "Vgrind entry too long\n", 23); 162 q[BUFSIZ - (p-tbuf)] = 0; 163 } 164 strcpy(p, q+1); 165 tbuf = holdtbuf; 166 return(1); 167} 168 169/* 170 * Tnamatch deals with name matching. The first field of the termcap 171 * entry is a sequence of names separated by |'s, so we compare 172 * against each such name. The normal : terminator after the last 173 * name (before the first field) stops us. 174 */ 175tnamatch(np) 176 char *np; 177{ 178 register char *Np, *Bp; 179 180 Bp = tbuf; 181 if (*Bp == '#') 182 return(0); 183 for (;;) { 184 for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 185 continue; 186 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 187 return (1); 188 while (*Bp && *Bp != ':' && *Bp != '|') 189 Bp++; 190 if (*Bp == 0 || *Bp == ':') 191 return (0); 192 Bp++; 193 } 194} 195 196/* 197 * Skip to the next field. Notice that this is very dumb, not 198 * knowing about \: escapes or any such. If necessary, :'s can be put 199 * into the termcap file in octal. 200 */ 201static char * 202tskip(bp) 203 register char *bp; 204{ 205 206 while (*bp && *bp != ':') 207 bp++; 208 if (*bp == ':') 209 bp++; 210 return (bp); 211} 212 213/* 214 * Return the (numeric) option id. 215 * Numeric options look like 216 * li#80 217 * i.e. the option string is separated from the numeric value by 218 * a # character. If the option is not found we return -1. 219 * Note that we handle octal numbers beginning with 0. 220 */ 221tgetnum(id) 222 char *id; 223{ 224 register int i, base; 225 register char *bp = tbuf; 226 227 for (;;) { 228 bp = tskip(bp); 229 if (*bp == 0) 230 return (-1); 231 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 232 continue; 233 if (*bp == '@') 234 return(-1); 235 if (*bp != '#') 236 continue; 237 bp++; 238 base = 10; 239 if (*bp == '0') 240 base = 8; 241 i = 0; 242 while (isdigit(*bp)) 243 i *= base, i += *bp++ - '0'; 244 return (i); 245 } 246} 247 248/* 249 * Handle a flag option. 250 * Flag options are given "naked", i.e. followed by a : or the end 251 * of the buffer. Return 1 if we find the option, or 0 if it is 252 * not given. 253 */ 254tgetflag(id) 255 char *id; 256{ 257 register char *bp = tbuf; 258 259 for (;;) { 260 bp = tskip(bp); 261 if (!*bp) 262 return (0); 263 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 264 if (!*bp || *bp == ':') 265 return (1); 266 else if (*bp == '@') 267 return(0); 268 } 269 } 270} 271 272/* 273 * Get a string valued option. 274 * These are given as 275 * cl=^Z 276 * Much decoding is done on the strings, and the strings are 277 * placed in area, which is a ref parameter which is updated. 278 * No checking on area overflow. 279 */ 280char * 281tgetstr(id, area) 282 char *id, **area; 283{ 284 register char *bp = tbuf; 285 286 for (;;) { 287 bp = tskip(bp); 288 if (!*bp) 289 return (0); 290 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 291 continue; 292 if (*bp == '@') 293 return(0); 294 if (*bp != '=') 295 continue; 296 bp++; 297 return (tdecode(bp, area)); 298 } 299} 300 301/* 302 * Tdecode does the grung work to decode the 303 * string capability escapes. 304 */ 305static char * 306tdecode(str, area) 307 register char *str; 308 char **area; 309{ 310 register char *cp; 311 register int c; 312 int i; 313 314 cp = *area; 315 while (c = *str++) { 316 if (c == ':' && *(cp-1) != '\\') 317 break; 318 *cp++ = c; 319 } 320 *cp++ = 0; 321 str = *area; 322 *area = cp; 323 return (str); 324} 325