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