2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: tranvar.c /main/2 1996/12/07 13:15:57 rws $ */
25 * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
26 * All rights reserved.
30 * Open Software Foundation, Inc.
32 * Permission is hereby granted to use, copy, modify and freely distribute
33 * the software in this file and its documentation for any purpose without
34 * fee, provided that the above copyright notice appears in all copies and
35 * that both the copyright notice and this permission notice appear in
36 * supporting documentation. Further, provided that the name of Open
37 * Software Foundation, Inc. ("OSF") not be used in advertising or
38 * publicity pertaining to distribution of the software without prior
39 * written permission from OSF. OSF makes no representations about the
40 * suitability of this software for any purpose. It is provided "as is"
41 * without express or implied warranty.
44 * Copyright (c) 1996 X Consortium
45 * Copyright (c) 1995, 1996 Dalrymple Consulting
47 * Permission is hereby granted, free of charge, to any person obtaining a copy
48 * of this software and associated documentation files (the "Software"), to deal
49 * in the Software without restriction, including without limitation the rights
50 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51 * copies of the Software, and to permit persons to whom the Software is
52 * furnished to do so, subject to the following conditions:
54 * The above copyright notice and this permission notice shall be included in
55 * all copies or substantial portions of the Software.
57 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60 * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
61 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
62 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
63 * OTHER DEALINGS IN THE SOFTWARE.
65 * Except as contained in this notice, the names of the X Consortium and
66 * Dalrymple Consulting shall not be used in advertising or otherwise to
67 * promote the sale, use or other dealings in this Software without prior
68 * written authorization.
70 /* ________________________________________________________________________
72 * instant - a program to manipulate SGML instances.
74 * This module is for handling "special variables". These act a lot like
76 * ________________________________________________________________________
84 #include <sys/types.h>
87 #include <tptregexp.h>
89 #include "translate.h"
91 static char **idrefs; /* list of IDREF att names to follow */
92 static char *def_idrefs[] = { "LINKEND", "LINKENDS", "IDREF", 0 };
93 static char *each_A = 0; /* last seen _eachatt */
94 static char *each_C = 0; /* last seen _eachcon */
96 /* forward references */
97 void ChaseIDRefs(Element_t *, char *, char *, FILE *);
98 void Find(Element_t *, int, char **, FILE *);
101 /* ______________________________________________________________________ */
102 /* Handle "special" variable - read file, run command, do action, etc.
104 * Name of special variable to expand.
105 * Pointer to element under consideration.
106 * FILE pointer to where to write output.
107 * Flag saying whether to track the character position we're on
108 * (passed to OutputString).
120 char buf[LINESIZE], *cp, *cp2, *atval;
122 int ntok, n, i, actioni;
123 char *action, *action1;
128 * Format: _! command args ... */
131 if ((infile = popen(name, "r"))) {
132 while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
137 fprintf(stderr, "Could not start program '%s': %s",
138 name, strerror(errno));
143 /* See if caller wants one of the tokens from _eachatt or _eachcon.
144 * If so, output it and return. (Yes, I admit that this is a hack.)
146 if (*name == 'A' && name[1] == EOS && each_A) {
147 OutputString(each_A, fp, track_pos);
150 if (*name == 'C' && name[1] == EOS && each_C) {
151 OutputString(each_C, fp, track_pos);
156 tok = Split(name, &ntok, 0);
158 /* Include another file.
159 * Format: _include filename */
160 if (StrEq(tok[0], "include")) {
163 if ((infile=OpenFile(name)) == NULL) {
164 sprintf(buf, "Can not open included file '%s'", name);
168 while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
171 else fprintf(stderr, "No file name specified for include\n");
175 /* Print location (nearest title, line no, path).
176 * Format: _location */
177 else if (StrEq(tok[0], "location")) {
178 PrintLocation(e, fp);
181 /* Print path to this element.
183 else if (StrEq(tok[0], "path")) {
184 (void)FindElementPath(e, buf);
185 OutputString(buf, fp, track_pos);
188 /* Print name of this element (gi).
189 * Format: _gi [M|L|U] */
190 else if (StrEq(tok[0], "gi")) {
193 if (*tok[1] == 'L' || *tok[1] == 'l' ||
194 *tok[1] == 'M' || *tok[1] == 'm') {
195 for (cp=buf; *cp; cp++)
196 if (isupper(*cp)) *cp = tolower(*cp);
198 if (*tok[1] == 'M' || *tok[1] == 'm')
199 if (islower(buf[0])) buf[0] = toupper(buf[0]);
201 OutputString(buf, fp, track_pos);
204 /* Print filename of this element's associated external entity.
205 * Format: _filename */
206 else if (StrEq(tok[0], "filename")) {
208 fprintf(stderr, "Expected ext entity (internal error? bug?):\n");
209 PrintLocation(e, stderr);
212 if (!e->entity->fname) {
213 fprintf(stderr, "Expected filename (internal error? bug?):\n");
214 PrintLocation(e, stderr);
217 OutputString(e->entity->fname, fp, track_pos);
220 /* Value of parent's attribute, by attr name.
221 * Format: _pattr attname */
222 else if (StrEq(tok[0], "pattr")) {
225 fprintf(stderr, "Element does not have a parent:\n");
226 PrintLocation(ep, stderr);
229 if ((atval = FindAttValByName(ep, tok[1]))) {
230 OutputString(atval, fp, track_pos);
234 /* Use an action, given transpec's SID.
235 * Format: _action action */
236 else if (StrEq(tok[0], "action")) {
237 TranTByAction(e, tok[1], fp);
240 /* Number of child elements of this element.
242 else if (StrEq(tok[0], "nchild")) {
244 for (n=0,i=0; i<e->necont; i++)
245 if (StrEq(e->econt[i]->gi, tok[1])) n++;
248 sprintf(buf, "%d", n);
249 OutputString(buf, fp, track_pos);
252 /* number of 1st child's child elements (grandchildren from first child).
253 * Format: _n1gchild */
254 else if (StrEq(tok[0], "n1gchild")) {
256 sprintf(buf, "%d", e->econt[0]->necont);
257 OutputString(buf, fp, track_pos);
261 /* Chase this element's pointers until we hit the named GI.
262 * Do the action if it matches.
263 * Format: _chasetogi gi action */
264 else if (StrEq(tok[0], "chasetogi")) {
266 fprintf(stderr, "Error: Not enough args for _chasetogi.\n");
269 actioni = atoi(tok[2]);
270 if (actioni) ChaseIDRefs(e, tok[1], tok[2], fp);
273 /* Follow link to element pointed to, then do action.
274 * Format: _followlink [attname] action. */
275 else if (StrEq(tok[0], "followlink")) {
278 if ((atval = FindAttValByName(e, tok[1]))) {
279 if ((ep = FindElemByID(atval))) {
280 TranTByAction(ep, tok[2], fp);
284 else fprintf(stderr, "Error: Did not find attr: %s.\n", tok[1]);
288 for (s=idrefs; *s; s++) {
289 /* is this IDREF attr set? */
290 if ((atval = FindAttValByName(e, *s))) {
292 tok = Split(atval, &ntok, S_STRDUP);
293 /* we'll follow the first one... */
294 if ((ep = FindElemByID(tok[0]))) {
295 TranTByAction(ep, tok[1], fp);
298 else fprintf(stderr, "Error: Can not find elem for ID: %s.\n",
302 fprintf(stderr, "Error: Element does not have IDREF attribute set:\n");
303 PrintLocation(e, stderr);
307 /* Starting at this element, decend tree (in-order), finding GI.
308 * Do the action if it matches.
309 * Format: _find args ... */
310 else if (StrEq(tok[0], "find")) {
311 Find(e, ntok, tok, fp);
314 /* Starting at this element's parent, decend tree (in-order), finding GI.
315 * Do the action if it matches.
316 * Format: _pfind args ... */
317 else if (StrEq(tok[0], "pfind")) {
318 Find(e->parent ? e->parent : e, ntok, tok, fp);
321 /* Content is supposed to be a list of IDREFs. Follow each, doing action.
322 * If 2 actions are specified, use 1st for the 1st ID, 2nd for the rest.
323 * Format: _namelist action [action2] */
324 else if (StrEq(tok[0], "namelist")) {
327 if (ntok > 2) action = tok[2];
328 else action = action1;
329 for (i=0; i<e->ndcont; i++) {
331 tok = Split(e->dcont[i], &n, S_STRDUP);
332 for (id=0; id<n; id++) {
334 for (cp=tok[id]; *cp; cp++)
335 if (islower(*cp)) *cp = toupper(*cp);
336 if ((e = FindElemByID(tok[id]))) {
337 if (id) TranTByAction(e, action, fp);
338 else TranTByAction(e, action1, fp); /* first one */
340 else fprintf(stderr, "Error: Can not find ID: %s.\n", tok[id]);
345 /* For each word in the element's content, do action.
346 * Format: _eachcon action [action] */
347 else if (StrEq(tok[0], "eachcon")) {
350 if (ntok > 3) action = tok[2];
351 else action = action1;
352 for (i=0; i<e->ndcont; i++) {
354 tok = Split(e->dcont[i], &n, S_STRDUP|S_ALVEC);
355 for (id=0; id<n; id++) {
357 TranTByAction(e, action, fp);
362 /* For each word in the given attribute's value, do action.
363 * Format: _eachatt attname action [action] */
364 else if (StrEq(tok[0], "eachatt")) {
367 if (ntok > 3) action = tok[3];
368 else action = action1;
369 if ((atval = FindAttValByName(e, tok[1]))) {
371 tok = Split(atval, &n, S_STRDUP|S_ALVEC);
372 for (id=0; id<n; id++) {
374 if (id) TranTByAction(e, action, fp);
375 else TranTByAction(e, action1, fp); /* first one */
381 /* Do action on this element if element has [relationship] with gi.
382 * Format: _relation relationship gi action [action] */
383 else if (StrEq(tok[0], "relation")) {
385 if (!CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Current)) {
386 /* action not done, see if alt action specified */
388 TranTByAction(e, tok[4], fp);
393 /* Do action on followed element if element has [relationship] with gi.
394 * Format: _followrel relationship gi action */
395 else if (StrEq(tok[0], "followrel")) {
397 (void)CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Related);
400 /* Find element with matching ID and do action. If action not specified,
401 * choose the right one appropriate for its context.
402 * Format: _id id [action] */
403 else if (StrEq(tok[0], "id")) {
404 if ((ep = FindElemByID(tok[1]))) {
405 if (ntok > 2) TranTByAction(ep, tok[2], fp);
407 t = FindTrans(ep, 0);
408 TransElement(ep, fp, t);
413 /* Set variable to value.
414 * Format: _set name value */
415 else if (StrEq(tok[0], "set")) {
416 SetMappingNV(Variables, tok[1], tok[2]);
419 /* Do action if variable is set, optionally to value.
420 * If not set, do nothing.
421 * Format: _isset varname [value] action
422 * Format: _issete varname [value] action -- expands value */
423 else if (StrEq(tok[0], "isset") || StrEq(tok[0], "issete")) {
424 if ((cp = FindMappingVal(Variables, tok[1]))) {
425 if (ntok == 3) TranTByAction(e, tok[2], fp);
428 if ( StrEq(tok[0], "issete") ) {
429 ExpandVariables(tok[2], buf, e);
433 if ( !strcmp(cp, cp2))
434 TranTByAction(e, tok[3], fp);
439 /* Insert a node into the tree at start/end, pointing to action to perform.
440 * Format: _insertnode S|E action */
441 else if (StrEq(tok[0], "insertnode")) {
442 actioni = atoi(tok[2]);
443 if (*tok[1] == 'S') e->gen_trans[0] = actioni;
444 else if (*tok[1] == 'E') e->gen_trans[1] = actioni;
447 /* Do an CALS DTD table spec for TeX or troff. Looks through attributes
448 * and determines what to output. "check" means to check consistency,
449 * and print error messages.
450 * This is (hopefully) the only hard-coded part of instant.
452 * This was originally written for the OSF DTDs and recoded by FLD for
453 * CALS tables (since no one will ever use the OSF tables). Although
454 * TeX was addressed first, it seems that a fresh approach was required,
455 * and so, tbl is the first to be really *fixed*. Once tbl is stable,
456 * and there is a need for TeX again, that part will be recoded.
458 * *Obsolete* form (viz, for TeX):
459 * Format: _calstable [clear|check|tex]
460 * [cellstart|cellend|rowstart|rowend|top|bottom]
464 * Format: _calstable [tbl]
465 * [tablestart|tableend|tablegroup|tablefoot|rowstart|
466 * rowend|entrystart|entryend]
469 else if (StrEq(tok[0], "calstable")) {
470 CALStable(e, fp, tok, ntok);
473 /* Do action if element's attr is set, optionally to value.
474 * If not set, do nothing.
475 * Format: _attval att [value] action */
476 else if (StrEq(tok[0], "attval")) {
477 if ((atval = FindAttValByName(e, tok[1]))) {
478 if (ntok == 3) TranTByAction(e, tok[2], fp);
479 else if (ntok > 3 && !strcmp(atval, tok[2]))
480 TranTByAction(e, tok[3], fp);
483 /* Same thing, but look at parent */
484 else if (StrEq(tok[0], "pattval")) {
485 if ((atval = FindAttValByName(e->parent, tok[1]))) {
487 TranTByAction(e, tok[2], fp);
489 if (ntok > 3 && !strcmp(atval, tok[2]))
490 TranTByAction(e, tok[3], fp);
494 /* Print each attribute and value for the current element, hopefully
495 * in a legal sgml form: <elem-name att1="value1" att2="value2:> .
496 * Format: _allatts */
497 else if (StrEq(tok[0], "allatts")) {
498 for (i=0; i<e->natts; i++) {
499 if (i != 0) putc(' ', fp);
500 fputs(e->atts[i].name, fp);
502 fputs(e->atts[i].sval, fp);
507 /* Print the element's input filename, and optionally, the line number.
508 * Format: _infile [line] */
509 else if (StrEq(tok[0], "infile")) {
511 if (ntok > 1 && !strcmp(tok[1], "root")) {
512 strcpy(buf, e->infile);
513 if ((cp = strrchr(buf, '.'))) *cp = EOS;
517 fputs(e->infile, fp);
518 if (ntok > 1 && !strcmp(tok[1], "line"))
519 fprintf(fp, " %d", e->lineno);
523 else fputs("input-file??", fp);
526 /* Get value of an environement variable */
527 else if (StrEq(tok[0], "env")) {
528 if (ntok > 1 && (cp = getenv(tok[1]))) {
529 OutputString(cp, fp, track_pos);
533 /* Something unknown */
535 fprintf(stderr, "Unknown special variable: %s\n", tok[0]);
537 if (tt && tt->lineno)
538 fprintf(stderr, "Used in transpec, line %d\n", tt->lineno);
543 /* ______________________________________________________________________ */
544 /* return the value for the special variables _A (last processed _eachatt)
545 * and _C (last processed _eachcon)
549 Get_A_C_value(char * name)
551 if ( !strcmp(name, "each_A") ) {
555 fprintf(stderr, "Requested value for unset _A variable\n");
558 if ( !strcmp(name, "each_C") ) {
562 fprintf(stderr, "Requested value for unset _C variable\n");
565 fprintf(stderr, "Requested value for unknown special variable '%s'\n",
571 /* ______________________________________________________________________ */
572 /* Chase IDs until we find an element whose GI matches. We also check
573 * child element names, not just the names of elements directly pointed
574 * at (by IDREF attributes).
583 /* did user or transpec set the variable */
584 if ((cp = FindMappingVal(Variables, "link_atts")))
585 idrefs = Split(cp, 0, S_STRDUP|S_ALVEC);
591 /* ______________________________________________________________________ */
592 /* Chase ID references - follow IDREF(s) attributes until we find
593 * a GI named 'gi', then perform given action on that GI.
595 * Pointer to element under consideration.
596 * Name of GI we're looking for.
597 * Spec ID of action to take.
598 * FILE pointer to where to write output.
609 char **tok, **s, *atval;
611 /* First, see if we got what we came for with this element */
612 if (StrEq(e->gi, gi)) {
613 TranTByAction(e, action, fp);
618 /* loop for each attribute of type IDREF(s) */
619 for (s=idrefs; *s; s++) {
620 /* is this IDREF attr set? */
621 if ((atval = FindAttValByName(e, *s))) {
623 tok = Split(atval, &ntok, 0);
624 for (i=0; i<ntok; i++) {
625 /* get element pointed to */
626 if ((e = FindElemByID(tok[i]))) {
627 /* OK, we found a matching GI name */
628 if (StrEq(e->gi, gi)) {
629 /* process using named action */
630 TranTByAction(e, action, fp);
634 /* this elem itself did not match, try its children */
635 for (ei=0; ei<e->necont; ei++) {
636 if (StrEq(e->econt[ei]->gi, gi)) {
637 TranTByAction(e->econt[ei], action, fp);
641 /* try this elem's IDREF attributes */
642 ChaseIDRefs(e, gi, action, fp);
647 /* should not happen, since parser checks ID/IDREFs */
648 fprintf(stderr, "Error: Could not find ID %s\n", atval);
654 /* if the pointers didn't lead to the GI, give error */
656 fprintf(stderr, "Error: Could not find '%s'\n", gi);
659 /* ______________________________________________________________________ */
661 /* state to pass to recursive routines - so we don't have to use
662 * global variables. */
677 if (StrEq(ds->gi, e->gi))
678 if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
687 if (StrEq(ds->gi, e->gi) && e->parent &&
688 StrEq(ds->gi2, e->parent->gi))
689 if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
699 if ((atval = FindAttValByName(e, ds->gi)) && StrEq(ds->gi2, atval))
700 TranTByAction(e, ds->action, ds->fp);
709 if (QRelation(e, ds->gi, REL_Parent)) {
710 if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
714 /* ______________________________________________________________________ */
715 /* Descend tree, finding elements that match criteria, then perform
718 * Pointer to element under consideration.
719 * Number of tokens in special variable.
720 * Vector of tokens in special variable (eg, "find" "gi" "TITLE")
721 * FILE pointer to where to write output.
731 Descent_t DS; /* state passed to recursive routine */
733 memset(&DS, 0, sizeof(Descent_t));
737 /* see if we should start at the top of instance tree */
738 if (StrEq(av[1], "top")) {
744 fprintf(stderr, "Bad '_find' specification - missing args.\n");
747 /* Find elem whose GI is av[2] */
748 if (StrEq(av[1], "gi")) {
750 strcpy(DS.action, av[3]);
751 DescendTree(e, tr_find_gi, 0, 0, &DS);
753 /* Find elem whose GI is av[2] and whose parent GI is av[3] */
754 else if (StrEq(av[1], "gi-parent")) {
757 strcpy(DS.action, av[4]);
758 DescendTree(e, tr_find_gipar, 0, 0, &DS);
760 /* Find elem whose parent GI is av[2] */
761 else if (StrEq(av[0], "parent")) {
763 strcpy(DS.action, av[3]);
764 DescendTree(e, tr_find_parent, 0, 0, &DS);
766 /* Find elem whose attribute av[2] has value av[3] */
767 else if (StrEq(av[0], "attr")) {
770 strcpy(DS.action, av[4]);
771 DescendTree(e, tr_find_attr, 0, 0, &DS);
775 /* ______________________________________________________________________ */