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