Commit | Line | Data |
---|---|---|
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 | ||
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 | } |