xref: /illumos-gate/usr/src/cmd/lp/lib/filters/loadfilters.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
34 
35 #include "stdio.h"
36 #include "string.h"
37 #include "errno.h"
38 #include "stdlib.h"
39 #include "unistd.h"
40 
41 #include "lp.h"
42 #include "filters.h"
43 
44 _FILTER			*filters;
45 
46 size_t			nfilters;
47 
48 static int		getfields (int, char *[], char *, int, int, char *);
49 static int		fs_cmp(const void *, const void *);
50 
51 /**
52  ** loadfilters() - READ FILTERS FROM FILTER TABLE INTO INTERNAL STRUCTURE
53  **/
54 
55 int
56 loadfilters(char *file)
57 {
58 	register _FILTER	*pf;
59 	int fd;
60 	char			*filt[FL_MAX],
61 				buf[3 * BUFSIZ];
62 	size_t			nalloc;
63 
64 	if (filters) {
65 		nalloc = nfilters;
66 		trash_filters ();
67 	} else
68 		nalloc = FL_MAX_GUESS;
69 
70 	if ((fd = open_filtertable(file, "r")) < 0)
71 		return (-1);
72 
73 	/*
74 	 * Preallocate space for the internal filter table.
75 	 * Our guess is the number of filters previously read in,
76 	 * if any have been read in before (see above).
77 	 */
78 	filters = (_FILTER *)Malloc((nalloc + 1) * sizeof(_FILTER));
79 	if (!filters) {
80 		close(fd);
81 		errno = ENOMEM;
82 		return (-1);
83 	}
84 
85 	for (
86 		pf = filters, nfilters = 0;
87 		getfields(fd, filt, buf, sizeof(buf), FL_MAX, FL_SEP) != -1;
88 		pf++
89 	) {
90 
91 		char			**list;
92 
93 		/*
94 		 * Allocate more space if needed.
95 		 */
96 		if (++nfilters > nalloc) {
97 			nalloc = nfilters;
98 			filters = (_FILTER *)Realloc(
99 				filters,
100 				(nalloc + 1) * sizeof(_FILTER)
101 			);
102 			if (!filters) {
103 				close(fd);
104 				errno = ENOMEM;
105 				return (-1);
106 			}
107 			pf = &filters[nfilters - 1];
108 		}
109 
110 #define DFLT(X)	(filt[X] && *filt[X]? filt[X] : NAME_ANY)
111 
112 		pf->name = Strdup(filt[FL_NAME]);
113 		pf->type = s_to_filtertype(filt[FL_TYPE]);
114 		pf->command = Strdup(filt[FL_CMD]);
115 
116 		pf->printers = getlist(DFLT(FL_PRTRS), LP_WS, LP_SEP);
117 
118 		list = getlist(DFLT(FL_PTYPS), LP_WS, LP_SEP);
119 		pf->printer_types = sl_to_typel(list);
120 		freelist (list);
121 
122 		list = getlist(DFLT(FL_ITYPS), LP_WS, LP_SEP);
123 		pf->input_types = sl_to_typel(list);
124 		freelist (list);
125 
126 		list = getlist(DFLT(FL_OTYPS), LP_WS, LP_SEP);
127 		pf->output_types = sl_to_typel(list);
128 		freelist (list);
129 
130 		/*
131 		 * Note the use of "" instead of LP_WS. The
132 		 * "sl_to_templatel()" routine will take care
133 		 * of stripping leading blanks. Stripping trailing
134 		 * blanks would be nice but shouldn't matter.
135 		 */
136 
137 /* quote reason #3 (in "getlist()") */
138 		list = getlist(filt[FL_TMPS], "", LP_SEP);
139 
140 /* quote reason #4 (in "s_to_template()") */
141 		pf->templates = sl_to_templatel(list);
142 		freelist (list);
143 
144 	}
145 	if (errno != 0) {
146 		int			save_errno = errno;
147 
148 		free_filter (pf);
149 		close(fd);
150 		errno = save_errno;
151 		return (-1);
152 	}
153 	close(fd);
154 
155 	/*
156 	 * If we have more space allocated than we need,
157 	 * return the extra.
158 	 */
159 	if (nfilters != nalloc) {
160 		filters = (_FILTER *)Realloc(
161 			filters,
162 			(nfilters + 1) * sizeof(_FILTER)
163 		);
164 		if (!filters) {
165 			errno = ENOMEM;
166 			return (-1);
167 		}
168 	}
169 	filters[nfilters].name = 0;
170 
171 	/*
172 	 * Sort the filters, putting ``fast'' filters before
173 	 * ``slow'' filters. This preps the list for "insfilter()"
174 	 * so that it can easily pick fast filters over otherwise
175 	 * equivalent slow filters. This sorting is done every
176 	 * time we read in the table; one might think that if
177 	 * "putfilter()" would insert in the correct order then
178 	 * the table, when written out to disk, would be sorted
179 	 * already--removing the need to sort it here. We don't
180 	 * take that approach, because (1) sorting it isn't that
181 	 * expensive and (2) someone might tamper with the table
182 	 * file.
183 	 */
184 	qsort ((char *)filters, nfilters, sizeof(_FILTER), fs_cmp);
185 
186 	return (0);
187 }
188 
189 /**
190  ** getfields() - PARSE NON-COMMENT LINE FROM FILE INTO FIELDS
191  **/
192 
193 static int
194 getfields(int fd, char *fields[], char *buf, int bufsiz, int max, char *seps)
195 {
196 	register char		*p,
197 				*q;
198 
199 	register int		n	= 0;
200 	enum ParsingMode {CHECK_LEAD_DBL_QUOTE, NORMAL_PARSING, LITERAL_READ} eMode;
201 	errno = 0;
202 	while (fdgets(buf, bufsiz, fd) != NULL) {
203 		buf[strlen(buf) - 1] = 0;
204 		p = buf + strspn(buf, " \t");
205 		if (*p && *p != '#') {
206 			for (eMode = CHECK_LEAD_DBL_QUOTE, fields[n++] = q = p; *p; ) {
207 				switch (eMode) {
208 				case CHECK_LEAD_DBL_QUOTE: /* check for leading double quote */
209 					if (*p == '"') {
210 						eMode = LITERAL_READ;
211 						p++;
212 						break;
213 					}
214 					eMode = NORMAL_PARSING;
215 					/* drop through to NORMAL_PARSING case */
216 
217 				case NORMAL_PARSING: /* default legacy editing */
218 					if (*p == '\\') {
219 						if (
220 /* quote reason #1 */					p[1] == '\\'
221 /* quote reason #2 */				     || strchr(seps, p[1])
222 						)
223 							p++;
224 						*q++ = *p++;
225 					} else if (strchr(seps, *p)) {
226 						*q++ = 0;
227 						p++;
228 						if (n < max) {
229 							fields[n++] = q;
230 							eMode = CHECK_LEAD_DBL_QUOTE;
231 						}
232 					} else
233 						*q++ = *p++;
234 					break;
235 
236 				case LITERAL_READ: /* read literally until another double quote */
237 					if (*p == '\\' && p[1] == '"') { /* embedded double quote */
238 						p++;
239 						*q++ = *p++;
240 					} else if (*p == '"') { /* end of literal read */
241 						p++;
242 						eMode = NORMAL_PARSING;
243 					} else {
244 						*q++ = *p++; /* capture as is */
245 					}
246 					break;
247 				}
248 			}
249 			*q = 0;
250 			while (n < max)
251 				fields[n++] = "";
252 			return (n);
253 		}
254 	}
255 	return (-1);
256 }
257 
258 /**
259  ** fs_cmp() - COMPARE TWO FILTERS BY "FILTERTYPE"
260  **/
261 
262 static int
263 fs_cmp(const void *pfa, const void *pfb)
264 {
265 	if (((_FILTER *)pfa)->type == ((_FILTER *)pfb)->type)
266 		return (0);
267 	else if (((_FILTER *)pfa)->type == fl_fast)
268 		return (-1);
269 	else
270 		return (1);
271 }
272