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
46size_t			nfilters;
47
48static int		getfields (int, char *[], char *, int, int, char *);
49static int		fs_cmp(const void *, const void *);
50
51/**
52 ** loadfilters() - READ FILTERS FROM FILTER TABLE INTO INTERNAL STRUCTURE
53 **/
54
55int
56loadfilters(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
193static int
194getfields(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
262static int
263fs_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