1*3678Sroot /*	printcap.c	1.1	81/05/09	*/
2*3678Sroot /* Copyright (c) 1979 Regents of the University of California */
3*3678Sroot #define	BUFSIZ	512
4*3678Sroot 
5*3678Sroot #include <ctype.h>
6*3678Sroot /*
7*3678Sroot  * printcap - routines for dealing with the line printer capability data base
8*3678Sroot  *
9*3678Sroot  * BUG:		Should use a "last" pointer in tbuf, so that searching
10*3678Sroot  *		for capabilities alphabetically would not be a n**2/2
11*3678Sroot  *		process when large numbers of capabilities are given.
12*3678Sroot  *
13*3678Sroot  * Essentially all the work here is scanning and decoding escapes
14*3678Sroot  * in string capabilities.  We don't use stdio because the editor
15*3678Sroot  * doesn't, and because living w/o it is not hard.
16*3678Sroot  */
17*3678Sroot 
18*3678Sroot static	char *pbuf;
19*3678Sroot char	*pskip();
20*3678Sroot char	*pgetstr();
21*3678Sroot char	*pdecode();
22*3678Sroot 
23*3678Sroot /*
24*3678Sroot  * Get an entry for printer name in buffer bp,
25*3678Sroot  * from the printcap file.  Parse is very rudimentary;
26*3678Sroot  * we just notice escaped newlines.
27*3678Sroot  */
28*3678Sroot pgetent(bp, name)
29*3678Sroot 	char *bp, *name;
30*3678Sroot {
31*3678Sroot 	register char *cp;
32*3678Sroot 	register int c;
33*3678Sroot 	register int i = 0, cnt = 0;
34*3678Sroot 	char ibuf[BUFSIZ];
35*3678Sroot 	int tf;
36*3678Sroot 
37*3678Sroot 	pbuf = bp;
38*3678Sroot 	tf = open("/etc/printcap", 0);
39*3678Sroot 	if (tf < 0)
40*3678Sroot 		return (-1);
41*3678Sroot 	for (;;) {
42*3678Sroot 		cp = bp;
43*3678Sroot 		for (;;) {
44*3678Sroot 			if (i == cnt) {
45*3678Sroot 				cnt = read(tf, ibuf, BUFSIZ);
46*3678Sroot 				if (cnt <= 0) {
47*3678Sroot 					close(tf);
48*3678Sroot 					return (0);
49*3678Sroot 				}
50*3678Sroot 				i = 0;
51*3678Sroot 			}
52*3678Sroot 			c = ibuf[i++];
53*3678Sroot 			if (c == '\n') {
54*3678Sroot 				if (cp > bp && cp[-1] == '\\'){
55*3678Sroot 					cp--;
56*3678Sroot 					continue;
57*3678Sroot 				}
58*3678Sroot 				break;
59*3678Sroot 			}
60*3678Sroot 			*cp++ = c;
61*3678Sroot 		}
62*3678Sroot 		*cp = 0;
63*3678Sroot 
64*3678Sroot 		/*
65*3678Sroot 		 * The real work for the match.
66*3678Sroot 		 */
67*3678Sroot 		if (pnamatch(name)) {
68*3678Sroot 			close(tf);
69*3678Sroot 			return (1);
70*3678Sroot 		}
71*3678Sroot 	}
72*3678Sroot }
73*3678Sroot 
74*3678Sroot /*
75*3678Sroot  * Tnamatch deals with name matching.  The first field of the printcap
76*3678Sroot  * entry is a sequence of names separated by |'s, so we compare
77*3678Sroot  * against each such name.  The normal : terminator after the last
78*3678Sroot  * name (before the first field) stops us.
79*3678Sroot  */
80*3678Sroot pnamatch(np)
81*3678Sroot 	char *np;
82*3678Sroot {
83*3678Sroot 	register char *Np, *Bp;
84*3678Sroot 
85*3678Sroot 	Bp = pbuf;
86*3678Sroot 	for (;;) {
87*3678Sroot 		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
88*3678Sroot 			continue;
89*3678Sroot 		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
90*3678Sroot 			return (1);
91*3678Sroot 		while (*Bp && *Bp != ':' && *Bp != '|')
92*3678Sroot 			Bp++;
93*3678Sroot 		if (*Bp == 0 || *Bp == ':')
94*3678Sroot 			return (0);
95*3678Sroot 		Bp++;
96*3678Sroot 	}
97*3678Sroot }
98*3678Sroot 
99*3678Sroot /*
100*3678Sroot  * Skip to the next field.  Notice that this is very dumb, not
101*3678Sroot  * knowing about \: escapes or any such.  If necessary, :'s can be put
102*3678Sroot  * into the printcap file in octal.
103*3678Sroot  */
104*3678Sroot static char *
105*3678Sroot pskip(bp)
106*3678Sroot 	register char *bp;
107*3678Sroot {
108*3678Sroot 
109*3678Sroot 	while (*bp && *bp != ':')
110*3678Sroot 		bp++;
111*3678Sroot 	if (*bp == ':')
112*3678Sroot 		bp++;
113*3678Sroot 	return (bp);
114*3678Sroot }
115*3678Sroot 
116*3678Sroot /*
117*3678Sroot  * Return the (numeric) option id.
118*3678Sroot  * Numeric options look like
119*3678Sroot  *	li#80
120*3678Sroot  * i.e. the option string is separated from the numeric value by
121*3678Sroot  * a # character.  If the option is not found we return -1.
122*3678Sroot  * Note that we handle octal numbers beginning with 0.
123*3678Sroot  */
124*3678Sroot pgetnum(id)
125*3678Sroot 	char *id;
126*3678Sroot {
127*3678Sroot 	register int i, base;
128*3678Sroot 	register char *bp = pbuf;
129*3678Sroot 
130*3678Sroot 	for (;;) {
131*3678Sroot 		bp = pskip(bp);
132*3678Sroot 		if (*bp == 0)
133*3678Sroot 			return (-1);
134*3678Sroot 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
135*3678Sroot 			continue;
136*3678Sroot 		if (*bp != '#')
137*3678Sroot 			continue;
138*3678Sroot 		bp++;
139*3678Sroot 		base = 10;
140*3678Sroot 		if (*bp == '0')
141*3678Sroot 			base = 8;
142*3678Sroot 		i = 0;
143*3678Sroot 		while (isdigit(*bp))
144*3678Sroot 			i *= base, i += *bp++ - '0';
145*3678Sroot 		return (i);
146*3678Sroot 	}
147*3678Sroot }
148*3678Sroot 
149*3678Sroot /*
150*3678Sroot  * Handle a flag option.
151*3678Sroot  * Flag options are given "naked", i.e. followed by a : or the end
152*3678Sroot  * of the buffer.  Return 1 if we find the option, or 0 if it is
153*3678Sroot  * not given.
154*3678Sroot  */
155*3678Sroot pgetflag(id)
156*3678Sroot 	char *id;
157*3678Sroot {
158*3678Sroot 	register char *bp = pbuf;
159*3678Sroot 
160*3678Sroot 	for (;;) {
161*3678Sroot 		bp = pskip(bp);
162*3678Sroot 		if (!*bp)
163*3678Sroot 			return (0);
164*3678Sroot 		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1] && (!*bp || *bp == ':'))
165*3678Sroot 			return (1);
166*3678Sroot 	}
167*3678Sroot }
168*3678Sroot 
169*3678Sroot /*
170*3678Sroot  * Get a string valued option.
171*3678Sroot  * These are given as
172*3678Sroot  *	cl=^Z
173*3678Sroot  * Much decoding is done on the strings, and the strings are
174*3678Sroot  * placed in area, which is a ref parameter which is updated.
175*3678Sroot  * No checking on area overflow.
176*3678Sroot  */
177*3678Sroot char *
178*3678Sroot pgetstr(id, area)
179*3678Sroot 	char *id, **area;
180*3678Sroot {
181*3678Sroot 	register char *bp = pbuf;
182*3678Sroot 
183*3678Sroot 	for (;;) {
184*3678Sroot 		bp = pskip(bp);
185*3678Sroot 		if (!*bp)
186*3678Sroot 			return (0);
187*3678Sroot 		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
188*3678Sroot 			continue;
189*3678Sroot 		if (*bp != '=')
190*3678Sroot 			continue;
191*3678Sroot 		bp++;
192*3678Sroot 		return (pdecode(bp, area));
193*3678Sroot 	}
194*3678Sroot }
195*3678Sroot 
196*3678Sroot /*
197*3678Sroot  * Tdecode does the grung work to decode the
198*3678Sroot  * string capability escapes.
199*3678Sroot  */
200*3678Sroot static char *
201*3678Sroot pdecode(str, area)
202*3678Sroot 	register char *str;
203*3678Sroot 	char **area;
204*3678Sroot {
205*3678Sroot 	register char *cp;
206*3678Sroot 	register int c;
207*3678Sroot 	register char *dp;
208*3678Sroot 	int i;
209*3678Sroot 
210*3678Sroot 	cp = *area;
211*3678Sroot 	while ((c = *str++) && c != ':') {
212*3678Sroot 		switch (c) {
213*3678Sroot 
214*3678Sroot 		case '^':
215*3678Sroot 			c = *str++ & 037;
216*3678Sroot 			break;
217*3678Sroot 
218*3678Sroot 		case '\\':
219*3678Sroot 			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
220*3678Sroot 			c = *str++;
221*3678Sroot nextc:
222*3678Sroot 			if (*dp++ == c) {
223*3678Sroot 				c = *dp++;
224*3678Sroot 				break;
225*3678Sroot 			}
226*3678Sroot 			dp++;
227*3678Sroot 			if (*dp)
228*3678Sroot 				goto nextc;
229*3678Sroot 			if (isdigit(c)) {
230*3678Sroot 				c -= '0', i = 2;
231*3678Sroot 				do
232*3678Sroot 					c <<= 3, c |= *str++ - '0';
233*3678Sroot 				while (--i && isdigit(*str));
234*3678Sroot 			}
235*3678Sroot 			break;
236*3678Sroot 		}
237*3678Sroot 		*cp++ = c;
238*3678Sroot 	}
239*3678Sroot 	*cp++ = 0;
240*3678Sroot 	str = *area;
241*3678Sroot 	*area = cp;
242*3678Sroot 	return (str);
243*3678Sroot }
244