1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
32
33 #include "stdio.h"
34 #include "string.h"
35 #include "errno.h"
36 #include "stdlib.h"
37 #include "unistd.h"
38
39 #include "lp.h"
40 #include "filters.h"
41
42 _FILTER *filters;
43
44 size_t nfilters;
45
46 static int getfields (int, char *[], char *, int, int, char *);
47 static int fs_cmp(const void *, const void *);
48
49 /**
50 ** loadfilters() - READ FILTERS FROM FILTER TABLE INTO INTERNAL STRUCTURE
51 **/
52
53 int
loadfilters(char * file)54 loadfilters(char *file)
55 {
56 register _FILTER *pf;
57 int fd;
58 char *filt[FL_MAX],
59 buf[3 * BUFSIZ];
60 size_t nalloc;
61
62 if (filters) {
63 nalloc = nfilters;
64 trash_filters ();
65 } else
66 nalloc = FL_MAX_GUESS;
67
68 if ((fd = open_filtertable(file, "r")) < 0)
69 return (-1);
70
71 /*
72 * Preallocate space for the internal filter table.
73 * Our guess is the number of filters previously read in,
74 * if any have been read in before (see above).
75 */
76 filters = (_FILTER *)Malloc((nalloc + 1) * sizeof(_FILTER));
77 if (!filters) {
78 close(fd);
79 errno = ENOMEM;
80 return (-1);
81 }
82
83 for (
84 pf = filters, nfilters = 0;
85 getfields(fd, filt, buf, sizeof(buf), FL_MAX, FL_SEP) != -1;
86 pf++
87 ) {
88
89 char **list;
90
91 /*
92 * Allocate more space if needed.
93 */
94 if (++nfilters > nalloc) {
95 nalloc = nfilters;
96 filters = (_FILTER *)Realloc(
97 filters,
98 (nalloc + 1) * sizeof(_FILTER)
99 );
100 if (!filters) {
101 close(fd);
102 errno = ENOMEM;
103 return (-1);
104 }
105 pf = &filters[nfilters - 1];
106 }
107
108 #define DFLT(X) (filt[X] && *filt[X]? filt[X] : NAME_ANY)
109
110 pf->name = Strdup(filt[FL_NAME]);
111 pf->type = s_to_filtertype(filt[FL_TYPE]);
112 pf->command = Strdup(filt[FL_CMD]);
113
114 pf->printers = getlist(DFLT(FL_PRTRS), LP_WS, LP_SEP);
115
116 list = getlist(DFLT(FL_PTYPS), LP_WS, LP_SEP);
117 pf->printer_types = sl_to_typel(list);
118 freelist (list);
119
120 list = getlist(DFLT(FL_ITYPS), LP_WS, LP_SEP);
121 pf->input_types = sl_to_typel(list);
122 freelist (list);
123
124 list = getlist(DFLT(FL_OTYPS), LP_WS, LP_SEP);
125 pf->output_types = sl_to_typel(list);
126 freelist (list);
127
128 /*
129 * Note the use of "" instead of LP_WS. The
130 * "sl_to_templatel()" routine will take care
131 * of stripping leading blanks. Stripping trailing
132 * blanks would be nice but shouldn't matter.
133 */
134
135 /* quote reason #3 (in "getlist()") */
136 list = getlist(filt[FL_TMPS], "", LP_SEP);
137
138 /* quote reason #4 (in "s_to_template()") */
139 pf->templates = sl_to_templatel(list);
140 freelist (list);
141
142 }
143 if (errno != 0) {
144 int save_errno = errno;
145
146 free_filter (pf);
147 close(fd);
148 errno = save_errno;
149 return (-1);
150 }
151 close(fd);
152
153 /*
154 * If we have more space allocated than we need,
155 * return the extra.
156 */
157 if (nfilters != nalloc) {
158 filters = (_FILTER *)Realloc(
159 filters,
160 (nfilters + 1) * sizeof(_FILTER)
161 );
162 if (!filters) {
163 errno = ENOMEM;
164 return (-1);
165 }
166 }
167 filters[nfilters].name = 0;
168
169 /*
170 * Sort the filters, putting ``fast'' filters before
171 * ``slow'' filters. This preps the list for "insfilter()"
172 * so that it can easily pick fast filters over otherwise
173 * equivalent slow filters. This sorting is done every
174 * time we read in the table; one might think that if
175 * "putfilter()" would insert in the correct order then
176 * the table, when written out to disk, would be sorted
177 * already--removing the need to sort it here. We don't
178 * take that approach, because (1) sorting it isn't that
179 * expensive and (2) someone might tamper with the table
180 * file.
181 */
182 qsort ((char *)filters, nfilters, sizeof(_FILTER), fs_cmp);
183
184 return (0);
185 }
186
187 /**
188 ** getfields() - PARSE NON-COMMENT LINE FROM FILE INTO FIELDS
189 **/
190
191 static int
getfields(int fd,char * fields[],char * buf,int bufsiz,int max,char * seps)192 getfields(int fd, char *fields[], char *buf, int bufsiz, int max, char *seps)
193 {
194 register char *p,
195 *q;
196
197 register int n = 0;
198 enum ParsingMode {CHECK_LEAD_DBL_QUOTE, NORMAL_PARSING, LITERAL_READ} eMode;
199 errno = 0;
200 while (fdgets(buf, bufsiz, fd) != NULL) {
201 buf[strlen(buf) - 1] = 0;
202 p = buf + strspn(buf, " \t");
203 if (*p && *p != '#') {
204 for (eMode = CHECK_LEAD_DBL_QUOTE, fields[n++] = q = p; *p; ) {
205 switch (eMode) {
206 case CHECK_LEAD_DBL_QUOTE: /* check for leading double quote */
207 if (*p == '"') {
208 eMode = LITERAL_READ;
209 p++;
210 break;
211 }
212 eMode = NORMAL_PARSING;
213 /* FALLTHROUGH */
214
215 case NORMAL_PARSING: /* default legacy editing */
216 if (*p == '\\') {
217 if (
218 /* quote reason #1 */ p[1] == '\\'
219 /* quote reason #2 */ || strchr(seps, p[1])
220 )
221 p++;
222 *q++ = *p++;
223 } else if (strchr(seps, *p)) {
224 *q++ = 0;
225 p++;
226 if (n < max) {
227 fields[n++] = q;
228 eMode = CHECK_LEAD_DBL_QUOTE;
229 }
230 } else
231 *q++ = *p++;
232 break;
233
234 case LITERAL_READ: /* read literally until another double quote */
235 if (*p == '\\' && p[1] == '"') { /* embedded double quote */
236 p++;
237 *q++ = *p++;
238 } else if (*p == '"') { /* end of literal read */
239 p++;
240 eMode = NORMAL_PARSING;
241 } else {
242 *q++ = *p++; /* capture as is */
243 }
244 break;
245 }
246 }
247 *q = 0;
248 while (n < max)
249 fields[n++] = "";
250 return (n);
251 }
252 }
253 return (-1);
254 }
255
256 /**
257 ** fs_cmp() - COMPARE TWO FILTERS BY "FILTERTYPE"
258 **/
259
260 static int
fs_cmp(const void * pfa,const void * pfb)261 fs_cmp(const void *pfa, const void *pfb)
262 {
263 if (((_FILTER *)pfa)->type == ((_FILTER *)pfb)->type)
264 return (0);
265 else if (((_FILTER *)pfa)->type == fl_fast)
266 return (-1);
267 else
268 return (1);
269 }
270