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