1 /*
2 * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
3 * All rights reserved.
4 */
5 /*
6 #pragma ident "%Z%%M% %I% %E% SMI"
7 * Copyright (c) 1994
8 * Open Software Foundation, Inc.
9 *
10 * Permission is hereby granted to use, copy, modify and freely distribute
11 * the software in this file and its documentation for any purpose without
12 * fee, provided that the above copyright notice appears in all copies and
13 * that both the copyright notice and this permission notice appear in
14 * supporting documentation. Further, provided that the name of Open
15 * Software Foundation, Inc. ("OSF") not be used in advertising or
16 * publicity pertaining to distribution of the software without prior
17 * written permission from OSF. OSF makes no representations about the
18 * suitability of this software for any purpose. It is provided "as is"
19 * without express or implied warranty.
20 */
21 /*
22 * Copyright (c) 1996 X Consortium
23 * Copyright (c) 1995, 1996 Dalrymple Consulting
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a copy
26 * of this software and associated documentation files (the "Software"), to deal
27 * in the Software without restriction, including without limitation the rights
28 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 * copies of the Software, and to permit persons to whom the Software is
30 * furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38 * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
39 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
40 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
41 * OTHER DEALINGS IN THE SOFTWARE.
42 *
43 * Except as contained in this notice, the names of the X Consortium and
44 * Dalrymple Consulting shall not be used in advertising or otherwise to
45 * promote the sale, use or other dealings in this Software without prior
46 * written authorization.
47 */
48 /* ________________________________________________________________________
49 *
50 * instant - a program to manipulate SGML instances.
51 *
52 * This module is for handling "special variables". These act a lot like
53 * procedure calls
54 * ________________________________________________________________________
55 */
56
57 #ifndef lint
58 static char *RCSid =
59 "$Header: /usr/src/docbook-to-man/Instant/RCS/tranvar.c,v 1.8 1998/06/28 18:53:40 fld Exp $";
60 #endif
61
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <ctype.h>
65 #include <string.h>
66 #include <memory.h>
67 #include <sys/types.h>
68 #include <errno.h>
69
70 #include <tptregexp.h>
71 #include "general.h"
72 #include "translate.h"
73
74 static char **idrefs; /* list of IDREF att names to follow */
75 static char *def_idrefs[] = { "LINKEND", "LINKENDS", "IDREF", 0 };
76 static char *each_A = 0; /* last seen _eachatt */
77 static char *each_C = 0; /* last seen _eachcon */
78
79 /* forward references */
80 void ChaseIDRefs(Element_t *, char *, char *, FILE *);
81 void Find(Element_t *, int, char **, FILE *);
82 void GetIDREFnames();
83
84 /* ______________________________________________________________________ */
85 /* Handle "special" variable - read file, run command, do action, etc.
86 * Arguments:
87 * Name of special variable to expand.
88 * Pointer to element under consideration.
89 * FILE pointer to where to write output.
90 * Flag saying whether to track the character position we're on
91 * (passed to OutputString).
92 */
93
94 void
ExpandSpecialVar(char * name,Element_t * e,FILE * fp,int track_pos)95 ExpandSpecialVar(
96 char *name,
97 Element_t *e,
98 FILE *fp,
99 int track_pos
100 )
101 {
102 FILE *infile;
103 char buf[LINESIZE], *cp, *cp2, *atval;
104 char **tok;
105 int ntok, n, i, actioni;
106 char *action, *action1;
107 Element_t *ep;
108 Trans_t *t, *tt;
109 Entity_t *entp;
110
111 /* Run a command.
112 * Format: _! command args ... */
113 if (*name == '!') {
114 name++;
115 if ((infile = popen(name, "r"))) {
116 while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
117 pclose(infile);
118 fflush(fp);
119 }
120 else {
121 fprintf(stderr, "Could not start program '%s': %s",
122 name, strerror(errno));
123 }
124 return;
125 }
126
127 /* See if caller wants one of the tokens from _eachatt or _eachcon.
128 * If so, output it and return. (Yes, I admit that this is a hack.)
129 */
130 if (*name == 'A' && name[1] == EOS && each_A) {
131 OutputString(each_A, fp, track_pos);
132 return;
133 }
134 if (*name == 'C' && name[1] == EOS && each_C) {
135 OutputString(each_C, fp, track_pos);
136 return;
137 }
138
139 ntok = 0;
140 tok = Split(name, &ntok, 0);
141
142 /* Include another file.
143 * Format: _include filename */
144 if (StrEq(tok[0], "include")) {
145 name = tok[1];
146 if (ntok > 1 ) {
147 if ((infile=OpenFile(name)) == NULL) {
148 sprintf(buf, "Can not open included file '%s'", name);
149 perror(buf);
150 return;
151 }
152 while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
153 fclose(infile);
154 }
155 else fprintf(stderr, "No file name specified for include\n");
156 return;
157 }
158
159 /* Print location (nearest title, line no, path).
160 * Format: _location */
161 else if (StrEq(tok[0], "location")) {
162 PrintLocation(e, fp);
163 }
164
165 /* Print path to this element.
166 * Format: _path */
167 else if (StrEq(tok[0], "path")) {
168 (void)FindElementPath(e, buf);
169 OutputString(buf, fp, track_pos);
170 }
171
172 /* Print name of this element (gi).
173 * Format: _gi [M|L|U] */
174 else if (StrEq(tok[0], "gi")) {
175 strcpy(buf, e->gi);
176 if (ntok >= 2) {
177 if (*tok[1] == 'L' || *tok[1] == 'l' ||
178 *tok[1] == 'M' || *tok[1] == 'm') {
179 for (cp=buf; *cp; cp++)
180 if (isupper(*cp)) *cp = tolower(*cp);
181 }
182 if (*tok[1] == 'M' || *tok[1] == 'm')
183 if (islower(buf[0])) buf[0] = toupper(buf[0]);
184 }
185 OutputString(buf, fp, track_pos);
186 }
187
188 /* Print filename of this element's associated external entity.
189 * Format: _filename */
190 else if (StrEq(tok[0], "filename")) {
191 if ( ntok >= 2 ) {
192 cp2 = FindAttValByName(e, tok[1]);
193 if ( ! (entp = FindEntity(cp2)) ) {
194 fprintf(stderr, "Can't find entity named %s (via _filename expression):\n", tok[1]);
195 PrintLocation(e, stderr);
196 return;
197 }
198 OutputString(entp->sysid, fp, track_pos);
199 } else {
200 if (!e->entity) {
201 fprintf(stderr, "Expected ext entity (element %s) - no ->entity (internal error? bug?):\n", e->gi);
202 PrintLocation(e, stderr);
203 return;
204 }
205 if (!e->entity->fname) {
206 fprintf(stderr, "Expected filename (element %s) - no ->entity->fname (internal error? bug?):\n", e->gi);
207 PrintLocation(e, stderr);
208 return;
209 }
210 OutputString(e->entity->sysid, fp, track_pos);
211 }
212 }
213
214 /* Value of parent's attribute, by attr name.
215 * Format: _pattr attname */
216 else if (StrEq(tok[0], "pattr")) {
217 ep = e->parent;
218 if (!ep) {
219 fprintf(stderr, "Element does not have a parent:\n");
220 PrintLocation(ep, stderr);
221 return;
222 }
223 if ((atval = FindAttValByName(ep, tok[1]))) {
224 OutputString(atval, fp, track_pos);
225 }
226 }
227
228 /* Use an action, given transpec's SID.
229 * Format: _action action */
230 else if (StrEq(tok[0], "action")) {
231 TranTByAction(e, tok[1], fp);
232 }
233
234 /* Number of child elements of this element.
235 * Format: _nchild */
236 else if (StrEq(tok[0], "nchild")) {
237 if (ntok > 1) {
238 for (n=0,i=0; i<e->necont; i++)
239 if (StrEq(e->econt[i]->gi, tok[1])) n++;
240 }
241 else n = e->necont;
242 sprintf(buf, "%d", n);
243 OutputString(buf, fp, track_pos);
244 }
245
246 /* number of 1st child's child elements (grandchildren from first child).
247 * Format: _n1gchild */
248 else if (StrEq(tok[0], "n1gchild")) {
249 if (e->necont) {
250 sprintf(buf, "%d", e->econt[0]->necont);
251 OutputString(buf, fp, track_pos);
252 }
253 }
254
255 /* Chase this element's pointers until we hit the named GI.
256 * Do the action if it matches.
257 * Format: _chasetogi gi action */
258 else if (StrEq(tok[0], "chasetogi")) {
259 if (ntok < 3) {
260 fprintf(stderr, "Error: Not enough args for _chasetogi.\n");
261 return;
262 }
263 actioni = atoi(tok[2]);
264 if (actioni) ChaseIDRefs(e, tok[1], tok[2], fp);
265 }
266
267 /* Follow link to element pointed to, then do action.
268 * Format: _followlink [attname] action. */
269 else if (StrEq(tok[0], "followlink")) {
270 char **s;
271 if (ntok > 2) {
272 if ((atval = FindAttValByName(e, tok[1]))) {
273 if ((ep = FindElemByID(atval))) {
274 TranTByAction(ep, tok[2], fp);
275 return;
276 }
277 }
278 else fprintf(stderr, "Error: Did not find attr: %s.\n", tok[1]);
279 return;
280 }
281 GetIDREFnames();
282 for (s=idrefs; *s; s++) {
283 /* is this IDREF attr set? */
284 if ((atval = FindAttValByName(e, *s))) {
285 ntok = 0;
286 tok = Split(atval, &ntok, S_STRDUP);
287 /* we'll follow the first one... */
288 if ((ep = FindElemByID(tok[0]))) {
289 TranTByAction(ep, tok[1], fp);
290 return;
291 }
292 else fprintf(stderr, "Error: Can not find elem for ID: %s.\n",
293 tok[0]);
294 }
295 }
296 fprintf(stderr, "Error: Element does not have IDREF attribute set:\n");
297 PrintLocation(e, stderr);
298 return;
299 }
300
301 /* Starting at this element, decend tree (in-order), finding GI.
302 * Do the action if it matches.
303 * Format: _find args ... */
304 else if (StrEq(tok[0], "find")) {
305 Find(e, ntok, tok, fp);
306 }
307
308 /* Starting at this element's parent, decend tree (in-order), finding GI.
309 * Do the action if it matches.
310 * Format: _pfind args ... */
311 else if (StrEq(tok[0], "pfind")) {
312 Find(e->parent ? e->parent : e, ntok, tok, fp);
313 }
314
315 /* Content is supposed to be a list of IDREFs. Follow each, doing action.
316 * If 2 actions are specified, use 1st for the 1st ID, 2nd for the rest.
317 * Format: _namelist action [action2] */
318 else if (StrEq(tok[0], "namelist")) {
319 int id;
320 action1 = tok[1];
321 if (ntok > 2) action = tok[2];
322 else action = action1;
323 for (i=0; i<e->ndcont; i++) {
324 n = 0;
325 tok = Split(e->dcont[i], &n, S_STRDUP);
326 for (id=0; id<n; id++) {
327 if (fold_case)
328 for (cp=tok[id]; *cp; cp++)
329 if (islower(*cp)) *cp = toupper(*cp);
330 if ((e = FindElemByID(tok[id]))) {
331 if (id) TranTByAction(e, action, fp);
332 else TranTByAction(e, action1, fp); /* first one */
333 }
334 else fprintf(stderr, "Error: Can not find ID: %s.\n", tok[id]);
335 }
336 }
337 }
338
339 /* For each word in the element's content, do action.
340 * Format: _eachcon action [action] */
341 else if (StrEq(tok[0], "eachcon")) {
342 int id;
343 action1 = tok[1];
344 if (ntok > 3) action = tok[2];
345 else action = action1;
346 for (i=0; i<e->ndcont; i++) {
347 n = 0;
348 tok = Split(e->dcont[i], &n, S_STRDUP|S_ALVEC);
349 for (id=0; id<n; id++) {
350 each_C = tok[id];
351 TranTByAction(e, action, fp);
352 }
353 free(*tok);
354 }
355 }
356 /* For each word in the given attribute's value, do action.
357 * Format: _eachatt attname action [action] */
358 else if (StrEq(tok[0], "eachatt")) {
359 int id;
360 action1 = tok[2];
361 if (ntok > 3) action = tok[3];
362 else action = action1;
363 if ((atval = FindAttValByName(e, tok[1]))) {
364 n = 0;
365 tok = Split(atval, &n, S_STRDUP|S_ALVEC);
366 for (id=0; id<n; id++) {
367 each_A = tok[id];
368 if (id) TranTByAction(e, action, fp);
369 else TranTByAction(e, action1, fp); /* first one */
370 }
371 free(*tok);
372 }
373 }
374
375 /* Do action on this element if element has [relationship] with gi.
376 * Format: _relation relationship gi action [action] */
377 else if (StrEq(tok[0], "relation")) {
378 if (ntok >= 4) {
379 if (!CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Current)) {
380 /* action not done, see if alt action specified */
381 if (ntok >= 5)
382 TranTByAction(e, tok[4], fp);
383 }
384 }
385 }
386
387 /* Do action on followed element if element has [relationship] with gi.
388 * Format: _followrel relationship gi action */
389 else if (StrEq(tok[0], "followrel")) {
390 if (ntok >= 4)
391 (void)CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Related);
392 }
393
394 /* Find element with matching ID and do action. If action not specified,
395 * choose the right one appropriate for its context.
396 * Format: _id id [action] */
397 else if (StrEq(tok[0], "id")) {
398 if ((ep = FindElemByID(tok[1]))) {
399 if (ntok > 2) TranTByAction(ep, tok[2], fp);
400 else {
401 t = FindTrans(ep, 0);
402 TransElement(ep, fp, t);
403 }
404 }
405 }
406
407 /* Set variable to value.
408 * Format: _set name value */
409 else if (StrEq(tok[0], "set")) {
410 SetMappingNV(Variables, tok[1], tok[2]);
411 }
412
413 /* Do action if variable is set, optionally to value.
414 * If not set, do nothing.
415 * Format: _isset varname [value] action
416 * Format: _issete varname [value] action -- expands value */
417 else if (StrEq(tok[0], "isset") || StrEq(tok[0], "issete")) {
418 if ((cp = FindMappingVal(Variables, tok[1]))) {
419 if (ntok == 3) TranTByAction(e, tok[2], fp);
420 else
421 if (ntok > 3) {
422 if ( StrEq(tok[0], "issete") ) {
423 ExpandVariables(tok[2], buf, e);
424 cp2 = buf;
425 } else
426 cp2 = tok[2];
427 if ( !strcmp(cp, cp2))
428 TranTByAction(e, tok[3], fp);
429 }
430 }
431 }
432
433 /* Insert a node into the tree at start/end, pointing to action to perform.
434 * Format: _insertnode S|E action */
435 else if (StrEq(tok[0], "insertnode")) {
436 actioni = atoi(tok[2]);
437 if (*tok[1] == 'S') e->gen_trans[0] = actioni;
438 else if (*tok[1] == 'E') e->gen_trans[1] = actioni;
439 }
440
441 /* Do an CALS DTD table spec for TeX or troff. Looks through attributes
442 * and determines what to output. "check" means to check consistency,
443 * and print error messages.
444 * This is (hopefully) the only hard-coded part of instant.
445 *
446 * This was originally written for the OSF DTDs and recoded by FLD for
447 * CALS tables (since no one will ever use the OSF tables). Although
448 * TeX was addressed first, it seems that a fresh approach was required,
449 * and so, tbl is the first to be really *fixed*. Once tbl is stable,
450 * and there is a need for TeX again, that part will be recoded.
451 *
452 * *Obsolete* form (viz, for TeX):
453 * Format: _calstable [clear|check|tex]
454 * [cellstart|cellend|rowstart|rowend|top|bottom]
455 *
456 * New, good form:
457 *
458 * Format: _calstable [tbl]
459 * [tablestart|tableend|tablegroup|tablefoot|rowstart|
460 * rowend|entrystart|entryend]
461 */
462
463 else if (StrEq(tok[0], "calstable")) {
464 CALStable(e, fp, tok, ntok);
465 }
466
467 /* Do action if element's attr is set, optionally to value.
468 * If not set, do nothing.
469 * Format: _attval att [value] action */
470 else if (StrEq(tok[0], "attval")) {
471 if ((atval = FindAttValByName(e, tok[1]))) {
472 if (ntok == 3) TranTByAction(e, tok[2], fp);
473 else if (ntok > 3 && !strcmp(atval, tok[2]))
474 TranTByAction(e, tok[3], fp);
475 }
476 }
477 /* Same thing, but look at parent */
478 else if (StrEq(tok[0], "pattval")) {
479 if ((atval = FindAttValByName(e->parent, tok[1]))) {
480 if (ntok == 3) {
481 TranTByAction(e, tok[2], fp);
482 }
483 if (ntok > 3 && !strcmp(atval, tok[2]))
484 TranTByAction(e, tok[3], fp);
485 }
486 }
487
488 /* Print each attribute and value for the current element, hopefully
489 * in a legal sgml form: <elem-name att1="value1" att2="value2:> .
490 * Format: _allatts */
491 else if (StrEq(tok[0], "allatts")) {
492 for (i=0; i<e->natts; i++) {
493 if (i != 0) putc(' ', fp);
494 fputs(e->atts[i].name, fp);
495 fputs("=\"", fp);
496 fputs(e->atts[i].sval, fp);
497 putc('"', fp);
498 }
499 }
500
501 /* Print the element's input filename, and optionally, the line number.
502 * Format: _infile [line] */
503 else if (StrEq(tok[0], "infile")) {
504 if (e->infile) {
505 if (ntok > 1 && !strcmp(tok[1], "root")) {
506 strcpy(buf, e->infile);
507 if ((cp = strrchr(buf, '.'))) *cp = EOS;
508 fputs(buf, fp);
509 }
510 else {
511 fputs(e->infile, fp);
512 if (ntok > 1 && !strcmp(tok[1], "line"))
513 fprintf(fp, " %d", e->lineno);
514 }
515 return;
516 }
517 else fputs("input-file??", fp);
518 }
519
520 /* Get value of an environement variable */
521 else if (StrEq(tok[0], "env")) {
522 if (ntok > 1 && (cp = getenv(tok[1]))) {
523 OutputString(cp, fp, track_pos);
524 }
525 }
526
527 /* Something unknown */
528 else {
529 fprintf(stderr, "Unknown special variable: %s\n", tok[0]);
530 tt = e->trans;
531 if (tt && tt->lineno)
532 fprintf(stderr, "Used in transpec, line %d\n", tt->lineno);
533 }
534 return;
535 }
536
537 /* ______________________________________________________________________ */
538 /* return the value for the special variables _A (last processed _eachatt)
539 * and _C (last processed _eachcon)
540 */
541
542 char *
Get_A_C_value(char * name)543 Get_A_C_value(char * name)
544 {
545 if ( !strcmp(name, "each_A") ) {
546 if ( each_A ) {
547 return each_A;
548 } else {
549 fprintf(stderr, "Requested value for unset _A variable\n");
550 }
551 } else
552 if ( !strcmp(name, "each_C") ) {
553 if ( each_C ) {
554 return each_C;
555 } else {
556 fprintf(stderr, "Requested value for unset _C variable\n");
557 }
558 } else {
559 fprintf(stderr, "Requested value for unknown special variable '%s'\n",
560 name);
561 }
562 return "";
563 }
564
565 /* ______________________________________________________________________ */
566 /* Chase IDs until we find an element whose GI matches. We also check
567 * child element names, not just the names of elements directly pointed
568 * at (by IDREF attributes).
569 */
570
571 void
GetIDREFnames()572 GetIDREFnames()
573 {
574 char *cp;
575
576 if (!idrefs) {
577 /* did user or transpec set the variable */
578 if ((cp = FindMappingVal(Variables, "link_atts")))
579 idrefs = Split(cp, 0, S_STRDUP|S_ALVEC);
580 else
581 idrefs = def_idrefs;
582 }
583 }
584
585 /* ______________________________________________________________________ */
586 /* Chase ID references - follow IDREF(s) attributes until we find
587 * a GI named 'gi', then perform given action on that GI.
588 * Arguments:
589 * Pointer to element under consideration.
590 * Name of GI we're looking for.
591 * Spec ID of action to take.
592 * FILE pointer to where to write output.
593 */
594 void
ChaseIDRefs(Element_t * e,char * gi,char * action,FILE * fp)595 ChaseIDRefs(
596 Element_t *e,
597 char *gi,
598 char * action,
599 FILE *fp
600 )
601 {
602 int ntok, i, ei;
603 char **tok, **s, *atval;
604
605 /* First, see if we got what we came for with this element */
606 if (StrEq(e->gi, gi)) {
607 TranTByAction(e, action, fp);
608 return;
609 }
610 GetIDREFnames();
611
612 /* loop for each attribute of type IDREF(s) */
613 for (s=idrefs; *s; s++) {
614 /* is this IDREF attr set? */
615 if ((atval = FindAttValByName(e, *s))) {
616 ntok = 0;
617 tok = Split(atval, &ntok, 0);
618 for (i=0; i<ntok; i++) {
619 /* get element pointed to */
620 if ((e = FindElemByID(tok[i]))) {
621 /* OK, we found a matching GI name */
622 if (StrEq(e->gi, gi)) {
623 /* process using named action */
624 TranTByAction(e, action, fp);
625 return;
626 }
627 else {
628 /* this elem itself did not match, try its children */
629 for (ei=0; ei<e->necont; ei++) {
630 if (StrEq(e->econt[ei]->gi, gi)) {
631 TranTByAction(e->econt[ei], action, fp);
632 return;
633 }
634 }
635 /* try this elem's IDREF attributes */
636 ChaseIDRefs(e, gi, action, fp);
637 return;
638 }
639 }
640 else {
641 /* should not happen, since parser checks ID/IDREFs */
642 fprintf(stderr, "Error: Could not find ID %s\n", atval);
643 }
644 }
645 }
646 }
647 /* if the pointers didn't lead to the GI, give error */
648 if (!s)
649 fprintf(stderr, "Error: Could not find '%s'\n", gi);
650 }
651
652 /* ______________________________________________________________________ */
653
654 /* state to pass to recursive routines - so we don't have to use
655 * global variables. */
656 typedef struct {
657 char *gi;
658 char *gi2;
659 char action[10];
660 Element_t *elem;
661 FILE *fp;
662 } Descent_t;
663
664 static void
tr_find_gi(Element_t * e,Descent_t * ds)665 tr_find_gi(
666 Element_t *e,
667 Descent_t *ds
668 )
669 {
670 if (StrEq(ds->gi, e->gi))
671 if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
672 }
673
674 static void
tr_find_gipar(Element_t * e,Descent_t * ds)675 tr_find_gipar(
676 Element_t *e,
677 Descent_t *ds
678 )
679 {
680 if (StrEq(ds->gi, e->gi) && e->parent &&
681 StrEq(ds->gi2, e->parent->gi))
682 if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
683 }
684
685 static void
tr_find_attr(Element_t * e,Descent_t * ds)686 tr_find_attr(
687 Element_t *e,
688 Descent_t *ds
689 )
690 {
691 char *atval;
692 if ((atval = FindAttValByName(e, ds->gi)) && StrEq(ds->gi2, atval))
693 TranTByAction(e, ds->action, ds->fp);
694 }
695
696 static void
tr_find_parent(Element_t * e,Descent_t * ds)697 tr_find_parent(
698 Element_t *e,
699 Descent_t *ds
700 )
701 {
702 if (QRelation(e, ds->gi, REL_Parent)) {
703 if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
704 }
705 }
706
707 /* ______________________________________________________________________ */
708 /* Descend tree, finding elements that match criteria, then perform
709 * given action.
710 * Arguments:
711 * Pointer to element under consideration.
712 * Number of tokens in special variable.
713 * Vector of tokens in special variable (eg, "find" "gi" "TITLE")
714 * FILE pointer to where to write output.
715 */
716 void
Find(Element_t * e,int ac,char ** av,FILE * fp)717 Find(
718 Element_t *e,
719 int ac,
720 char **av,
721 FILE *fp
722 )
723 {
724 Descent_t DS; /* state passed to recursive routine */
725
726 memset(&DS, 0, sizeof(Descent_t));
727 DS.elem = e;
728 DS.fp = fp;
729
730 /* see if we should start at the top of instance tree */
731 if (StrEq(av[1], "top")) {
732 av++;
733 ac--;
734 e = DocTree;
735 }
736 if (ac < 4) {
737 fprintf(stderr, "Bad '_find' specification - missing args.\n");
738 return;
739 }
740 /* Find elem whose GI is av[2] */
741 if (StrEq(av[1], "gi")) {
742 DS.gi = av[2];
743 strcpy(DS.action, av[3]);
744 DescendTree(e, tr_find_gi, 0, 0, &DS);
745 }
746 /* Find elem whose GI is av[2] and whose parent GI is av[3] */
747 else if (StrEq(av[1], "gi-parent")) {
748 DS.gi = av[2];
749 DS.gi2 = av[3];
750 strcpy(DS.action, av[4]);
751 DescendTree(e, tr_find_gipar, 0, 0, &DS);
752 }
753 /* Find elem whose parent GI is av[2] */
754 else if (StrEq(av[0], "parent")) {
755 DS.gi = av[2];
756 strcpy(DS.action, av[3]);
757 DescendTree(e, tr_find_parent, 0, 0, &DS);
758 }
759 /* Find elem whose attribute av[2] has value av[3] */
760 else if (StrEq(av[0], "attr")) {
761 DS.gi = av[2];
762 DS.gi2 = av[3];
763 strcpy(DS.action, av[4]);
764 DescendTree(e, tr_find_attr, 0, 0, &DS);
765 }
766 }
767
768 /* ______________________________________________________________________ */
769
770