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