xref: /csrg-svn/usr.bin/vgrind/vgrindefs.c (revision 62423)
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