xref: /illumos-gate/usr/src/cmd/lp/lib/filters/insfilter.c (revision 2a8bcb4e)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-1999 by Sun Microsystems, Inc.
28*7c478bd9Sstevel@tonic-gate  * All rights reserved.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include "assert.h"
34*7c478bd9Sstevel@tonic-gate #include "string.h"
35*7c478bd9Sstevel@tonic-gate #include "errno.h"
36*7c478bd9Sstevel@tonic-gate #include "stdlib.h"
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include "lp.h"
39*7c478bd9Sstevel@tonic-gate #include "filters.h"
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include "regex.h"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #define	MATCH(PT, PM) (STREQU((PT)->pattern, PATT_STAR) || \
45*7c478bd9Sstevel@tonic-gate 					match((PT)->re, *((PM)->pvalue)))
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate typedef struct PARM {
49*7c478bd9Sstevel@tonic-gate 	char			*keyword;
50*7c478bd9Sstevel@tonic-gate 	unsigned short		flags;
51*7c478bd9Sstevel@tonic-gate 	char			**pvalue;
52*7c478bd9Sstevel@tonic-gate }			PARM;
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #define	X_MUST	0x0800	/* Pipeline MUST use this parm */
55*7c478bd9Sstevel@tonic-gate #define	X_FIRST	0x1000	/* Use parm only in 1st cmd of pipeline */
56*7c478bd9Sstevel@tonic-gate #define	X_FIXED	0x2000	/* Get value from elsewhere, not parms */
57*7c478bd9Sstevel@tonic-gate #define	X_MANY	0x4000	/* Several values allowed for parm */
58*7c478bd9Sstevel@tonic-gate #define	X_USED	0x8000	/* Used already, don't use again */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate static struct S {
61*7c478bd9Sstevel@tonic-gate 	TYPE			input_type;
62*7c478bd9Sstevel@tonic-gate 	TYPE			output_type;
63*7c478bd9Sstevel@tonic-gate 	TYPE			printer_type;
64*7c478bd9Sstevel@tonic-gate 	char			*printer;
65*7c478bd9Sstevel@tonic-gate 	PARM			*parms;
66*7c478bd9Sstevel@tonic-gate } S;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate static int		searchlist_t(TYPE *, TYPE *);
71*7c478bd9Sstevel@tonic-gate static int		instantiate(_FILTER **, TYPE *, TYPE *,
72*7c478bd9Sstevel@tonic-gate 							int (*)(), void *);
73*7c478bd9Sstevel@tonic-gate static int		check_pipeline(_FILTER *, PARM *);
74*7c478bd9Sstevel@tonic-gate static char		*build_pipe(_FILTER *, PARM *, unsigned short *);
75*7c478bd9Sstevel@tonic-gate #else
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate static int		searchlist_t();
78*7c478bd9Sstevel@tonic-gate static int		instantiate();
79*7c478bd9Sstevel@tonic-gate static int		check_pipeline();
80*7c478bd9Sstevel@tonic-gate static char		*build_pipe();
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate #endif
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /*
85*7c478bd9Sstevel@tonic-gate  * Table of recognized keywords, with info. about them.
86*7c478bd9Sstevel@tonic-gate  */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate #define	NFIXED 4
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate static PARM		parmtable[] = {
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate /* These must be the first NFIXED, and in this order */
93*7c478bd9Sstevel@tonic-gate PARM_INPUT,	X_FIXED,			&S.input_type.name,
94*7c478bd9Sstevel@tonic-gate PARM_OUTPUT,	X_FIXED,			&S.output_type.name,
95*7c478bd9Sstevel@tonic-gate PARM_TERM,	X_FIXED,			&S.printer_type.name,
96*7c478bd9Sstevel@tonic-gate PARM_PRINTER,	X_FIXED,			&S.printer,
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate PARM_CPI,	FPARM_CPI,			0,
99*7c478bd9Sstevel@tonic-gate PARM_LPI,	FPARM_LPI,			0,
100*7c478bd9Sstevel@tonic-gate PARM_LENGTH,	FPARM_LENGTH,			0,
101*7c478bd9Sstevel@tonic-gate PARM_WIDTH,	FPARM_WIDTH,			0,
102*7c478bd9Sstevel@tonic-gate PARM_PAGES,	FPARM_PAGES | X_FIRST | X_MUST,	0,
103*7c478bd9Sstevel@tonic-gate PARM_CHARSET,	FPARM_CHARSET,			0,
104*7c478bd9Sstevel@tonic-gate PARM_FORM,	FPARM_FORM,			0,
105*7c478bd9Sstevel@tonic-gate PARM_COPIES,	FPARM_COPIES | X_FIRST,		0,
106*7c478bd9Sstevel@tonic-gate PARM_MODES,	FPARM_MODES | X_MANY | X_MUST,	0,
107*7c478bd9Sstevel@tonic-gate 0,		0,				0,
108*7c478bd9Sstevel@tonic-gate };
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate /*
111*7c478bd9Sstevel@tonic-gate  * insfilter()
112*7c478bd9Sstevel@tonic-gate  */
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate FILTERTYPE
115*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
insfilter(char ** pipes,char * input_type,char * output_type,char * printer_type,char * printer,char ** parms,unsigned short * flagsp)116*7c478bd9Sstevel@tonic-gate insfilter(
117*7c478bd9Sstevel@tonic-gate 	char			**pipes,
118*7c478bd9Sstevel@tonic-gate 	char			*input_type,
119*7c478bd9Sstevel@tonic-gate 	char			*output_type,
120*7c478bd9Sstevel@tonic-gate 	char			*printer_type,
121*7c478bd9Sstevel@tonic-gate 	char			*printer,
122*7c478bd9Sstevel@tonic-gate 	char			**parms,
123*7c478bd9Sstevel@tonic-gate 	unsigned short		*flagsp
124*7c478bd9Sstevel@tonic-gate )
125*7c478bd9Sstevel@tonic-gate #else
126*7c478bd9Sstevel@tonic-gate insfilter(pipes, input_type, output_type, printer_type, printer, parms, flagsp)
127*7c478bd9Sstevel@tonic-gate 	char			**pipes,
128*7c478bd9Sstevel@tonic-gate 				*input_type,
129*7c478bd9Sstevel@tonic-gate 				*output_type,
130*7c478bd9Sstevel@tonic-gate 				*printer_type,
131*7c478bd9Sstevel@tonic-gate 				*printer,
132*7c478bd9Sstevel@tonic-gate 				**parms;
133*7c478bd9Sstevel@tonic-gate 	unsigned short		*flagsp;
134*7c478bd9Sstevel@tonic-gate #endif
135*7c478bd9Sstevel@tonic-gate {
136*7c478bd9Sstevel@tonic-gate 	_FILTER			*pipeline;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	FILTERTYPE		ret;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	S.input_type.name = input_type;
142*7c478bd9Sstevel@tonic-gate 	S.input_type.info = isterminfo(input_type);
143*7c478bd9Sstevel@tonic-gate 	S.output_type.name = output_type;
144*7c478bd9Sstevel@tonic-gate 	S.output_type.info = isterminfo(output_type);
145*7c478bd9Sstevel@tonic-gate 	S.printer_type.name = printer_type;
146*7c478bd9Sstevel@tonic-gate 	S.printer_type.info = isterminfo(printer_type);
147*7c478bd9Sstevel@tonic-gate 	S.printer = printer;
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	/*
150*7c478bd9Sstevel@tonic-gate 	 * If the filters have't been loaded yet, do so now.
151*7c478bd9Sstevel@tonic-gate 	 * We'll load the standard table, but the caller can override
152*7c478bd9Sstevel@tonic-gate 	 * this by first calling "loadfilters()" with the appropriate
153*7c478bd9Sstevel@tonic-gate 	 * filter table name.
154*7c478bd9Sstevel@tonic-gate 	 */
155*7c478bd9Sstevel@tonic-gate 	if (!filters && loadfilters((char *)0) == -1)
156*7c478bd9Sstevel@tonic-gate 		return (fl_none);
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	/*
159*7c478bd9Sstevel@tonic-gate 	 * Allocate and initialize space to hold additional
160*7c478bd9Sstevel@tonic-gate 	 * information about each item in "parms".
161*7c478bd9Sstevel@tonic-gate 	 * THIS SPACE MUST BE FREED BEFORE EXITING THIS ROUTINE!
162*7c478bd9Sstevel@tonic-gate 	 */
163*7c478bd9Sstevel@tonic-gate 	{
164*7c478bd9Sstevel@tonic-gate 		register int		n;
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 		register PARM *		pp;
167*7c478bd9Sstevel@tonic-gate 		register PARM *		ppt;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		register char **	p;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 		for (n = 0, p = parms; *p; n++, p++)
174*7c478bd9Sstevel@tonic-gate 			;
175*7c478bd9Sstevel@tonic-gate 		n /= 2;
176*7c478bd9Sstevel@tonic-gate 		n += NFIXED; /* for fixed parms (in/out/printer types) */
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 		if (!(S.parms = (PARM *)Malloc((n + 1) * sizeof (PARM)))) {
179*7c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
180*7c478bd9Sstevel@tonic-gate 			return (fl_none);
181*7c478bd9Sstevel@tonic-gate 		}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 		for (ppt = parmtable; ppt->keyword; ppt++)
184*7c478bd9Sstevel@tonic-gate 			ppt->flags &= ~X_USED;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 		/*
187*7c478bd9Sstevel@tonic-gate 		 * Load the parameter list with the fixed ``type''
188*7c478bd9Sstevel@tonic-gate 		 * parameters. Mark them as used (if appropriate)
189*7c478bd9Sstevel@tonic-gate 		 * so we don't pick them up from the callers list.
190*7c478bd9Sstevel@tonic-gate 		 */
191*7c478bd9Sstevel@tonic-gate 		pp = S.parms;
192*7c478bd9Sstevel@tonic-gate 		for (ppt = parmtable; ppt < parmtable + NFIXED; ppt++) {
193*7c478bd9Sstevel@tonic-gate 			pp->keyword = ppt->keyword;
194*7c478bd9Sstevel@tonic-gate 			pp->flags = ppt->flags;
195*7c478bd9Sstevel@tonic-gate 			if (ppt->flags & X_FIXED)
196*7c478bd9Sstevel@tonic-gate 				pp->pvalue = ppt->pvalue;
197*7c478bd9Sstevel@tonic-gate 			else
198*7c478bd9Sstevel@tonic-gate 				pp->pvalue = parms + 1;
199*7c478bd9Sstevel@tonic-gate 			if (!(ppt->flags & X_MANY))
200*7c478bd9Sstevel@tonic-gate 				ppt->flags |= X_USED;
201*7c478bd9Sstevel@tonic-gate 			pp++;
202*7c478bd9Sstevel@tonic-gate 		}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 		/*
205*7c478bd9Sstevel@tonic-gate 		 * Copy each parameter from the caller supplied list
206*7c478bd9Sstevel@tonic-gate 		 * to another list, adding information gathered from
207*7c478bd9Sstevel@tonic-gate 		 * the keyword table. Note that some keywords should
208*7c478bd9Sstevel@tonic-gate 		 * be given only once; additional occurrances in the
209*7c478bd9Sstevel@tonic-gate 		 * caller's list will be ignored.
210*7c478bd9Sstevel@tonic-gate 		 */
211*7c478bd9Sstevel@tonic-gate 		for (p = parms; *p; p += 2)
212*7c478bd9Sstevel@tonic-gate 			for (ppt = parmtable; ppt->keyword; ppt++)
213*7c478bd9Sstevel@tonic-gate 				if (STREQU(*p, ppt->keyword) &&
214*7c478bd9Sstevel@tonic-gate 						!(ppt->flags & X_USED)) {
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 					pp->keyword = ppt->keyword;
217*7c478bd9Sstevel@tonic-gate 					pp->flags = ppt->flags;
218*7c478bd9Sstevel@tonic-gate 					if (ppt->flags & X_FIXED)
219*7c478bd9Sstevel@tonic-gate 						pp->pvalue = ppt->pvalue;
220*7c478bd9Sstevel@tonic-gate 					else
221*7c478bd9Sstevel@tonic-gate 						pp->pvalue = p + 1;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 					if (!(ppt->flags & X_MANY))
224*7c478bd9Sstevel@tonic-gate 						ppt->flags |= X_USED;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 					pp++;
227*7c478bd9Sstevel@tonic-gate 					break;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 				}
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 		pp->keyword = 0;
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	}
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	/*
236*7c478bd9Sstevel@tonic-gate 	 * Preview the list of filters, to rule out those that
237*7c478bd9Sstevel@tonic-gate 	 * can't possibly work.
238*7c478bd9Sstevel@tonic-gate 	 */
239*7c478bd9Sstevel@tonic-gate 	{
240*7c478bd9Sstevel@tonic-gate 		register _FILTER *	pf;
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 		for (pf = filters; pf->name; pf++) {
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 			pf->mark = FL_CLEAR;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 			if (printer && !searchlist(printer, pf->printers))
247*7c478bd9Sstevel@tonic-gate 				pf->mark = FL_SKIP;
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 			else if (printer_type &&
250*7c478bd9Sstevel@tonic-gate 					!searchlist_t(&(S.printer_type),
251*7c478bd9Sstevel@tonic-gate 							pf->printer_types))
252*7c478bd9Sstevel@tonic-gate 				pf->mark = FL_SKIP;
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 		}
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	/*
258*7c478bd9Sstevel@tonic-gate 	 * Find a pipeline that will convert the input-type to the
259*7c478bd9Sstevel@tonic-gate 	 * output-type and map the parameters as well.
260*7c478bd9Sstevel@tonic-gate 	 */
261*7c478bd9Sstevel@tonic-gate 	if (!instantiate(&pipeline, &S.input_type, &S.output_type,
262*7c478bd9Sstevel@tonic-gate 			check_pipeline, S.parms)) {
263*7c478bd9Sstevel@tonic-gate 		ret = fl_none;
264*7c478bd9Sstevel@tonic-gate 		goto Return;
265*7c478bd9Sstevel@tonic-gate 	}
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	if (!pipes) {
268*7c478bd9Sstevel@tonic-gate 		ret = fl_both;
269*7c478bd9Sstevel@tonic-gate 		goto Return;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	} else {
272*7c478bd9Sstevel@tonic-gate 		register _FILTER *	pf;
273*7c478bd9Sstevel@tonic-gate 		register _FILTER *	pfastf; /* first in fast pipe */
274*7c478bd9Sstevel@tonic-gate 		register _FILTER *	pslowf; /* last in slow pipe */
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 		/*
277*7c478bd9Sstevel@tonic-gate 		 * Found a pipeline, so now build it.
278*7c478bd9Sstevel@tonic-gate 		 */
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 		/*
281*7c478bd9Sstevel@tonic-gate 		 * Split pipeline after last slow filter.
282*7c478bd9Sstevel@tonic-gate 		 * "pipeline" will point to first filter in slow
283*7c478bd9Sstevel@tonic-gate 		 * pipe, "pfastf" will point to first filter in
284*7c478bd9Sstevel@tonic-gate 		 * fast pipe.
285*7c478bd9Sstevel@tonic-gate 		 */
286*7c478bd9Sstevel@tonic-gate 		for (pf = pfastf = pipeline, pslowf = 0; pf; pf = pf->next)
287*7c478bd9Sstevel@tonic-gate 			if (pf->type == fl_slow) {
288*7c478bd9Sstevel@tonic-gate 				pslowf = pf;
289*7c478bd9Sstevel@tonic-gate 				pfastf = pf->next;
290*7c478bd9Sstevel@tonic-gate 			}
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 		if (pslowf) {
293*7c478bd9Sstevel@tonic-gate 			assert(pslowf != pfastf);
294*7c478bd9Sstevel@tonic-gate 			pslowf->next = 0;
295*7c478bd9Sstevel@tonic-gate 			pipes[0] = build_pipe(pipeline, S.parms, flagsp);
296*7c478bd9Sstevel@tonic-gate 			ret = fl_slow;
297*7c478bd9Sstevel@tonic-gate 		} else
298*7c478bd9Sstevel@tonic-gate 			pipes[0] = 0;
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 		if (pfastf) {
301*7c478bd9Sstevel@tonic-gate 			pipes[1] = build_pipe(pfastf, S.parms, flagsp);
302*7c478bd9Sstevel@tonic-gate 			ret = fl_fast;
303*7c478bd9Sstevel@tonic-gate 		} else
304*7c478bd9Sstevel@tonic-gate 			pipes[1] = 0;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 		if (pslowf && pfastf)
307*7c478bd9Sstevel@tonic-gate 			ret = fl_both;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 		/*
310*7c478bd9Sstevel@tonic-gate 		 * Check for the oops case.
311*7c478bd9Sstevel@tonic-gate 		 */
312*7c478bd9Sstevel@tonic-gate 		if (pslowf && !pipes[0] || pfastf && !pipes[1])
313*7c478bd9Sstevel@tonic-gate 			ret = fl_none;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate Return:	Free((char *)S.parms);
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	return (ret);
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate /*
323*7c478bd9Sstevel@tonic-gate  * searchlist_t() - SEARCH (TYPE *) LIST FOR ITEM
324*7c478bd9Sstevel@tonic-gate  */
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate static int
327*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
typematch(TYPE * type1,TYPE * type2)328*7c478bd9Sstevel@tonic-gate typematch(
329*7c478bd9Sstevel@tonic-gate 	TYPE			*type1,
330*7c478bd9Sstevel@tonic-gate 	TYPE			*type2
331*7c478bd9Sstevel@tonic-gate )
332*7c478bd9Sstevel@tonic-gate #else
333*7c478bd9Sstevel@tonic-gate typematch(type1, type2)
334*7c478bd9Sstevel@tonic-gate 	TYPE			*type1, *type2;
335*7c478bd9Sstevel@tonic-gate #endif
336*7c478bd9Sstevel@tonic-gate {
337*7c478bd9Sstevel@tonic-gate 	if (STREQU(type1->name, NAME_ANY) || STREQU(type2->name, NAME_ANY) ||
338*7c478bd9Sstevel@tonic-gate 			STREQU(type1->name, type2->name) ||
339*7c478bd9Sstevel@tonic-gate 			(STREQU(type1->name, NAME_TERMINFO) && type2->info) ||
340*7c478bd9Sstevel@tonic-gate 			(STREQU(type2->name, NAME_TERMINFO) && type1->info))
341*7c478bd9Sstevel@tonic-gate 		return (1);
342*7c478bd9Sstevel@tonic-gate 	else
343*7c478bd9Sstevel@tonic-gate 		return (0);
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate static int
347*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
searchlist_t(TYPE * itemp,TYPE * list)348*7c478bd9Sstevel@tonic-gate searchlist_t(
349*7c478bd9Sstevel@tonic-gate 	TYPE			*itemp,
350*7c478bd9Sstevel@tonic-gate 	TYPE			*list
351*7c478bd9Sstevel@tonic-gate )
352*7c478bd9Sstevel@tonic-gate #else
353*7c478bd9Sstevel@tonic-gate searchlist_t(itemp, list)
354*7c478bd9Sstevel@tonic-gate 	TYPE			*itemp;
355*7c478bd9Sstevel@tonic-gate 	register TYPE		*list;
356*7c478bd9Sstevel@tonic-gate #endif
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	if (!list || !list->name)
359*7c478bd9Sstevel@tonic-gate 		return (0);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	/*
362*7c478bd9Sstevel@tonic-gate 	 * This is a linear search--we believe that the lists
363*7c478bd9Sstevel@tonic-gate 	 * will be short.
364*7c478bd9Sstevel@tonic-gate 	 */
365*7c478bd9Sstevel@tonic-gate 	while (list->name) {
366*7c478bd9Sstevel@tonic-gate 		if (typematch(itemp, list))
367*7c478bd9Sstevel@tonic-gate 			return (1);
368*7c478bd9Sstevel@tonic-gate 		list++;
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate 	return (0);
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate /*
374*7c478bd9Sstevel@tonic-gate  * instantiate() - CREATE FILTER-PIPELINE KNOWING INPUT/OUTPUT TYPES
375*7c478bd9Sstevel@tonic-gate  */
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate /*
378*7c478bd9Sstevel@tonic-gate  *	The "instantiate()" routine is the meat of the "insfilter()"
379*7c478bd9Sstevel@tonic-gate  *	algorithm. It is given an input-type and output-type and finds a
380*7c478bd9Sstevel@tonic-gate  *	filter-pipline that will convert the input-type into the
381*7c478bd9Sstevel@tonic-gate  *	output-type. Since the filter-pipeline must meet other criteria,
382*7c478bd9Sstevel@tonic-gate  *	a function "verify" is also given, along with the set of criteria;
383*7c478bd9Sstevel@tonic-gate  *	these are used by "instantiate()" to verify a filter-pipeline.
384*7c478bd9Sstevel@tonic-gate  *
385*7c478bd9Sstevel@tonic-gate  *	The filter-pipeline is built up and returned in "pipeline".
386*7c478bd9Sstevel@tonic-gate  *	Conceptually this is just a list of filters, with the pipeline to
387*7c478bd9Sstevel@tonic-gate  *	be constructed by simply concatenating the filter simple-commmands
388*7c478bd9Sstevel@tonic-gate  *	(after filling in option templates) in the order found in the
389*7c478bd9Sstevel@tonic-gate  *	list. What is used in the routine, though, is a pair of linked
390*7c478bd9Sstevel@tonic-gate  *	lists, one list forming the ``right-half'' of the pipeline, the
391*7c478bd9Sstevel@tonic-gate  *	other forming the ``left-half''. The pipeline is then the two
392*7c478bd9Sstevel@tonic-gate  *	lists taken together.
393*7c478bd9Sstevel@tonic-gate  *
394*7c478bd9Sstevel@tonic-gate  *	The "instantiate()" routine looks for a single filter that matches
395*7c478bd9Sstevel@tonic-gate  *	the input-type and output-type and satisfies the criteria. If one
396*7c478bd9Sstevel@tonic-gate  *	is found, it is added to the end of the ``left-half'' list (it
397*7c478bd9Sstevel@tonic-gate  *	could be added to the beginning of the ``right-half'' list with no
398*7c478bd9Sstevel@tonic-gate  *	problem). The two lists are linked together to form one linked
399*7c478bd9Sstevel@tonic-gate  *	list, which is passed, along with the set of criteria, to the
400*7c478bd9Sstevel@tonic-gate  *	"verify" routine to check the filter-pipeline. If it passes the
401*7c478bd9Sstevel@tonic-gate  *	check, the work is done.
402*7c478bd9Sstevel@tonic-gate  *
403*7c478bd9Sstevel@tonic-gate  *	If a single filter is not found, "instantiate()" examines all
404*7c478bd9Sstevel@tonic-gate  *	pairs of filters where one in the pair can accept the input-type
405*7c478bd9Sstevel@tonic-gate  *	and the other can produce the output-type. For each of these, it
406*7c478bd9Sstevel@tonic-gate  *	calls itself again to find a filter that can join the pair
407*7c478bd9Sstevel@tonic-gate  *	together--one that accepts as input the output-type of the first
408*7c478bd9Sstevel@tonic-gate  *	in the pair, and produces as output the input-type of the second
409*7c478bd9Sstevel@tonic-gate  *	in the pair.  This joining filter may be a single filter or may
410*7c478bd9Sstevel@tonic-gate  *	be a filter-pipeline. "instantiate()" checks for the trivial case
411*7c478bd9Sstevel@tonic-gate  *	where the input-type is the output-type; with trivial cases it
412*7c478bd9Sstevel@tonic-gate  *	links the two lists without adding a filter and checks it with
413*7c478bd9Sstevel@tonic-gate  *	"verify".
414*7c478bd9Sstevel@tonic-gate  */
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate /*
417*7c478bd9Sstevel@tonic-gate  * instantiate()
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate /*
421*7c478bd9Sstevel@tonic-gate  * A PIPELIST is what is passed to each recursive call to "instantiate()".
422*7c478bd9Sstevel@tonic-gate  * It contains a pointer to the end of the ``left-list'', a pointer to the
423*7c478bd9Sstevel@tonic-gate  * head of the ``right-list'', and a pointer to the head of the left-list.
424*7c478bd9Sstevel@tonic-gate  * The latter is passed to "verify". The end of the right-list (and thus
425*7c478bd9Sstevel@tonic-gate  * the end of the entire list when left and right are joined) is the
426*7c478bd9Sstevel@tonic-gate  * filter with a null ``next'' pointer.
427*7c478bd9Sstevel@tonic-gate  */
428*7c478bd9Sstevel@tonic-gate typedef struct PIPELIST {
429*7c478bd9Sstevel@tonic-gate 	_FILTER *		lhead;
430*7c478bd9Sstevel@tonic-gate 	_FILTER *		ltail;
431*7c478bd9Sstevel@tonic-gate 	_FILTER *		rhead;
432*7c478bd9Sstevel@tonic-gate }			PIPELIST;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
435*7c478bd9Sstevel@tonic-gate static int		_instantiate(PIPELIST *, TYPE *, TYPE *,
436*7c478bd9Sstevel@tonic-gate 					int (*)(_FILTER *, void *), void *);
437*7c478bd9Sstevel@tonic-gate #else
438*7c478bd9Sstevel@tonic-gate static int		_instantiate();
439*7c478bd9Sstevel@tonic-gate #endif
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate static int		peg;
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate static int
444*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
instantiate(_FILTER ** pline,TYPE * input,TYPE * output,int (* verify)(_FILTER *,void *),void * criteria)445*7c478bd9Sstevel@tonic-gate instantiate(
446*7c478bd9Sstevel@tonic-gate 	_FILTER			**pline,
447*7c478bd9Sstevel@tonic-gate 	TYPE			*input,
448*7c478bd9Sstevel@tonic-gate 	TYPE			*output,
449*7c478bd9Sstevel@tonic-gate 	int			(*verify)(_FILTER *, void *),
450*7c478bd9Sstevel@tonic-gate 	void			*criteria
451*7c478bd9Sstevel@tonic-gate )
452*7c478bd9Sstevel@tonic-gate #else
453*7c478bd9Sstevel@tonic-gate instantiate(pline, input, output, verify, criteria)
454*7c478bd9Sstevel@tonic-gate 	_FILTER			**pline;
455*7c478bd9Sstevel@tonic-gate 	TYPE			*input,
456*7c478bd9Sstevel@tonic-gate 				*output;
457*7c478bd9Sstevel@tonic-gate 	int			(*verify)();
458*7c478bd9Sstevel@tonic-gate 	char			*criteria;
459*7c478bd9Sstevel@tonic-gate #endif
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	PIPELIST		p;
462*7c478bd9Sstevel@tonic-gate 	int			ret;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	peg = 0;
465*7c478bd9Sstevel@tonic-gate 	p.lhead = p.ltail = p.rhead = 0;
466*7c478bd9Sstevel@tonic-gate 	ret = _instantiate(&p, input, output, verify, criteria);
467*7c478bd9Sstevel@tonic-gate 	*pline = p.lhead;
468*7c478bd9Sstevel@tonic-gate 	return (ret);
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate #define	ENTER()		int our_tag; our_tag = ++peg;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate #define	LEAVE(Y)	if (!Y) { \
474*7c478bd9Sstevel@tonic-gate 				register _FILTER *f; \
475*7c478bd9Sstevel@tonic-gate 				for (f = filters; f->name; f++) \
476*7c478bd9Sstevel@tonic-gate 					CLEAR(f); \
477*7c478bd9Sstevel@tonic-gate 				return (0); \
478*7c478bd9Sstevel@tonic-gate 			} else \
479*7c478bd9Sstevel@tonic-gate 				return (1)
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate #define	MARK(F, M)	(((F)->mark |= M), (F)->level = our_tag)
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate #define	CLEAR(F)	if ((F)->level == our_tag) \
484*7c478bd9Sstevel@tonic-gate 				(F)->level = 0, (F)->mark = FL_CLEAR
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate #define	CHECK(F, M)	(((F)->mark & M) && (F)->level == our_tag)
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate #define	USED(F)		((F)->mark)
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate static int
491*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
_instantiate(PIPELIST * pp,TYPE * inputp,TYPE * outputp,int (* verify)(_FILTER *,void *),void * criteria)492*7c478bd9Sstevel@tonic-gate _instantiate(
493*7c478bd9Sstevel@tonic-gate 	PIPELIST		*pp,
494*7c478bd9Sstevel@tonic-gate 	TYPE			*inputp,
495*7c478bd9Sstevel@tonic-gate 	TYPE			*outputp,
496*7c478bd9Sstevel@tonic-gate 	int			(*verify)(_FILTER *, void *),
497*7c478bd9Sstevel@tonic-gate 	void			*criteria
498*7c478bd9Sstevel@tonic-gate )
499*7c478bd9Sstevel@tonic-gate #else
500*7c478bd9Sstevel@tonic-gate _instantiate(pp, inputp, outputp, verify, criteria)
501*7c478bd9Sstevel@tonic-gate 	PIPELIST		*pp;
502*7c478bd9Sstevel@tonic-gate 	TYPE			*inputp,
503*7c478bd9Sstevel@tonic-gate 				*outputp;
504*7c478bd9Sstevel@tonic-gate 	int			(*verify)();
505*7c478bd9Sstevel@tonic-gate 	char			*criteria;
506*7c478bd9Sstevel@tonic-gate #endif
507*7c478bd9Sstevel@tonic-gate {
508*7c478bd9Sstevel@tonic-gate 	register _FILTER	*prev_lhead;
509*7c478bd9Sstevel@tonic-gate 	register _FILTER	*prev_ltail;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	/*
513*7c478bd9Sstevel@tonic-gate 	 * Must be first ``statement'' after declarations.
514*7c478bd9Sstevel@tonic-gate 	 */
515*7c478bd9Sstevel@tonic-gate 	ENTER();
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	/*
518*7c478bd9Sstevel@tonic-gate 	 * We're done when we've added filters on the left and right
519*7c478bd9Sstevel@tonic-gate 	 * that let us connect the left and right directly; i.e. when
520*7c478bd9Sstevel@tonic-gate 	 * the output of the left is the same type as the input of the
521*7c478bd9Sstevel@tonic-gate 	 * right. HOWEVER, there must be at least one filter involved,
522*7c478bd9Sstevel@tonic-gate 	 * to allow the filter feature to be used for handling modes,
523*7c478bd9Sstevel@tonic-gate 	 * pages, copies, etc. not just FILTERING data.
524*7c478bd9Sstevel@tonic-gate 	 */
525*7c478bd9Sstevel@tonic-gate 	if (typematch(inputp, outputp) && pp->lhead) {
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 		/*
528*7c478bd9Sstevel@tonic-gate 		 * Getting here means that we must have a left and right
529*7c478bd9Sstevel@tonic-gate 		 * pipeline. Why? For "pp->lhead" to be non-zero it
530*7c478bd9Sstevel@tonic-gate 		 * must have been set below. The first place below
531*7c478bd9Sstevel@tonic-gate 		 * doesn't set the right pipeline, but it also doesn't
532*7c478bd9Sstevel@tonic-gate 		 * get us here (at least not directly). The only
533*7c478bd9Sstevel@tonic-gate 		 * place we can get to here again is the second place
534*7c478bd9Sstevel@tonic-gate 		 * "pp->phead" is set, and THAT sets the right pipeline.
535*7c478bd9Sstevel@tonic-gate 		 */
536*7c478bd9Sstevel@tonic-gate 		pp->ltail->next = pp->rhead;
537*7c478bd9Sstevel@tonic-gate 		if ((*verify)(pp->lhead, criteria))
538*7c478bd9Sstevel@tonic-gate 			LEAVE(1);
539*7c478bd9Sstevel@tonic-gate 		else
540*7c478bd9Sstevel@tonic-gate 			LEAVE(0);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	}
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	/*
545*7c478bd9Sstevel@tonic-gate 	 * Each time we search the list of filters, we examine
546*7c478bd9Sstevel@tonic-gate 	 * them in the order given and stop searching when a filter
547*7c478bd9Sstevel@tonic-gate 	 * that meets the needs is found. If the list is ordered with
548*7c478bd9Sstevel@tonic-gate 	 * fast filters before slow filters, then fast filters will
549*7c478bd9Sstevel@tonic-gate 	 * be chosen over otherwise-equal filters.
550*7c478bd9Sstevel@tonic-gate 	 */
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	/*
553*7c478bd9Sstevel@tonic-gate 	 * See if there's a single filter that will work.
554*7c478bd9Sstevel@tonic-gate 	 * Just in case we can't find one, mark those that
555*7c478bd9Sstevel@tonic-gate 	 * will work as left- or right-filters, to save time
556*7c478bd9Sstevel@tonic-gate 	 * later.
557*7c478bd9Sstevel@tonic-gate 	 *
558*7c478bd9Sstevel@tonic-gate 	 * Also, record exactly *which* input/output
559*7c478bd9Sstevel@tonic-gate 	 * type would be needed if the filter was used.
560*7c478bd9Sstevel@tonic-gate 	 * This record will be complete (both input and output
561*7c478bd9Sstevel@tonic-gate 	 * recorded) IF the single filter works. Otherwise,
562*7c478bd9Sstevel@tonic-gate 	 * only the input, for the left possible filters,
563*7c478bd9Sstevel@tonic-gate 	 * and the output, for the right possible filters,
564*7c478bd9Sstevel@tonic-gate 	 * will be recorded. Thus, we'll have to record the
565*7c478bd9Sstevel@tonic-gate 	 * missing types later.
566*7c478bd9Sstevel@tonic-gate 	 */
567*7c478bd9Sstevel@tonic-gate 	{
568*7c478bd9Sstevel@tonic-gate 		register _FILTER *		pf;
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 		for (pf = filters; pf->name; pf++) {
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 			if (USED(pf))
574*7c478bd9Sstevel@tonic-gate 				continue;
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 			if (searchlist_t(inputp, pf->input_types)) {
577*7c478bd9Sstevel@tonic-gate 				MARK(pf, FL_LEFT);
578*7c478bd9Sstevel@tonic-gate 				pf->inputp = inputp;
579*7c478bd9Sstevel@tonic-gate 			}
580*7c478bd9Sstevel@tonic-gate 			if (searchlist_t(outputp, pf->output_types)) {
581*7c478bd9Sstevel@tonic-gate 				MARK(pf, FL_RIGHT);
582*7c478bd9Sstevel@tonic-gate 				pf->outputp = outputp;
583*7c478bd9Sstevel@tonic-gate 			}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 			if (CHECK(pf, FL_LEFT) && CHECK(pf, FL_RIGHT)) {
586*7c478bd9Sstevel@tonic-gate 				prev_lhead = pp->lhead;
587*7c478bd9Sstevel@tonic-gate 				prev_ltail = pp->ltail;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 				if (!pp->lhead)
590*7c478bd9Sstevel@tonic-gate 					pp->lhead = pf;
591*7c478bd9Sstevel@tonic-gate 				else
592*7c478bd9Sstevel@tonic-gate 					pp->ltail->next = pf;
593*7c478bd9Sstevel@tonic-gate 				(pp->ltail = pf)->next = pp->rhead;
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 				if ((*verify)(pp->lhead, criteria))
596*7c478bd9Sstevel@tonic-gate 					LEAVE(1);
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 				if ((pp->ltail = prev_ltail))
599*7c478bd9Sstevel@tonic-gate 					pp->ltail->next = 0;
600*7c478bd9Sstevel@tonic-gate 				pp->lhead = prev_lhead;
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 			}
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 		}
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	/*
608*7c478bd9Sstevel@tonic-gate 	 * Try all DISJOINT pairs of left- and right-filters; recursively
609*7c478bd9Sstevel@tonic-gate 	 * call this function to find a filter that will connect
610*7c478bd9Sstevel@tonic-gate 	 * them (it might be a ``null'' filter).
611*7c478bd9Sstevel@tonic-gate 	 */
612*7c478bd9Sstevel@tonic-gate 	{
613*7c478bd9Sstevel@tonic-gate 		register _FILTER *	pfl;
614*7c478bd9Sstevel@tonic-gate 		register _FILTER *	pfr;
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 		register TYPE *		llist;
617*7c478bd9Sstevel@tonic-gate 		register TYPE *		rlist;
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 		for (pfl = filters; pfl->name; pfl++) {
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 			if (!CHECK(pfl, FL_LEFT))
623*7c478bd9Sstevel@tonic-gate 				continue;
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 			for (pfr = filters; pfr->name; pfr++) {
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 				if (pfr == pfl || !CHECK(pfr, FL_RIGHT))
628*7c478bd9Sstevel@tonic-gate 					continue;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 				prev_lhead = pp->lhead;
631*7c478bd9Sstevel@tonic-gate 				prev_ltail = pp->ltail;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 				if (!pp->lhead)
634*7c478bd9Sstevel@tonic-gate 					pp->lhead = pfl;
635*7c478bd9Sstevel@tonic-gate 				else
636*7c478bd9Sstevel@tonic-gate 					pp->ltail->next = pfl;
637*7c478bd9Sstevel@tonic-gate 				(pp->ltail = pfl)->next = 0;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 				pfr->next = pp->rhead;
640*7c478bd9Sstevel@tonic-gate 				pp->rhead = pfr;
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 				/*
643*7c478bd9Sstevel@tonic-gate 				 * Try all the possible output types of
644*7c478bd9Sstevel@tonic-gate 				 * the left filter with all the possible
645*7c478bd9Sstevel@tonic-gate 				 * input types of the right filter. If
646*7c478bd9Sstevel@tonic-gate 				 * we find a combo. that works, record
647*7c478bd9Sstevel@tonic-gate 				 * the output and input types for the
648*7c478bd9Sstevel@tonic-gate 				 * respective filters.
649*7c478bd9Sstevel@tonic-gate 				 */
650*7c478bd9Sstevel@tonic-gate 				for (llist = pfl->output_types; llist->name;
651*7c478bd9Sstevel@tonic-gate 								llist++)
652*7c478bd9Sstevel@tonic-gate 					for (rlist = pfr->input_types;
653*7c478bd9Sstevel@tonic-gate 							rlist->name; rlist++)
654*7c478bd9Sstevel@tonic-gate 						if (_instantiate(pp, llist,
655*7c478bd9Sstevel@tonic-gate 								rlist, verify,
656*7c478bd9Sstevel@tonic-gate 								criteria)) {
657*7c478bd9Sstevel@tonic-gate 							pfl->outputp = llist;
658*7c478bd9Sstevel@tonic-gate 							pfr->inputp = rlist;
659*7c478bd9Sstevel@tonic-gate 							LEAVE(1);
660*7c478bd9Sstevel@tonic-gate 						}
661*7c478bd9Sstevel@tonic-gate 				pp->rhead = pfr->next;
662*7c478bd9Sstevel@tonic-gate 				if ((pp->ltail = prev_ltail))
663*7c478bd9Sstevel@tonic-gate 					pp->ltail->next = 0;
664*7c478bd9Sstevel@tonic-gate 				pp->lhead = prev_lhead;
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 			}
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 		}
669*7c478bd9Sstevel@tonic-gate 	}
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	LEAVE(0);
672*7c478bd9Sstevel@tonic-gate }
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate /*
675*7c478bd9Sstevel@tonic-gate  * check_pipeline() - CHECK THAT PIPELINE HANDLES MODES, PAGE-LIST
676*7c478bd9Sstevel@tonic-gate  */
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate static int
679*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
check_pipeline(_FILTER * pipeline,PARM * parms)680*7c478bd9Sstevel@tonic-gate check_pipeline(
681*7c478bd9Sstevel@tonic-gate 	_FILTER			*pipeline,
682*7c478bd9Sstevel@tonic-gate 	PARM			*parms
683*7c478bd9Sstevel@tonic-gate )
684*7c478bd9Sstevel@tonic-gate #else
685*7c478bd9Sstevel@tonic-gate check_pipeline(pipeline, parms)
686*7c478bd9Sstevel@tonic-gate 	_FILTER			*pipeline;
687*7c478bd9Sstevel@tonic-gate 	PARM			*parms;
688*7c478bd9Sstevel@tonic-gate #endif
689*7c478bd9Sstevel@tonic-gate {
690*7c478bd9Sstevel@tonic-gate 	register PARM		*pm;
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	register _FILTER	*pf;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	register TEMPLATE	*pt;
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	register int		fail;
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	for (fail = 0, pm = parms; !fail && pm->keyword; pm++) {
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 		if (!(pm->flags & X_MUST))
702*7c478bd9Sstevel@tonic-gate 			continue;
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 		for (pf = pipeline; pf; pf = pf->next) {
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 			if (!(pt = pf->templates))
707*7c478bd9Sstevel@tonic-gate 				continue;
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 			for (; pt->keyword; pt++)
710*7c478bd9Sstevel@tonic-gate 				if (STREQU(pt->keyword, pm->keyword) &&
711*7c478bd9Sstevel@tonic-gate 						pt->result && MATCH(pt, pm))
712*7c478bd9Sstevel@tonic-gate 					goto Okay;
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 		}
715*7c478bd9Sstevel@tonic-gate 		fail = 1;
716*7c478bd9Sstevel@tonic-gate 		continue;
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate Okay:;
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	}
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	return (fail? 0 : 1);
723*7c478bd9Sstevel@tonic-gate }
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate /*
726*7c478bd9Sstevel@tonic-gate  * build_filter() - CONSTRUCT PIPELINE FROM LINKED LIST OF FILTERS
727*7c478bd9Sstevel@tonic-gate  */
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
730*7c478bd9Sstevel@tonic-gate static size_t		build_simple_cmd(char **, _FILTER *, PARM *,
731*7c478bd9Sstevel@tonic-gate 							unsigned short *);
732*7c478bd9Sstevel@tonic-gate #else
733*7c478bd9Sstevel@tonic-gate static size_t		build_simple_cmd();
734*7c478bd9Sstevel@tonic-gate #endif
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate static char *
737*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
build_pipe(_FILTER * pipeline,PARM * parms,unsigned short * fp)738*7c478bd9Sstevel@tonic-gate build_pipe(
739*7c478bd9Sstevel@tonic-gate 	_FILTER			*pipeline,
740*7c478bd9Sstevel@tonic-gate 	PARM			*parms,
741*7c478bd9Sstevel@tonic-gate 	unsigned short		*fp
742*7c478bd9Sstevel@tonic-gate )
743*7c478bd9Sstevel@tonic-gate #else
744*7c478bd9Sstevel@tonic-gate build_pipe(pipeline, parms, fp)
745*7c478bd9Sstevel@tonic-gate 	_FILTER			*pipeline;
746*7c478bd9Sstevel@tonic-gate 	PARM			*parms;
747*7c478bd9Sstevel@tonic-gate 	unsigned short		*fp;
748*7c478bd9Sstevel@tonic-gate #endif
749*7c478bd9Sstevel@tonic-gate {
750*7c478bd9Sstevel@tonic-gate 	register _FILTER	*pf;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	register size_t		nchars;
753*7c478bd9Sstevel@tonic-gate 	register size_t		n;
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 	char			*p;	/* NOT register */
756*7c478bd9Sstevel@tonic-gate 	char			*ret;
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	/*
760*7c478bd9Sstevel@tonic-gate 	 * This is a two-pass routine. In the first pass we add
761*7c478bd9Sstevel@tonic-gate 	 * up how much space is needed for the pipeline, in the second
762*7c478bd9Sstevel@tonic-gate 	 * pass we allocate the space and construct the pipeline.
763*7c478bd9Sstevel@tonic-gate 	 */
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	for (nchars = 0, pf = pipeline; pf; pf = pf->next)
766*7c478bd9Sstevel@tonic-gate 		if ((n = build_simple_cmd((char **)0, pf, parms, fp)) > 0)
767*7c478bd9Sstevel@tonic-gate 			nchars += n + 1;   /* +1 for '|' or ending null */
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	if (!(ret = p = Malloc(nchars))) {
770*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
771*7c478bd9Sstevel@tonic-gate 		return (0);
772*7c478bd9Sstevel@tonic-gate 	}
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	for (pf = pipeline; pf; pf = pf->next, *p++ = (pf? '|' : 0))
775*7c478bd9Sstevel@tonic-gate 		(void) build_simple_cmd(&p, pf, parms, fp);
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	return (ret);
778*7c478bd9Sstevel@tonic-gate }
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate /*
781*7c478bd9Sstevel@tonic-gate  * build_simple_cmd()
782*7c478bd9Sstevel@tonic-gate  */
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate static size_t
785*7c478bd9Sstevel@tonic-gate #if	defined(__STDC__)
build_simple_cmd(char ** pp,_FILTER * pf,PARM * parms,unsigned short * flagsp)786*7c478bd9Sstevel@tonic-gate build_simple_cmd(
787*7c478bd9Sstevel@tonic-gate 	char			**pp,
788*7c478bd9Sstevel@tonic-gate 	_FILTER			*pf,
789*7c478bd9Sstevel@tonic-gate 	PARM			*parms,
790*7c478bd9Sstevel@tonic-gate 	unsigned short		*flagsp
791*7c478bd9Sstevel@tonic-gate )
792*7c478bd9Sstevel@tonic-gate #else
793*7c478bd9Sstevel@tonic-gate build_simple_cmd(pp, pf, parms, flagsp)
794*7c478bd9Sstevel@tonic-gate 	char			**pp;
795*7c478bd9Sstevel@tonic-gate 	_FILTER			*pf;
796*7c478bd9Sstevel@tonic-gate 	PARM			*parms;
797*7c478bd9Sstevel@tonic-gate 	unsigned short		*flagsp;
798*7c478bd9Sstevel@tonic-gate #endif
799*7c478bd9Sstevel@tonic-gate {
800*7c478bd9Sstevel@tonic-gate 	register size_t		ncount;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	register TEMPLATE	*pt;
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	register PARM		*pm;
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	if (pf->command) {
808*7c478bd9Sstevel@tonic-gate 		ncount = strlen(pf->command);
809*7c478bd9Sstevel@tonic-gate 		if (pp) {
810*7c478bd9Sstevel@tonic-gate 			strcpy (*pp, pf->command);
811*7c478bd9Sstevel@tonic-gate 			*pp += ncount;
812*7c478bd9Sstevel@tonic-gate 		}
813*7c478bd9Sstevel@tonic-gate 	} else
814*7c478bd9Sstevel@tonic-gate 		ncount = 0;
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	if (!pf->templates)
817*7c478bd9Sstevel@tonic-gate 		return (ncount);
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	for (pm = parms; pm->keyword; pm++) {
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 		if ((pm->flags & X_USED) || !*(pm->pvalue))
822*7c478bd9Sstevel@tonic-gate 			continue;
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 		for (pt = pf->templates; pt->keyword; pt++) {
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 			if (!STREQU(pt->keyword, pm->keyword) || !pt->result)
827*7c478bd9Sstevel@tonic-gate 				continue;
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 			/*
830*7c478bd9Sstevel@tonic-gate 			 * INPUT and OUTPUT are those for *this* filter,
831*7c478bd9Sstevel@tonic-gate 			 * not for the entire pipeline.
832*7c478bd9Sstevel@tonic-gate 			 */
833*7c478bd9Sstevel@tonic-gate 			if (STREQU(pt->keyword, PARM_INPUT))
834*7c478bd9Sstevel@tonic-gate 				pm->pvalue = &(pf->inputp->name);
835*7c478bd9Sstevel@tonic-gate 			else if (STREQU(pt->keyword, PARM_OUTPUT))
836*7c478bd9Sstevel@tonic-gate 				pm->pvalue = &(pf->outputp->name);
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 			if (MATCH(pt, pm)) {
839*7c478bd9Sstevel@tonic-gate 				if (pp)
840*7c478bd9Sstevel@tonic-gate 					*(*pp)++ = ' ';
841*7c478bd9Sstevel@tonic-gate 				ncount++;
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 				ncount += replace(pp, pt->result,
844*7c478bd9Sstevel@tonic-gate 						*(pm->pvalue), pt->nbra);
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 				/*
847*7c478bd9Sstevel@tonic-gate 				 * Difficulty here due to the two pass
848*7c478bd9Sstevel@tonic-gate 				 * nature of this code. The first pass
849*7c478bd9Sstevel@tonic-gate 				 * just counts the number of bytes; if
850*7c478bd9Sstevel@tonic-gate 				 * we mark the once-only parms as being
851*7c478bd9Sstevel@tonic-gate 				 * used, then we don't pick them up the
852*7c478bd9Sstevel@tonic-gate 				 * second time through. We could get
853*7c478bd9Sstevel@tonic-gate 				 * difficult and mark them temporarily,
854*7c478bd9Sstevel@tonic-gate 				 * but that's hard. So on the first pass
855*7c478bd9Sstevel@tonic-gate 				 * we don't mark the flags. The only
856*7c478bd9Sstevel@tonic-gate 				 * problem is an estimate too high.
857*7c478bd9Sstevel@tonic-gate 				 */
858*7c478bd9Sstevel@tonic-gate 				if (pp && pm->flags & X_FIRST)
859*7c478bd9Sstevel@tonic-gate 					pm->flags |= X_USED;
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 				*flagsp |= pm->flags;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 			}
864*7c478bd9Sstevel@tonic-gate 		}
865*7c478bd9Sstevel@tonic-gate 	}
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate 	return (ncount);
868*7c478bd9Sstevel@tonic-gate }
869