bug on -P option
[unix-history] / usr / src / usr.sbin / lpr / common_source / printcap.c
CommitLineData
2fd90732
BJ
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
18static char *pbuf;
19char *pskip();
20char *pgetstr();
21char *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 */
28pgetent(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 */
80pnamatch(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 */
104static char *
105pskip(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 */
124pgetnum(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 */
155pgetflag(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 */
177char *
178pgetstr(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 */
200static char *
201pdecode(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++;
221nextc:
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}