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
49 typedef 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
61 static 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
71 static int searchlist_t(TYPE *, TYPE *);
72 static int instantiate(_FILTER **, TYPE *, TYPE *,
73 int (*)(), void *);
74 static int check_pipeline(_FILTER *, PARM *);
75 static char *build_pipe(_FILTER *, PARM *, unsigned short *);
76 #else
77
78 static int searchlist_t();
79 static int instantiate();
80 static int check_pipeline();
81 static char *build_pipe();
82
83 #endif
84
85 /*
86 * Table of recognized keywords, with info. about them.
87 */
88
89 #define NFIXED 4
90
91 static PARM parmtable[] = {
92
93 /* These must be the first NFIXED, and in this order */
94 PARM_INPUT, X_FIXED, &S.input_type.name,
95 PARM_OUTPUT, X_FIXED, &S.output_type.name,
96 PARM_TERM, X_FIXED, &S.printer_type.name,
97 PARM_PRINTER, X_FIXED, &S.printer,
98
99 PARM_CPI, FPARM_CPI, 0,
100 PARM_LPI, FPARM_LPI, 0,
101 PARM_LENGTH, FPARM_LENGTH, 0,
102 PARM_WIDTH, FPARM_WIDTH, 0,
103 PARM_PAGES, FPARM_PAGES | X_FIRST | X_MUST, 0,
104 PARM_CHARSET, FPARM_CHARSET, 0,
105 PARM_FORM, FPARM_FORM, 0,
106 PARM_COPIES, FPARM_COPIES | X_FIRST, 0,
107 PARM_MODES, FPARM_MODES | X_MANY | X_MUST, 0,
108 0, 0, 0,
109 };
110
111 /*
112 * insfilter()
113 */
114
115 FILTERTYPE
116 #if defined(__STDC__)
insfilter(char ** pipes,char * input_type,char * output_type,char * printer_type,char * printer,char ** parms,unsigned short * flagsp)117 insfilter(
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
127 insfilter(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
318 Return: Free((char *)S.parms);
319
320 return (ret);
321 }
322
323 /*
324 * searchlist_t() - SEARCH (TYPE *) LIST FOR ITEM
325 */
326
327 static int
328 #if defined(__STDC__)
typematch(TYPE * type1,TYPE * type2)329 typematch(
330 TYPE *type1,
331 TYPE *type2
332 )
333 #else
334 typematch(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
347 static int
348 #if defined(__STDC__)
searchlist_t(TYPE * itemp,TYPE * list)349 searchlist_t(
350 TYPE *itemp,
351 TYPE *list
352 )
353 #else
354 searchlist_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 */
429 typedef struct PIPELIST {
430 _FILTER * lhead;
431 _FILTER * ltail;
432 _FILTER * rhead;
433 } PIPELIST;
434
435 #if defined(__STDC__)
436 static int _instantiate(PIPELIST *, TYPE *, TYPE *,
437 int (*)(_FILTER *, void *), void *);
438 #else
439 static int _instantiate();
440 #endif
441
442 static int peg;
443
444 static int
445 #if defined(__STDC__)
instantiate(_FILTER ** pline,TYPE * input,TYPE * output,int (* verify)(_FILTER *,void *),void * criteria)446 instantiate(
447 _FILTER **pline,
448 TYPE *input,
449 TYPE *output,
450 int (*verify)(_FILTER *, void *),
451 void *criteria
452 )
453 #else
454 instantiate(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
491 static int
492 #if defined(__STDC__)
_instantiate(PIPELIST * pp,TYPE * inputp,TYPE * outputp,int (* verify)(_FILTER *,void *),void * criteria)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
679 static int
680 #if defined(__STDC__)
check_pipeline(_FILTER * pipeline,PARM * parms)681 check_pipeline(
682 _FILTER *pipeline,
683 PARM *parms
684 )
685 #else
686 check_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
719 Okay:;
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__)
731 static size_t build_simple_cmd(char **, _FILTER *, PARM *,
732 unsigned short *);
733 #else
734 static size_t build_simple_cmd();
735 #endif
736
737 static char *
738 #if defined(__STDC__)
build_pipe(_FILTER * pipeline,PARM * parms,unsigned short * fp)739 build_pipe(
740 _FILTER *pipeline,
741 PARM *parms,
742 unsigned short *fp
743 )
744 #else
745 build_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
785 static size_t
786 #if defined(__STDC__)
build_simple_cmd(char ** pp,_FILTER * pf,PARM * parms,unsigned short * flagsp)787 build_simple_cmd(
788 char **pp,
789 _FILTER *pf,
790 PARM *parms,
791 unsigned short *flagsp
792 )
793 #else
794 build_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