122066Sdist /* 2*36167Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*36167Sbostic * All rights reserved. 4*36167Sbostic * 5*36167Sbostic * Redistribution and use in source and binary forms are permitted 6*36167Sbostic * provided that the above copyright notice and this paragraph are 7*36167Sbostic * duplicated in all such forms and that any documentation, 8*36167Sbostic * advertising materials, and other materials related to such 9*36167Sbostic * distribution and use acknowledge that the software was developed 10*36167Sbostic * by the University of California, Berkeley. The name of the 11*36167Sbostic * University may not be used to endorse or promote products derived 12*36167Sbostic * from this software without specific prior written permission. 13*36167Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*36167Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*36167Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622066Sdist */ 1722066Sdist 1813722Ssam #ifndef lint 19*36167Sbostic static char sccsid[] = "@(#)vgrindefs.c 5.2 (Berkeley) 10/25/88"; 20*36167Sbostic #endif /* not lint */ 2113722Ssam 228662Smckusick #define BUFSIZ 1024 238662Smckusick #define MAXHOP 32 /* max number of tc= indirections */ 248662Smckusick 258662Smckusick #include <ctype.h> 268662Smckusick /* 278662Smckusick * grindcap - routines for dealing with the language definitions data base 288662Smckusick * (code stolen almost totally from termcap) 298662Smckusick * 308662Smckusick * BUG: Should use a "last" pointer in tbuf, so that searching 318662Smckusick * for capabilities alphabetically would not be a n**2/2 328662Smckusick * process when large numbers of capabilities are given. 338662Smckusick * Note: If we add a last pointer now we will screw up the 348662Smckusick * tc capability. We really should compile termcap. 358662Smckusick * 368662Smckusick * Essentially all the work here is scanning and decoding escapes 378662Smckusick * in string capabilities. We don't use stdio because the editor 388662Smckusick * doesn't, and because living w/o it is not hard. 398662Smckusick */ 408662Smckusick 418662Smckusick static char *tbuf; 4217500Sralph static char *filename; 438662Smckusick static int hopcount; /* detect infinite loops in termcap, init 0 */ 448662Smckusick char *tskip(); 458662Smckusick char *tgetstr(); 468662Smckusick char *tdecode(); 478662Smckusick char *getenv(); 488662Smckusick 498662Smckusick /* 508662Smckusick * Get an entry for terminal name in buffer bp, 518662Smckusick * from the termcap file. Parse is very rudimentary; 528662Smckusick * we just notice escaped newlines. 538662Smckusick */ 5417500Sralph tgetent(bp, name, file) 5517500Sralph char *bp, *name, *file; 568662Smckusick { 578662Smckusick register char *cp; 588662Smckusick register int c; 598662Smckusick register int i = 0, cnt = 0; 608662Smckusick char ibuf[BUFSIZ]; 618662Smckusick char *cp2; 628662Smckusick int tf; 638662Smckusick 648662Smckusick tbuf = bp; 658662Smckusick tf = 0; 6617500Sralph filename = file; 678662Smckusick tf = open(filename, 0); 688662Smckusick if (tf < 0) 698662Smckusick return (-1); 708662Smckusick for (;;) { 718662Smckusick cp = bp; 728662Smckusick for (;;) { 738662Smckusick if (i == cnt) { 748662Smckusick cnt = read(tf, ibuf, BUFSIZ); 758662Smckusick if (cnt <= 0) { 768662Smckusick close(tf); 778662Smckusick return (0); 788662Smckusick } 798662Smckusick i = 0; 808662Smckusick } 818662Smckusick c = ibuf[i++]; 828662Smckusick if (c == '\n') { 838662Smckusick if (cp > bp && cp[-1] == '\\'){ 848662Smckusick cp--; 858662Smckusick continue; 868662Smckusick } 878662Smckusick break; 888662Smckusick } 898662Smckusick if (cp >= bp+BUFSIZ) { 908662Smckusick write(2,"Vgrind entry too long\n", 23); 918662Smckusick break; 928662Smckusick } else 938662Smckusick *cp++ = c; 948662Smckusick } 958662Smckusick *cp = 0; 968662Smckusick 978662Smckusick /* 988662Smckusick * The real work for the match. 998662Smckusick */ 1008662Smckusick if (tnamatch(name)) { 1018662Smckusick close(tf); 1028662Smckusick return(tnchktc()); 1038662Smckusick } 1048662Smckusick } 1058662Smckusick } 1068662Smckusick 1078662Smckusick /* 1088662Smckusick * tnchktc: check the last entry, see if it's tc=xxx. If so, 1098662Smckusick * recursively find xxx and append that entry (minus the names) 1108662Smckusick * to take the place of the tc=xxx entry. This allows termcap 1118662Smckusick * entries to say "like an HP2621 but doesn't turn on the labels". 1128662Smckusick * Note that this works because of the left to right scan. 1138662Smckusick */ 1148662Smckusick tnchktc() 1158662Smckusick { 1168662Smckusick register char *p, *q; 1178662Smckusick char tcname[16]; /* name of similar terminal */ 1188662Smckusick char tcbuf[BUFSIZ]; 1198662Smckusick char *holdtbuf = tbuf; 1208662Smckusick int l; 1218662Smckusick 1228662Smckusick p = tbuf + strlen(tbuf) - 2; /* before the last colon */ 1238662Smckusick while (*--p != ':') 1248662Smckusick if (p<tbuf) { 1258662Smckusick write(2, "Bad vgrind entry\n", 18); 1268662Smckusick return (0); 1278662Smckusick } 1288662Smckusick p++; 1298662Smckusick /* p now points to beginning of last field */ 1308662Smckusick if (p[0] != 't' || p[1] != 'c') 1318662Smckusick return(1); 1328662Smckusick strcpy(tcname,p+3); 1338662Smckusick q = tcname; 1348662Smckusick while (q && *q != ':') 1358662Smckusick q++; 1368662Smckusick *q = 0; 1378662Smckusick if (++hopcount > MAXHOP) { 1388662Smckusick write(2, "Infinite tc= loop\n", 18); 1398662Smckusick return (0); 1408662Smckusick } 14117500Sralph if (tgetent(tcbuf, tcname, filename) != 1) 1428662Smckusick return(0); 1438662Smckusick for (q=tcbuf; *q != ':'; q++) 1448662Smckusick ; 1458662Smckusick l = p - holdtbuf + strlen(q); 1468662Smckusick if (l > BUFSIZ) { 1478662Smckusick write(2, "Vgrind entry too long\n", 23); 1488662Smckusick q[BUFSIZ - (p-tbuf)] = 0; 1498662Smckusick } 1508662Smckusick strcpy(p, q+1); 1518662Smckusick tbuf = holdtbuf; 1528662Smckusick return(1); 1538662Smckusick } 1548662Smckusick 1558662Smckusick /* 1568662Smckusick * Tnamatch deals with name matching. The first field of the termcap 1578662Smckusick * entry is a sequence of names separated by |'s, so we compare 1588662Smckusick * against each such name. The normal : terminator after the last 1598662Smckusick * name (before the first field) stops us. 1608662Smckusick */ 1618662Smckusick tnamatch(np) 1628662Smckusick char *np; 1638662Smckusick { 1648662Smckusick register char *Np, *Bp; 1658662Smckusick 1668662Smckusick Bp = tbuf; 1678662Smckusick if (*Bp == '#') 1688662Smckusick return(0); 1698662Smckusick for (;;) { 1708662Smckusick for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 1718662Smckusick continue; 1728662Smckusick if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 1738662Smckusick return (1); 1748662Smckusick while (*Bp && *Bp != ':' && *Bp != '|') 1758662Smckusick Bp++; 1768662Smckusick if (*Bp == 0 || *Bp == ':') 1778662Smckusick return (0); 1788662Smckusick Bp++; 1798662Smckusick } 1808662Smckusick } 1818662Smckusick 1828662Smckusick /* 1838662Smckusick * Skip to the next field. Notice that this is very dumb, not 1848662Smckusick * knowing about \: escapes or any such. If necessary, :'s can be put 1858662Smckusick * into the termcap file in octal. 1868662Smckusick */ 1878662Smckusick static char * 1888662Smckusick tskip(bp) 1898662Smckusick register char *bp; 1908662Smckusick { 1918662Smckusick 1928662Smckusick while (*bp && *bp != ':') 1938662Smckusick bp++; 1948662Smckusick if (*bp == ':') 1958662Smckusick bp++; 1968662Smckusick return (bp); 1978662Smckusick } 1988662Smckusick 1998662Smckusick /* 2008662Smckusick * Return the (numeric) option id. 2018662Smckusick * Numeric options look like 2028662Smckusick * li#80 2038662Smckusick * i.e. the option string is separated from the numeric value by 2048662Smckusick * a # character. If the option is not found we return -1. 2058662Smckusick * Note that we handle octal numbers beginning with 0. 2068662Smckusick */ 2078662Smckusick tgetnum(id) 2088662Smckusick char *id; 2098662Smckusick { 2108662Smckusick register int i, base; 2118662Smckusick register char *bp = tbuf; 2128662Smckusick 2138662Smckusick for (;;) { 2148662Smckusick bp = tskip(bp); 2158662Smckusick if (*bp == 0) 2168662Smckusick return (-1); 2178662Smckusick if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 2188662Smckusick continue; 2198662Smckusick if (*bp == '@') 2208662Smckusick return(-1); 2218662Smckusick if (*bp != '#') 2228662Smckusick continue; 2238662Smckusick bp++; 2248662Smckusick base = 10; 2258662Smckusick if (*bp == '0') 2268662Smckusick base = 8; 2278662Smckusick i = 0; 2288662Smckusick while (isdigit(*bp)) 2298662Smckusick i *= base, i += *bp++ - '0'; 2308662Smckusick return (i); 2318662Smckusick } 2328662Smckusick } 2338662Smckusick 2348662Smckusick /* 2358662Smckusick * Handle a flag option. 2368662Smckusick * Flag options are given "naked", i.e. followed by a : or the end 2378662Smckusick * of the buffer. Return 1 if we find the option, or 0 if it is 2388662Smckusick * not given. 2398662Smckusick */ 2408662Smckusick tgetflag(id) 2418662Smckusick char *id; 2428662Smckusick { 2438662Smckusick register char *bp = tbuf; 2448662Smckusick 2458662Smckusick for (;;) { 2468662Smckusick bp = tskip(bp); 2478662Smckusick if (!*bp) 2488662Smckusick return (0); 2498662Smckusick if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 2508662Smckusick if (!*bp || *bp == ':') 2518662Smckusick return (1); 2528662Smckusick else if (*bp == '@') 2538662Smckusick return(0); 2548662Smckusick } 2558662Smckusick } 2568662Smckusick } 2578662Smckusick 2588662Smckusick /* 2598662Smckusick * Get a string valued option. 2608662Smckusick * These are given as 2618662Smckusick * cl=^Z 2628662Smckusick * Much decoding is done on the strings, and the strings are 2638662Smckusick * placed in area, which is a ref parameter which is updated. 2648662Smckusick * No checking on area overflow. 2658662Smckusick */ 2668662Smckusick char * 2678662Smckusick tgetstr(id, area) 2688662Smckusick char *id, **area; 2698662Smckusick { 2708662Smckusick register char *bp = tbuf; 2718662Smckusick 2728662Smckusick for (;;) { 2738662Smckusick bp = tskip(bp); 2748662Smckusick if (!*bp) 2758662Smckusick return (0); 2768662Smckusick if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 2778662Smckusick continue; 2788662Smckusick if (*bp == '@') 2798662Smckusick return(0); 2808662Smckusick if (*bp != '=') 2818662Smckusick continue; 2828662Smckusick bp++; 2838662Smckusick return (tdecode(bp, area)); 2848662Smckusick } 2858662Smckusick } 2868662Smckusick 2878662Smckusick /* 2888662Smckusick * Tdecode does the grung work to decode the 2898662Smckusick * string capability escapes. 2908662Smckusick */ 2918662Smckusick static char * 2928662Smckusick tdecode(str, area) 2938662Smckusick register char *str; 2948662Smckusick char **area; 2958662Smckusick { 2968662Smckusick register char *cp; 2978662Smckusick register int c; 2988662Smckusick int i; 2998662Smckusick 3008662Smckusick cp = *area; 3018662Smckusick while (c = *str++) { 3028662Smckusick if (c == ':' && *(cp-1) != '\\') 3038662Smckusick break; 3048662Smckusick *cp++ = c; 3058662Smckusick } 3068662Smckusick *cp++ = 0; 3078662Smckusick str = *area; 3088662Smckusick *area = cp; 3098662Smckusick return (str); 3108662Smckusick } 311