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