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