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