1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
3*0Sstevel@tonic-gate * All rights reserved.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate /*
6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
7*0Sstevel@tonic-gate * Copyright (c) 1994
8*0Sstevel@tonic-gate * Open Software Foundation, Inc.
9*0Sstevel@tonic-gate *
10*0Sstevel@tonic-gate * Permission is hereby granted to use, copy, modify and freely distribute
11*0Sstevel@tonic-gate * the software in this file and its documentation for any purpose without
12*0Sstevel@tonic-gate * fee, provided that the above copyright notice appears in all copies and
13*0Sstevel@tonic-gate * that both the copyright notice and this permission notice appear in
14*0Sstevel@tonic-gate * supporting documentation. Further, provided that the name of Open
15*0Sstevel@tonic-gate * Software Foundation, Inc. ("OSF") not be used in advertising or
16*0Sstevel@tonic-gate * publicity pertaining to distribution of the software without prior
17*0Sstevel@tonic-gate * written permission from OSF. OSF makes no representations about the
18*0Sstevel@tonic-gate * suitability of this software for any purpose. It is provided "as is"
19*0Sstevel@tonic-gate * without express or implied warranty.
20*0Sstevel@tonic-gate */
21*0Sstevel@tonic-gate /*
22*0Sstevel@tonic-gate * Copyright (c) 1996 X Consortium
23*0Sstevel@tonic-gate * Copyright (c) 1995, 1996 Dalrymple Consulting
24*0Sstevel@tonic-gate *
25*0Sstevel@tonic-gate * Permission is hereby granted, free of charge, to any person obtaining a copy
26*0Sstevel@tonic-gate * of this software and associated documentation files (the "Software"), to deal
27*0Sstevel@tonic-gate * in the Software without restriction, including without limitation the rights
28*0Sstevel@tonic-gate * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29*0Sstevel@tonic-gate * copies of the Software, and to permit persons to whom the Software is
30*0Sstevel@tonic-gate * furnished to do so, subject to the following conditions:
31*0Sstevel@tonic-gate *
32*0Sstevel@tonic-gate * The above copyright notice and this permission notice shall be included in
33*0Sstevel@tonic-gate * all copies or substantial portions of the Software.
34*0Sstevel@tonic-gate *
35*0Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36*0Sstevel@tonic-gate * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37*0Sstevel@tonic-gate * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38*0Sstevel@tonic-gate * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
39*0Sstevel@tonic-gate * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
40*0Sstevel@tonic-gate * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
41*0Sstevel@tonic-gate * OTHER DEALINGS IN THE SOFTWARE.
42*0Sstevel@tonic-gate *
43*0Sstevel@tonic-gate * Except as contained in this notice, the names of the X Consortium and
44*0Sstevel@tonic-gate * Dalrymple Consulting shall not be used in advertising or otherwise to
45*0Sstevel@tonic-gate * promote the sale, use or other dealings in this Software without prior
46*0Sstevel@tonic-gate * written authorization.
47*0Sstevel@tonic-gate */
48*0Sstevel@tonic-gate /* ________________________________________________________________________
49*0Sstevel@tonic-gate *
50*0Sstevel@tonic-gate * Program to manipulate SGML instances.
51*0Sstevel@tonic-gate *
52*0Sstevel@tonic-gate * This module is for "translating" an instance to another form, usually
53*0Sstevel@tonic-gate * suitable for a formatting application.
54*0Sstevel@tonic-gate *
55*0Sstevel@tonic-gate * Entry points for this module:
56*0Sstevel@tonic-gate * DoTranslate(elem, transfile, mapfile, fp)
57*0Sstevel@tonic-gate * ________________________________________________________________________
58*0Sstevel@tonic-gate */
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate #ifndef lint
61*0Sstevel@tonic-gate static char *RCSid =
62*0Sstevel@tonic-gate "$Header: /usr/src/docbook-to-man/Instant/RCS/translate.c,v 1.16 1998/06/29 04:13:40 fld Exp $";
63*0Sstevel@tonic-gate #endif
64*0Sstevel@tonic-gate
65*0Sstevel@tonic-gate #include <stdio.h>
66*0Sstevel@tonic-gate #include <stdlib.h>
67*0Sstevel@tonic-gate #include <ctype.h>
68*0Sstevel@tonic-gate #include <string.h>
69*0Sstevel@tonic-gate #include <memory.h>
70*0Sstevel@tonic-gate #include <sys/types.h>
71*0Sstevel@tonic-gate #include <errno.h>
72*0Sstevel@tonic-gate
73*0Sstevel@tonic-gate #include <tptregexp.h>
74*0Sstevel@tonic-gate #include "general.h"
75*0Sstevel@tonic-gate #define STORAGE
76*0Sstevel@tonic-gate #include "translate.h"
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gate static Trans_t NullTrans; /* an empty one */
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate /* stack for nested Transpecs */
81*0Sstevel@tonic-gate
82*0Sstevel@tonic-gate #define MAXTRANSPECDEPTH 500 /* max depth of transpec nesting */
83*0Sstevel@tonic-gate
84*0Sstevel@tonic-gate static Trans_t *tsStack[MAXTRANSPECDEPTH];
85*0Sstevel@tonic-gate static int tsStacki = -1; /* index into used stack */
86*0Sstevel@tonic-gate
87*0Sstevel@tonic-gate /* forward references */
88*0Sstevel@tonic-gate void ProcesOutputSpec(char *, Element_t *, FILE *, int);
89*0Sstevel@tonic-gate static void WasProcessed(Element_t *);
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gate /* ______________________________________________________________________ */
92*0Sstevel@tonic-gate /* Translate the subtree starting at 'e'. Use 'transfile' for translation
93*0Sstevel@tonic-gate * specs. Output goes to 'fp'. This is the entry point for translating
94*0Sstevel@tonic-gate * an instance.
95*0Sstevel@tonic-gate * Assumes you've read SDATA and CharMap files (optionally).
96*0Sstevel@tonic-gate * Arguments:
97*0Sstevel@tonic-gate * Pointer to element under consideration.
98*0Sstevel@tonic-gate * Pointer to name of translation spec file.
99*0Sstevel@tonic-gate * FILE pointer to where to write output.
100*0Sstevel@tonic-gate */
101*0Sstevel@tonic-gate
102*0Sstevel@tonic-gate void
DoTranslate(Element_t * e,char * transfile,FILE * fp)103*0Sstevel@tonic-gate DoTranslate(
104*0Sstevel@tonic-gate Element_t *e,
105*0Sstevel@tonic-gate char *transfile,
106*0Sstevel@tonic-gate FILE *fp
107*0Sstevel@tonic-gate )
108*0Sstevel@tonic-gate {
109*0Sstevel@tonic-gate Trans_t *t, *tn;
110*0Sstevel@tonic-gate
111*0Sstevel@tonic-gate if (!transfile) {
112*0Sstevel@tonic-gate fprintf(stderr,
113*0Sstevel@tonic-gate "Translation spec file not specified. Skipping translation.\n");
114*0Sstevel@tonic-gate return;
115*0Sstevel@tonic-gate }
116*0Sstevel@tonic-gate ReadTransSpec(transfile);
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gate /* Find transpec for each node. */
119*0Sstevel@tonic-gate DescendTree(e, PrepTranspecs, 0, 0, 0);
120*0Sstevel@tonic-gate
121*0Sstevel@tonic-gate /* Stuff to do at start of processing */
122*0Sstevel@tonic-gate if ((t = FindTransByName("_Start"))) {
123*0Sstevel@tonic-gate if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
124*0Sstevel@tonic-gate if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
125*0Sstevel@tonic-gate if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
126*0Sstevel@tonic-gate if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
127*0Sstevel@tonic-gate }
128*0Sstevel@tonic-gate
129*0Sstevel@tonic-gate /* Translate topmost/first element. This is recursive. */
130*0Sstevel@tonic-gate TransElement(e, fp, NULL);
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate /* Stuff to do at end of processing */
133*0Sstevel@tonic-gate if ((t = FindTransByName("_End"))) {
134*0Sstevel@tonic-gate if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
135*0Sstevel@tonic-gate if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
136*0Sstevel@tonic-gate if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
137*0Sstevel@tonic-gate if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate
140*0Sstevel@tonic-gate /* Warn about unprocessed elements in this doc tree, if verbose mode. */
141*0Sstevel@tonic-gate if (verbose)
142*0Sstevel@tonic-gate DescendTree(e, WasProcessed, 0, 0, 0);
143*0Sstevel@tonic-gate
144*0Sstevel@tonic-gate /* Clean up. This is not yet complete, which is no big deal (since the
145*0Sstevel@tonic-gate * program is normally done at this point anyway. */
146*0Sstevel@tonic-gate for (t=TrSpecs; t; ) {
147*0Sstevel@tonic-gate tn = t->next;
148*0Sstevel@tonic-gate /* free the contents of t here ... */
149*0Sstevel@tonic-gate (void)free((void* )t);
150*0Sstevel@tonic-gate t = tn;
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate TrSpecs = 0;
153*0Sstevel@tonic-gate }
154*0Sstevel@tonic-gate
155*0Sstevel@tonic-gate /* ______________________________________________________________________ */
156*0Sstevel@tonic-gate /* Print warning about unprocessed elements in this doc tree (if they
157*0Sstevel@tonic-gate * were not explicitely ignored).
158*0Sstevel@tonic-gate * Arguments:
159*0Sstevel@tonic-gate * Pointer to element under consideration.
160*0Sstevel@tonic-gate */
161*0Sstevel@tonic-gate static void
WasProcessed(Element_t * e)162*0Sstevel@tonic-gate WasProcessed(
163*0Sstevel@tonic-gate Element_t *e
164*0Sstevel@tonic-gate )
165*0Sstevel@tonic-gate {
166*0Sstevel@tonic-gate Trans_t *t;
167*0Sstevel@tonic-gate t = e->trans;
168*0Sstevel@tonic-gate if (!e->processed && (t && !t->ignore)) {
169*0Sstevel@tonic-gate fprintf(stderr, "Warning: element '%s' was not processed:\n", e->gi);
170*0Sstevel@tonic-gate PrintLocation(e, stderr);
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate /* ______________________________________________________________________ */
175*0Sstevel@tonic-gate /* For each element find transpec.
176*0Sstevel@tonic-gate * Arguments:
177*0Sstevel@tonic-gate * Pointer to element under consideration.
178*0Sstevel@tonic-gate */
179*0Sstevel@tonic-gate void
PrepTranspecs(Element_t * e)180*0Sstevel@tonic-gate PrepTranspecs(
181*0Sstevel@tonic-gate Element_t *e
182*0Sstevel@tonic-gate )
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate Trans_t *t;
185*0Sstevel@tonic-gate t = FindTrans(e, 0);
186*0Sstevel@tonic-gate e->trans = t;
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gate /* ______________________________________________________________________ */
190*0Sstevel@tonic-gate /* Copy a buffer/string into another, expanding regular variables and immediate
191*0Sstevel@tonic-gate * variables. (Special variables are done later.)
192*0Sstevel@tonic-gate * Arguments:
193*0Sstevel@tonic-gate * Pointer to string to expand.
194*0Sstevel@tonic-gate * Pointer to expanded string. (return)
195*0Sstevel@tonic-gate * Pointer to element under consideration.
196*0Sstevel@tonic-gate */
197*0Sstevel@tonic-gate void
ExpandVariables(char * in,char * out,Element_t * e)198*0Sstevel@tonic-gate ExpandVariables(
199*0Sstevel@tonic-gate char *in,
200*0Sstevel@tonic-gate char *out,
201*0Sstevel@tonic-gate Element_t *e
202*0Sstevel@tonic-gate )
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate register int i, j, k;
205*0Sstevel@tonic-gate char *ip, *vp, *op;
206*0Sstevel@tonic-gate char *def_val, *s, *atval, *modifier;
207*0Sstevel@tonic-gate char vbuf[500];
208*0Sstevel@tonic-gate int lev;
209*0Sstevel@tonic-gate
210*0Sstevel@tonic-gate ip = in;
211*0Sstevel@tonic-gate op = out;
212*0Sstevel@tonic-gate while (*ip) {
213*0Sstevel@tonic-gate /* start of regular variable? */
214*0Sstevel@tonic-gate if (*ip == '$' && *(ip+1) == L_CURLY && *(ip+2) != '_') {
215*0Sstevel@tonic-gate ip++;
216*0Sstevel@tonic-gate ip++; /* point at variable name */
217*0Sstevel@tonic-gate vp = vbuf;
218*0Sstevel@tonic-gate /* Look for matching (closing) curly. (watch for nesting)
219*0Sstevel@tonic-gate * We store the variable content in a tmp buffer, so we don't
220*0Sstevel@tonic-gate * clobber the input buffer.
221*0Sstevel@tonic-gate */
222*0Sstevel@tonic-gate lev = 0;
223*0Sstevel@tonic-gate while (*ip) {
224*0Sstevel@tonic-gate if (*ip == L_CURLY) lev++;
225*0Sstevel@tonic-gate if (*ip == R_CURLY) {
226*0Sstevel@tonic-gate if (lev == 0) {
227*0Sstevel@tonic-gate ip++;
228*0Sstevel@tonic-gate break;
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate else lev--;
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate *vp++ = *ip++; /* copy to variable buffer */
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate *vp = EOS;
235*0Sstevel@tonic-gate /* vbuf now contains the variable name (stuff between curlys). */
236*0Sstevel@tonic-gate if (lev != 0) {
237*0Sstevel@tonic-gate fprintf(stderr, "Botched variable use: %s\n", in);
238*0Sstevel@tonic-gate /* copy rest of string if we can't recover ?? */
239*0Sstevel@tonic-gate return;
240*0Sstevel@tonic-gate }
241*0Sstevel@tonic-gate /* Now, expand variable. */
242*0Sstevel@tonic-gate vp = vbuf;
243*0Sstevel@tonic-gate
244*0Sstevel@tonic-gate /* Check for immediate variables -- like _special variables but
245*0Sstevel@tonic-gate * interpreted right now. These start with a "+" */
246*0Sstevel@tonic-gate if ( *vp == '+' ) {
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gate if ( ! strcmp(vp, "+content") ) {
249*0Sstevel@tonic-gate for ( i=0; i<e->ncont; i++ ) {
250*0Sstevel@tonic-gate if ( IsContData(e, i) ) {
251*0Sstevel@tonic-gate j = strlen(ContData(e,i));
252*0Sstevel@tonic-gate memcpy(op, ContData(e,i), j);
253*0Sstevel@tonic-gate op += j;
254*0Sstevel@tonic-gate } else {
255*0Sstevel@tonic-gate if ( warnings )
256*0Sstevel@tonic-gate if (! IsContPI(e, i) )
257*0Sstevel@tonic-gate fprintf(stderr, "warning: ${+current} skipped element content\n");
258*0Sstevel@tonic-gate }
259*0Sstevel@tonic-gate }
260*0Sstevel@tonic-gate
261*0Sstevel@tonic-gate } else
262*0Sstevel@tonic-gate
263*0Sstevel@tonic-gate if ( ! strcmp(vp, "+caps") ) {
264*0Sstevel@tonic-gate for ( i=k=0; i<e->ncont; i++ ) {
265*0Sstevel@tonic-gate if ( IsContData(e, i) ) {
266*0Sstevel@tonic-gate for ( j=0; ContData(e, i)[j]; j++ ) {
267*0Sstevel@tonic-gate *op++ = toupper(ContData(e, i)[j]);
268*0Sstevel@tonic-gate }
269*0Sstevel@tonic-gate } else {
270*0Sstevel@tonic-gate #if FALSE
271*0Sstevel@tonic-gate if ( warnings )
272*0Sstevel@tonic-gate fprintf(stderr, "warning: ${+caps} skipped element content\n");
273*0Sstevel@tonic-gate #endif
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate *op = 0;
277*0Sstevel@tonic-gate
278*0Sstevel@tonic-gate } else {
279*0Sstevel@tonic-gate fprintf(stderr, "unknown immediate variable: %s\n", vp);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gate } else {
283*0Sstevel@tonic-gate
284*0Sstevel@tonic-gate /* See if this variable has a default [ format: ${varname def} ] */
285*0Sstevel@tonic-gate
286*0Sstevel@tonic-gate def_val = vp;
287*0Sstevel@tonic-gate while (*def_val && *def_val != ' ') def_val++;
288*0Sstevel@tonic-gate if (*def_val) *def_val++ = EOS;
289*0Sstevel@tonic-gate else def_val = 0;
290*0Sstevel@tonic-gate /* def_val now points to default, if it exists, null if not. */
291*0Sstevel@tonic-gate
292*0Sstevel@tonic-gate modifier = vp;
293*0Sstevel@tonic-gate while (*modifier && *modifier != ':') modifier++;
294*0Sstevel@tonic-gate if (*modifier) *modifier++ = EOS;
295*0Sstevel@tonic-gate else modifier = 0;
296*0Sstevel@tonic-gate /* modifier now points to modifier if it exists, null if not. */
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gate s = 0;
299*0Sstevel@tonic-gate /* if attribute of current elem with this name found, use value */
300*0Sstevel@tonic-gate if (e && (atval = FindAttValByName(e, vp)))
301*0Sstevel@tonic-gate s = atval;
302*0Sstevel@tonic-gate else /* else try for (global) variable with this name */
303*0Sstevel@tonic-gate s = FindMappingVal(Variables, vp);
304*0Sstevel@tonic-gate
305*0Sstevel@tonic-gate /* If we found a value, copy it to the output buffer. */
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate if (s) {
308*0Sstevel@tonic-gate if ( modifier && *modifier == 'l' ) {
309*0Sstevel@tonic-gate while (*s) {
310*0Sstevel@tonic-gate *op = tolower(*s);
311*0Sstevel@tonic-gate op++, *s++;
312*0Sstevel@tonic-gate }
313*0Sstevel@tonic-gate } else
314*0Sstevel@tonic-gate while (*s) *op++ = *s++;
315*0Sstevel@tonic-gate } else
316*0Sstevel@tonic-gate if (def_val) {
317*0Sstevel@tonic-gate while (*def_val) *op++ = *def_val++;
318*0Sstevel@tonic-gate }
319*0Sstevel@tonic-gate }
320*0Sstevel@tonic-gate continue;
321*0Sstevel@tonic-gate }
322*0Sstevel@tonic-gate *op++ = *ip++;
323*0Sstevel@tonic-gate }
324*0Sstevel@tonic-gate *op = EOS; /* terminate string */
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate
327*0Sstevel@tonic-gate /* ______________________________________________________________________ */
328*0Sstevel@tonic-gate /* Process an "output" translation spec - one of StartText, EndText,
329*0Sstevel@tonic-gate * Replace, Message. (These are the ones that produce output.)
330*0Sstevel@tonic-gate * Steps done:
331*0Sstevel@tonic-gate * Expand attributes and regular varaibles in input string.
332*0Sstevel@tonic-gate * Pass thru string, accumulating chars to be sent to output stream.
333*0Sstevel@tonic-gate * If we find the start of a special variable, output what we've
334*0Sstevel@tonic-gate * accumulated, then find the special variable's "bounds" (ie, the
335*0Sstevel@tonic-gate * stuff between the curly brackets), and expand that by passing to
336*0Sstevel@tonic-gate * ExpandSpecialVar(). Continue until done the input string.
337*0Sstevel@tonic-gate * Arguments:
338*0Sstevel@tonic-gate * Input buffer (string) to be expanded and output.
339*0Sstevel@tonic-gate * Pointer to element under consideration.
340*0Sstevel@tonic-gate * FILE pointer to where to write output.
341*0Sstevel@tonic-gate * Flag saying whether to track the character position we're on
342*0Sstevel@tonic-gate * (passed to OutputString).
343*0Sstevel@tonic-gate */
344*0Sstevel@tonic-gate void
ProcesOutputSpec(char * ib,Element_t * e,FILE * fp,int track_pos)345*0Sstevel@tonic-gate ProcesOutputSpec(
346*0Sstevel@tonic-gate char *ib,
347*0Sstevel@tonic-gate Element_t *e,
348*0Sstevel@tonic-gate FILE *fp,
349*0Sstevel@tonic-gate int track_pos
350*0Sstevel@tonic-gate )
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate char obuf[LINESIZE];
353*0Sstevel@tonic-gate char vbuf[LINESIZE];
354*0Sstevel@tonic-gate char *dest, vname[LINESIZE], *cp;
355*0Sstevel@tonic-gate int esc;
356*0Sstevel@tonic-gate
357*0Sstevel@tonic-gate obuf[0] = EOS; /* start with empty output buffer */
358*0Sstevel@tonic-gate
359*0Sstevel@tonic-gate ExpandVariables(ib, vbuf, e); /* expand regular variables */
360*0Sstevel@tonic-gate ib = vbuf;
361*0Sstevel@tonic-gate dest = obuf;
362*0Sstevel@tonic-gate
363*0Sstevel@tonic-gate esc = 0;
364*0Sstevel@tonic-gate while (*ib) {
365*0Sstevel@tonic-gate /* Is esc-$ next? If so, just copy the '$'. */
366*0Sstevel@tonic-gate if (*ib == '\\' && ib[1] == '$') {
367*0Sstevel@tonic-gate ib++; /* skip esc */
368*0Sstevel@tonic-gate *dest++ = *ib++; /* copy $ */
369*0Sstevel@tonic-gate continue;
370*0Sstevel@tonic-gate }
371*0Sstevel@tonic-gate
372*0Sstevel@tonic-gate /* If not a $, it's a regular char. Just copy it and go to next. */
373*0Sstevel@tonic-gate if (*ib != '$') { /* look for att/variable marker */
374*0Sstevel@tonic-gate *dest++ = *ib++; /* it's not. just copy character */
375*0Sstevel@tonic-gate continue;
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate
378*0Sstevel@tonic-gate /* We have a $. What we have must be a "special variable" since
379*0Sstevel@tonic-gate * regular variables have already been expanded, or just a lone $. */
380*0Sstevel@tonic-gate
381*0Sstevel@tonic-gate if (ib[1] != L_CURLY) { /* just a stray dollar sign (no variable) */
382*0Sstevel@tonic-gate *dest++ = *ib++;
383*0Sstevel@tonic-gate continue;
384*0Sstevel@tonic-gate }
385*0Sstevel@tonic-gate
386*0Sstevel@tonic-gate ib++; /* point past $ */
387*0Sstevel@tonic-gate
388*0Sstevel@tonic-gate /* Output what we have in buffer so far. */
389*0Sstevel@tonic-gate *dest = EOS; /* terminate string */
390*0Sstevel@tonic-gate if (obuf[0]) OutputString(obuf, fp, track_pos);
391*0Sstevel@tonic-gate dest = obuf; /* ready for new stuff in buffer */
392*0Sstevel@tonic-gate
393*0Sstevel@tonic-gate if (!strchr(ib, R_CURLY)) {
394*0Sstevel@tonic-gate fprintf(stderr, "Mismatched braces in TranSpec: %s\n", ib);
395*0Sstevel@tonic-gate /* how do we recover from this? */
396*0Sstevel@tonic-gate }
397*0Sstevel@tonic-gate ib++;
398*0Sstevel@tonic-gate cp = vname;
399*0Sstevel@tonic-gate while (*ib && *ib != R_CURLY) *cp++ = *ib++;
400*0Sstevel@tonic-gate *cp = EOS; /* terminate att/var name */
401*0Sstevel@tonic-gate ib++; /* point past closing curly */
402*0Sstevel@tonic-gate /* we now have special variable name (stuff in curly {}'s) in vname */
403*0Sstevel@tonic-gate ExpandSpecialVar(&vname[1], e, fp, track_pos);
404*0Sstevel@tonic-gate }
405*0Sstevel@tonic-gate *dest = EOS; /* terminate string in output buffer */
406*0Sstevel@tonic-gate
407*0Sstevel@tonic-gate if (obuf[0]) OutputString(obuf, fp, track_pos);
408*0Sstevel@tonic-gate }
409*0Sstevel@tonic-gate
410*0Sstevel@tonic-gate /* ______________________________________________________________________ */
411*0Sstevel@tonic-gate /* Find the translation spec for the given tag.
412*0Sstevel@tonic-gate * Returns pointer to first spec that matches (name, depth, etc., of tag).
413*0Sstevel@tonic-gate * Arguments:
414*0Sstevel@tonic-gate * e -- Pointer to element under consideration.
415*0Sstevel@tonic-gate * specID -- name of specid that we're looking for
416*0Sstevel@tonic-gate * Return:
417*0Sstevel@tonic-gate * Pointer to translation spec that matches given element's context.
418*0Sstevel@tonic-gate */
419*0Sstevel@tonic-gate
420*0Sstevel@tonic-gate Trans_t *
FindTrans(Element_t * e,int specID)421*0Sstevel@tonic-gate FindTrans(
422*0Sstevel@tonic-gate Element_t *e,
423*0Sstevel@tonic-gate int specID
424*0Sstevel@tonic-gate )
425*0Sstevel@tonic-gate {
426*0Sstevel@tonic-gate char context[LINESIZE], buf[LINESIZE], *cp, **vec, *atval;
427*0Sstevel@tonic-gate int i, a, match;
428*0Sstevel@tonic-gate Trans_t *t, *tt;
429*0Sstevel@tonic-gate
430*0Sstevel@tonic-gate /* loop through all transpecs */
431*0Sstevel@tonic-gate for (t=TrSpecs; t; t=t->next)
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate /* Only one of gi or gilist will be set. */
434*0Sstevel@tonic-gate /* Check if elem name matches */
435*0Sstevel@tonic-gate if (t->gi && !StrEq(t->gi, e->gi) && !specID) continue;
436*0Sstevel@tonic-gate
437*0Sstevel@tonic-gate /* test if we're looking for a specific specID and then if
438*0Sstevel@tonic-gate * this is it.. */
439*0Sstevel@tonic-gate if (specID)
440*0Sstevel@tonic-gate if (!t->my_id || (specID != t->my_id))
441*0Sstevel@tonic-gate continue;
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gate /* Match one in the list of GIs? */
444*0Sstevel@tonic-gate if (t->gilist) {
445*0Sstevel@tonic-gate for (match=0,vec=t->gilist; *vec; vec++) {
446*0Sstevel@tonic-gate if (StrEq(*vec, e->gi)) {
447*0Sstevel@tonic-gate match = 1;
448*0Sstevel@tonic-gate break;
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate }
451*0Sstevel@tonic-gate if (!match) continue;
452*0Sstevel@tonic-gate }
453*0Sstevel@tonic-gate
454*0Sstevel@tonic-gate /* Check context */
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate /* Special case of context */
457*0Sstevel@tonic-gate if (t->parent)
458*0Sstevel@tonic-gate if (!QRelation(e, t->parent, REL_Parent)) continue;
459*0Sstevel@tonic-gate
460*0Sstevel@tonic-gate if (t->context) { /* no context specified -> a match */
461*0Sstevel@tonic-gate FindContext(e, t->depth, context);
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gate /* If reg expr set, do regex compare; else just string compare. */
464*0Sstevel@tonic-gate if (t->context_re) {
465*0Sstevel@tonic-gate if (! tpt_regexec(t->context_re, context)) continue;
466*0Sstevel@tonic-gate }
467*0Sstevel@tonic-gate else {
468*0Sstevel@tonic-gate /* Is depth of spec deeper than element's depth? */
469*0Sstevel@tonic-gate if (t->depth > e->depth) continue;
470*0Sstevel@tonic-gate
471*0Sstevel@tonic-gate /* See if context of element matches "context" of transpec */
472*0Sstevel@tonic-gate match = ( (t->context[0] == context[0]) &&
473*0Sstevel@tonic-gate !strcmp(t->context, context) );
474*0Sstevel@tonic-gate if (!match) continue;
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate }
477*0Sstevel@tonic-gate
478*0Sstevel@tonic-gate /* Check attributes. Loop through list, comparing each. */
479*0Sstevel@tonic-gate if (t->nattpairs) { /* no att specified -> a match */
480*0Sstevel@tonic-gate for (match=1,a=0; a<t->nattpairs; a++) {
481*0Sstevel@tonic-gate if (!(atval = FindAttValByName(e, t->attpair[a].name))) {
482*0Sstevel@tonic-gate match = 0;
483*0Sstevel@tonic-gate break;
484*0Sstevel@tonic-gate }
485*0Sstevel@tonic-gate if (!tpt_regexec(t->attpair[a].rex, atval)) match = 0;
486*0Sstevel@tonic-gate }
487*0Sstevel@tonic-gate if (!match) continue;
488*0Sstevel@tonic-gate }
489*0Sstevel@tonic-gate
490*0Sstevel@tonic-gate /* Check relationships: child, parent, ancestor, sib, ... */
491*0Sstevel@tonic-gate if (t->relations) {
492*0Sstevel@tonic-gate Mapping_t *r;
493*0Sstevel@tonic-gate match = 1;
494*0Sstevel@tonic-gate for (r=t->relations->maps,i=0; i<t->relations->n_used; i++) {
495*0Sstevel@tonic-gate if (!CheckRelation(e, r[i].name, r[i].sval, 0, 0, RA_Current)) {
496*0Sstevel@tonic-gate match = 0;
497*0Sstevel@tonic-gate break;
498*0Sstevel@tonic-gate }
499*0Sstevel@tonic-gate }
500*0Sstevel@tonic-gate if (!match) continue;
501*0Sstevel@tonic-gate }
502*0Sstevel@tonic-gate
503*0Sstevel@tonic-gate /* check this element's parent's attribute */
504*0Sstevel@tonic-gate if (t->pattrset && e->parent) {
505*0Sstevel@tonic-gate char *p, **tok;
506*0Sstevel@tonic-gate
507*0Sstevel@tonic-gate i = 2;
508*0Sstevel@tonic-gate match = 1;
509*0Sstevel@tonic-gate tok = Split(t->pattrset, &i, S_STRDUP);
510*0Sstevel@tonic-gate if ( i == 2 ) {
511*0Sstevel@tonic-gate p = FindAttValByName(e->parent, tok[0]);
512*0Sstevel@tonic-gate ExpandVariables(tok[1], buf, 0);
513*0Sstevel@tonic-gate if ( !p || strcmp(p, buf) )
514*0Sstevel@tonic-gate match = 0;
515*0Sstevel@tonic-gate } else {
516*0Sstevel@tonic-gate if (!FindAttValByName(e->parent, t->pattrset))
517*0Sstevel@tonic-gate match = 0;
518*0Sstevel@tonic-gate }
519*0Sstevel@tonic-gate free(tok[0]);
520*0Sstevel@tonic-gate if (!match) continue;
521*0Sstevel@tonic-gate }
522*0Sstevel@tonic-gate
523*0Sstevel@tonic-gate /* check this element's "birth order" */
524*0Sstevel@tonic-gate if (t->nth_child) {
525*0Sstevel@tonic-gate /* First one is called "1" by the user. Internally called "0". */
526*0Sstevel@tonic-gate i = t->nth_child;
527*0Sstevel@tonic-gate if (i > 0) { /* positive # -- count from beginning */
528*0Sstevel@tonic-gate if (e->my_eorder != (i-1)) continue;
529*0Sstevel@tonic-gate }
530*0Sstevel@tonic-gate else { /* negative # -- count from end */
531*0Sstevel@tonic-gate i = e->parent->necont - i;
532*0Sstevel@tonic-gate if (e->my_eorder != i) continue;
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate }
535*0Sstevel@tonic-gate
536*0Sstevel@tonic-gate /* check that variables match */
537*0Sstevel@tonic-gate if (t->var_name) {
538*0Sstevel@tonic-gate cp = FindMappingVal(Variables, t->var_name);
539*0Sstevel@tonic-gate if (!cp || strcmp(cp, t->var_value)) continue;
540*0Sstevel@tonic-gate }
541*0Sstevel@tonic-gate
542*0Sstevel@tonic-gate /* check for variable regular expression match */
543*0Sstevel@tonic-gate if ( t->var_RE_name ) {
544*0Sstevel@tonic-gate cp = FindMappingVal(Variables, t->var_RE_name);
545*0Sstevel@tonic-gate if (!cp || !tpt_regexec(t->var_RE_value, cp)) continue;
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate
548*0Sstevel@tonic-gate /* check content */
549*0Sstevel@tonic-gate if (t->content) { /* no att specified -> a match */
550*0Sstevel@tonic-gate for (match=0,i=0; i<e->ndcont; i++) {
551*0Sstevel@tonic-gate if (tpt_regexec(t->content_re, e->dcont[i])) {
552*0Sstevel@tonic-gate match = 1;
553*0Sstevel@tonic-gate break;
554*0Sstevel@tonic-gate }
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate if (!match) continue;
557*0Sstevel@tonic-gate }
558*0Sstevel@tonic-gate
559*0Sstevel@tonic-gate /* -------- at this point we've passed all criteria -------- */
560*0Sstevel@tonic-gate
561*0Sstevel@tonic-gate /* See if we should be using another transpec's actions. */
562*0Sstevel@tonic-gate if (t->use_id) {
563*0Sstevel@tonic-gate if (t->use_id < 0) return &NullTrans; /* missing? */
564*0Sstevel@tonic-gate /* see if we have a pointer to that transpec */
565*0Sstevel@tonic-gate if (t->use_trans) return t->use_trans;
566*0Sstevel@tonic-gate for (tt=TrSpecs; tt; tt=tt->next) {
567*0Sstevel@tonic-gate if (t->use_id == tt->my_id) {
568*0Sstevel@tonic-gate /* remember pointer for next time */
569*0Sstevel@tonic-gate t->use_trans = tt;
570*0Sstevel@tonic-gate return t->use_trans;
571*0Sstevel@tonic-gate }
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate t->use_id = -1; /* flag it as missing */
574*0Sstevel@tonic-gate fprintf(stderr, "Warning: transpec ID (%d) not found for %s.\n",
575*0Sstevel@tonic-gate t->use_id, e->gi);
576*0Sstevel@tonic-gate return &NullTrans;
577*0Sstevel@tonic-gate }
578*0Sstevel@tonic-gate
579*0Sstevel@tonic-gate return t;
580*0Sstevel@tonic-gate }
581*0Sstevel@tonic-gate
582*0Sstevel@tonic-gate /* At this point, we have not found a matching spec. See if there
583*0Sstevel@tonic-gate * is a wildcard, and if so, use it. (Wildcard GI is named "*".) */
584*0Sstevel@tonic-gate if ((t = FindTransByName("*"))) return t;
585*0Sstevel@tonic-gate
586*0Sstevel@tonic-gate if (warnings && !specID)
587*0Sstevel@tonic-gate fprintf(stderr, "Warning: transpec not found for %s\n", e->gi);
588*0Sstevel@tonic-gate
589*0Sstevel@tonic-gate /* default spec - pass character data and descend node */
590*0Sstevel@tonic-gate return &NullTrans;
591*0Sstevel@tonic-gate }
592*0Sstevel@tonic-gate
593*0Sstevel@tonic-gate /* ______________________________________________________________________ */
594*0Sstevel@tonic-gate /* Find translation spec by (GI) name. Returns the first one that matches.
595*0Sstevel@tonic-gate * Arguments:
596*0Sstevel@tonic-gate * Pointer to name of transpec (the "gi" field of the Trans structure).
597*0Sstevel@tonic-gate * Return:
598*0Sstevel@tonic-gate * Pointer to translation spec that matches name.
599*0Sstevel@tonic-gate */
600*0Sstevel@tonic-gate
601*0Sstevel@tonic-gate Trans_t *
FindTransByName(char * s)602*0Sstevel@tonic-gate FindTransByName(
603*0Sstevel@tonic-gate char *s
604*0Sstevel@tonic-gate )
605*0Sstevel@tonic-gate {
606*0Sstevel@tonic-gate Trans_t *t;
607*0Sstevel@tonic-gate
608*0Sstevel@tonic-gate for (t=TrSpecs; t; t=t->next) {
609*0Sstevel@tonic-gate /* check if tag name matches (first check 1st char, for efficiency) */
610*0Sstevel@tonic-gate if (t->gi) {
611*0Sstevel@tonic-gate if (*(t->gi) != *s) continue; /* check 1st character */
612*0Sstevel@tonic-gate if (!strcmp(t->gi, s)) return t;
613*0Sstevel@tonic-gate }
614*0Sstevel@tonic-gate }
615*0Sstevel@tonic-gate return NULL;
616*0Sstevel@tonic-gate }
617*0Sstevel@tonic-gate
618*0Sstevel@tonic-gate /* Find translation spec by its ID (SpecID).
619*0Sstevel@tonic-gate * Arguments:
620*0Sstevel@tonic-gate * Spec ID (an int).
621*0Sstevel@tonic-gate * Return:
622*0Sstevel@tonic-gate * Pointer to translation spec that matches name.
623*0Sstevel@tonic-gate */
624*0Sstevel@tonic-gate Trans_t *
FindTranByID(int n)625*0Sstevel@tonic-gate FindTranByID(int n)
626*0Sstevel@tonic-gate {
627*0Sstevel@tonic-gate Trans_t *t;
628*0Sstevel@tonic-gate
629*0Sstevel@tonic-gate for (t=TrSpecs; t; t=t->next)
630*0Sstevel@tonic-gate if (n == t->my_id) return t;
631*0Sstevel@tonic-gate return NULL;
632*0Sstevel@tonic-gate }
633*0Sstevel@tonic-gate
634*0Sstevel@tonic-gate /* ______________________________________________________________________ */
635*0Sstevel@tonic-gate /* Process a "chunk" of content data of an element.
636*0Sstevel@tonic-gate * Arguments:
637*0Sstevel@tonic-gate * Pointer to data content to process
638*0Sstevel@tonic-gate * FILE pointer to where to write output.
639*0Sstevel@tonic-gate */
640*0Sstevel@tonic-gate
641*0Sstevel@tonic-gate void
DoData(char * data,FILE * fp,Trans_t * t)642*0Sstevel@tonic-gate DoData(
643*0Sstevel@tonic-gate char *data,
644*0Sstevel@tonic-gate FILE *fp,
645*0Sstevel@tonic-gate Trans_t *t
646*0Sstevel@tonic-gate )
647*0Sstevel@tonic-gate {
648*0Sstevel@tonic-gate char *cp, buf[LINESIZE], *dp, *sub, prev;
649*0Sstevel@tonic-gate int i, j, mapped;
650*0Sstevel@tonic-gate Mapping_t *m;
651*0Sstevel@tonic-gate
652*0Sstevel@tonic-gate /* Worry about embedded newlines? */
653*0Sstevel@tonic-gate
654*0Sstevel@tonic-gate if (!fp) return;
655*0Sstevel@tonic-gate
656*0Sstevel@tonic-gate /* CLEANUP: this should really all be done in OutputString(). (I think) */
657*0Sstevel@tonic-gate
658*0Sstevel@tonic-gate if (nCharMap) {
659*0Sstevel@tonic-gate /* for each character, see if it's mapped to something else */
660*0Sstevel@tonic-gate for (prev=0,cp=data,dp=buf; *cp; cp++) {
661*0Sstevel@tonic-gate if (prev == '\\') {
662*0Sstevel@tonic-gate *dp++ = *cp;
663*0Sstevel@tonic-gate prev = *cp;
664*0Sstevel@tonic-gate continue;
665*0Sstevel@tonic-gate }
666*0Sstevel@tonic-gate for (mapped=0,i=0; !t->verbatim && (i<nCharMap); i++) {
667*0Sstevel@tonic-gate if ((*cp != CharMap[i].name[0]) ||
668*0Sstevel@tonic-gate ((*cp == '\\') && (*(cp+1) != '\\')) )
669*0Sstevel@tonic-gate continue;
670*0Sstevel@tonic-gate if ( *cp == '\\' )
671*0Sstevel@tonic-gate *cp++;
672*0Sstevel@tonic-gate sub = CharMap[i].sval;
673*0Sstevel@tonic-gate while (*sub) *dp++ = *sub++;
674*0Sstevel@tonic-gate mapped = 1;
675*0Sstevel@tonic-gate break;
676*0Sstevel@tonic-gate }
677*0Sstevel@tonic-gate for ( j=tsStacki; j >= 0; j-- ) {
678*0Sstevel@tonic-gate if (tsStack[j]->substitute) {
679*0Sstevel@tonic-gate for (m=tsStack[j]->substitute->maps,i=0;
680*0Sstevel@tonic-gate i<tsStack[j]->substitute->n_used; i++) {
681*0Sstevel@tonic-gate if ( *cp == m[i].name[0] ) {
682*0Sstevel@tonic-gate sub = m[i].sval;
683*0Sstevel@tonic-gate while (*sub)
684*0Sstevel@tonic-gate *dp++ = *sub++;
685*0Sstevel@tonic-gate mapped = 2;
686*0Sstevel@tonic-gate break;
687*0Sstevel@tonic-gate }
688*0Sstevel@tonic-gate }
689*0Sstevel@tonic-gate if ( mapped == 2 )
690*0Sstevel@tonic-gate break;
691*0Sstevel@tonic-gate }
692*0Sstevel@tonic-gate }
693*0Sstevel@tonic-gate if ( *cp == -1 ) *cp = '';
694*0Sstevel@tonic-gate if (!mapped && t->trim && (strchr(t->trim, *cp) != NULL)) {
695*0Sstevel@tonic-gate continue;
696*0Sstevel@tonic-gate }
697*0Sstevel@tonic-gate if (!mapped) *dp++ = *cp;
698*0Sstevel@tonic-gate prev = *cp;
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate *dp = EOS;
701*0Sstevel@tonic-gate dp = buf;
702*0Sstevel@tonic-gate }
703*0Sstevel@tonic-gate else dp = data;
704*0Sstevel@tonic-gate OutputString(dp, fp, 1);
705*0Sstevel@tonic-gate }
706*0Sstevel@tonic-gate
707*0Sstevel@tonic-gate /* ______________________________________________________________________ */
708*0Sstevel@tonic-gate /* Handle a processing instruction. This is done similarly to elements,
709*0Sstevel@tonic-gate * where we find a transpec, then do what it says. Differences: PI names
710*0Sstevel@tonic-gate * start with '_' in the spec file (if a GI does not start with '_', it
711*0Sstevel@tonic-gate * may be forced to upper case, sgmls keeps PIs as mixed case); the args
712*0Sstevel@tonic-gate * to the PI are treated as the data of an element. Note that a PI wildcard
713*0Sstevel@tonic-gate * is "_*"
714*0Sstevel@tonic-gate * Arguments:
715*0Sstevel@tonic-gate * Pointer to the PI.
716*0Sstevel@tonic-gate * FILE pointer to where to write output.
717*0Sstevel@tonic-gate */
718*0Sstevel@tonic-gate
719*0Sstevel@tonic-gate void
DoPI(char * pi,FILE * fp)720*0Sstevel@tonic-gate DoPI(
721*0Sstevel@tonic-gate char *pi,
722*0Sstevel@tonic-gate FILE *fp
723*0Sstevel@tonic-gate )
724*0Sstevel@tonic-gate {
725*0Sstevel@tonic-gate char buf[250], **tok;
726*0Sstevel@tonic-gate int n;
727*0Sstevel@tonic-gate Trans_t *t;
728*0Sstevel@tonic-gate
729*0Sstevel@tonic-gate buf[0] = '_';
730*0Sstevel@tonic-gate strcpy(&buf[1], pi);
731*0Sstevel@tonic-gate n = 2;
732*0Sstevel@tonic-gate tok = Split(buf, &n, 0);
733*0Sstevel@tonic-gate if ((t = FindTransByName(tok[0])) ||
734*0Sstevel@tonic-gate (t = FindTransByName("_*"))) {
735*0Sstevel@tonic-gate if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
736*0Sstevel@tonic-gate else {
737*0Sstevel@tonic-gate if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
738*0Sstevel@tonic-gate if (t->ignore != IGN_DATA) /* skip data nodes? */
739*0Sstevel@tonic-gate if (n > 1) OutputString(tok[1], fp, 1);
740*0Sstevel@tonic-gate if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
741*0Sstevel@tonic-gate }
742*0Sstevel@tonic-gate if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
743*0Sstevel@tonic-gate }
744*0Sstevel@tonic-gate else {
745*0Sstevel@tonic-gate /* If not found, just print the PI in square brackets, along
746*0Sstevel@tonic-gate * with a warning message. */
747*0Sstevel@tonic-gate fprintf(fp, "[%s]", pi);
748*0Sstevel@tonic-gate if (warnings) fprintf(stderr, "Warning: Unrecognized PI: [%s]\n", pi);
749*0Sstevel@tonic-gate }
750*0Sstevel@tonic-gate }
751*0Sstevel@tonic-gate
752*0Sstevel@tonic-gate /* ______________________________________________________________________ */
753*0Sstevel@tonic-gate /* Set and increment variables, as appropriate, if the transpec says to.
754*0Sstevel@tonic-gate * Arguments:
755*0Sstevel@tonic-gate * Pointer to translation spec for current element.
756*0Sstevel@tonic-gate */
757*0Sstevel@tonic-gate
758*0Sstevel@tonic-gate static void
set_and_increment(Trans_t * t,Element_t * e)759*0Sstevel@tonic-gate set_and_increment(
760*0Sstevel@tonic-gate Trans_t *t,
761*0Sstevel@tonic-gate Element_t *e
762*0Sstevel@tonic-gate )
763*0Sstevel@tonic-gate {
764*0Sstevel@tonic-gate Mapping_t *m;
765*0Sstevel@tonic-gate int i, inc, n;
766*0Sstevel@tonic-gate char *cp, buf[50];
767*0Sstevel@tonic-gate char ebuf[5000];
768*0Sstevel@tonic-gate
769*0Sstevel@tonic-gate /* set/reset variables */
770*0Sstevel@tonic-gate if (t->set_var) {
771*0Sstevel@tonic-gate for (m=t->set_var->maps,i=0; i<t->set_var->n_used; i++) {
772*0Sstevel@tonic-gate ExpandVariables(m[i].sval, ebuf, e); /* do some expansion */
773*0Sstevel@tonic-gate SetMappingNV(Variables, m[i].name, ebuf);
774*0Sstevel@tonic-gate }
775*0Sstevel@tonic-gate }
776*0Sstevel@tonic-gate
777*0Sstevel@tonic-gate /* increment counters */
778*0Sstevel@tonic-gate if (t->incr_var) {
779*0Sstevel@tonic-gate for (m=t->incr_var->maps,i=0; i<t->incr_var->n_used; i++) {
780*0Sstevel@tonic-gate cp = FindMappingVal(Variables, m[i].name);
781*0Sstevel@tonic-gate /* if not set at all, set to 1 */
782*0Sstevel@tonic-gate if (!cp) SetMappingNV(Variables, m[i].name, "1");
783*0Sstevel@tonic-gate else {
784*0Sstevel@tonic-gate if (isdigit(*cp) || (*cp == '-' && isdigit(cp[1]))) {
785*0Sstevel@tonic-gate n = atoi(cp);
786*0Sstevel@tonic-gate if (m[i].sval && isdigit(*m[i].sval)) inc = atoi(m[i].sval);
787*0Sstevel@tonic-gate else inc = 1;
788*0Sstevel@tonic-gate sprintf(buf, "%d", (n + inc));
789*0Sstevel@tonic-gate SetMappingNV(Variables, m[i].name, buf);
790*0Sstevel@tonic-gate } else
791*0Sstevel@tonic-gate if (!*(cp+1) && isalpha(*cp)) {
792*0Sstevel@tonic-gate buf[0] = *cp + 1;
793*0Sstevel@tonic-gate buf[1] = 0;
794*0Sstevel@tonic-gate SetMappingNV(Variables, m[i].name, buf);
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate }
797*0Sstevel@tonic-gate }
798*0Sstevel@tonic-gate }
799*0Sstevel@tonic-gate }
800*0Sstevel@tonic-gate
801*0Sstevel@tonic-gate /* ______________________________________________________________________ */
802*0Sstevel@tonic-gate /* Translate one element.
803*0Sstevel@tonic-gate * Arguments:
804*0Sstevel@tonic-gate * Pointer to element under consideration.
805*0Sstevel@tonic-gate * FILE pointer to where to write output.
806*0Sstevel@tonic-gate * Pointer to translation spec for current element, or null.
807*0Sstevel@tonic-gate */
808*0Sstevel@tonic-gate void
TransElement(Element_t * e,FILE * fp,Trans_t * t)809*0Sstevel@tonic-gate TransElement(
810*0Sstevel@tonic-gate Element_t *e,
811*0Sstevel@tonic-gate FILE *fp,
812*0Sstevel@tonic-gate Trans_t *t
813*0Sstevel@tonic-gate )
814*0Sstevel@tonic-gate {
815*0Sstevel@tonic-gate int i;
816*0Sstevel@tonic-gate
817*0Sstevel@tonic-gate if (!t) t = ((e && e->trans) ? e->trans : &NullTrans);
818*0Sstevel@tonic-gate
819*0Sstevel@tonic-gate /* see if we should quit. */
820*0Sstevel@tonic-gate if (t->quit) {
821*0Sstevel@tonic-gate fprintf(stderr, "Quitting at location:\n");
822*0Sstevel@tonic-gate PrintLocation(e, fp);
823*0Sstevel@tonic-gate fprintf(stderr, "%s\n", t->quit);
824*0Sstevel@tonic-gate exit(1);
825*0Sstevel@tonic-gate }
826*0Sstevel@tonic-gate
827*0Sstevel@tonic-gate /* stack this element */
828*0Sstevel@tonic-gate PushTranspecName(t);
829*0Sstevel@tonic-gate
830*0Sstevel@tonic-gate /* See if we want to replace subtree (do text, don't descend subtree) */
831*0Sstevel@tonic-gate if (t->replace) {
832*0Sstevel@tonic-gate ProcesOutputSpec(t->replace, e, fp, 1);
833*0Sstevel@tonic-gate if (t->message) ProcesOutputSpec(t->message, e, stderr, 0);
834*0Sstevel@tonic-gate set_and_increment(t, e); /* adjust variables, if appropriate */
835*0Sstevel@tonic-gate PopTranspecName();
836*0Sstevel@tonic-gate return;
837*0Sstevel@tonic-gate }
838*0Sstevel@tonic-gate
839*0Sstevel@tonic-gate if (t->starttext) ProcesOutputSpec(t->starttext, e, fp, 1);
840*0Sstevel@tonic-gate if (t->message) ProcesOutputSpec(t->message, e, stderr, 0);
841*0Sstevel@tonic-gate
842*0Sstevel@tonic-gate /* Process data for this node and descend child elements/nodes. */
843*0Sstevel@tonic-gate if (t->ignore != IGN_ALL) {
844*0Sstevel@tonic-gate /* Is there a "generated" node at the front of this one? */
845*0Sstevel@tonic-gate if (e->gen_trans[0]) {
846*0Sstevel@tonic-gate Trans_t *tp;
847*0Sstevel@tonic-gate if ((tp = FindTranByID(e->gen_trans[0]))) {
848*0Sstevel@tonic-gate if (tp->starttext) ProcesOutputSpec(tp->starttext, e, fp, 1);
849*0Sstevel@tonic-gate if (tp->message) ProcesOutputSpec(tp->message, e, stderr, 0);
850*0Sstevel@tonic-gate if (tp->endtext) ProcesOutputSpec(tp->endtext, e, fp, 1);
851*0Sstevel@tonic-gate }
852*0Sstevel@tonic-gate }
853*0Sstevel@tonic-gate /* Loop thruthe "nodes", whether data, child element, or PI. */
854*0Sstevel@tonic-gate for (i=0; i<e->ncont; i++) {
855*0Sstevel@tonic-gate if (IsContElem(e,i)) {
856*0Sstevel@tonic-gate if (t->ignore != IGN_CHILDREN) /* skip child nodes? */
857*0Sstevel@tonic-gate TransElement(ContElem(e,i), fp, NULL);
858*0Sstevel@tonic-gate }
859*0Sstevel@tonic-gate else if (IsContData(e,i)) {
860*0Sstevel@tonic-gate if (t->ignore != IGN_DATA) /* skip data nodes? */
861*0Sstevel@tonic-gate DoData(ContData(e,i), fp, t);
862*0Sstevel@tonic-gate }
863*0Sstevel@tonic-gate else if (IsContPI(e,i))
864*0Sstevel@tonic-gate DoPI(e->cont[i].ch.data, fp);
865*0Sstevel@tonic-gate }
866*0Sstevel@tonic-gate /* Is there a "generated" node at the end of this one? */
867*0Sstevel@tonic-gate if (e->gen_trans[1]) {
868*0Sstevel@tonic-gate Trans_t *tp;
869*0Sstevel@tonic-gate if ((tp = FindTranByID(e->gen_trans[1]))) {
870*0Sstevel@tonic-gate if (tp->starttext) ProcesOutputSpec(tp->starttext, e, fp, 1);
871*0Sstevel@tonic-gate if (tp->message) ProcesOutputSpec(tp->message, e, stderr, 0);
872*0Sstevel@tonic-gate if (tp->endtext) ProcesOutputSpec(tp->endtext, e, fp, 1);
873*0Sstevel@tonic-gate }
874*0Sstevel@tonic-gate }
875*0Sstevel@tonic-gate }
876*0Sstevel@tonic-gate
877*0Sstevel@tonic-gate set_and_increment(t, e); /* adjust variables, if appropriate */
878*0Sstevel@tonic-gate
879*0Sstevel@tonic-gate if (t->endtext) ProcesOutputSpec(t->endtext, e, fp, 1);
880*0Sstevel@tonic-gate
881*0Sstevel@tonic-gate e->processed = 1;
882*0Sstevel@tonic-gate PopTranspecName();
883*0Sstevel@tonic-gate }
884*0Sstevel@tonic-gate
885*0Sstevel@tonic-gate /* ______________________________________________________________________ */
886*0Sstevel@tonic-gate /* Check if element matches specified relationship, and, if it does, perform
887*0Sstevel@tonic-gate * action on either current element or matching element (depends on flag).
888*0Sstevel@tonic-gate * Arguments:
889*0Sstevel@tonic-gate * Pointer to element under consideration.
890*0Sstevel@tonic-gate * Pointer to relationship name.
891*0Sstevel@tonic-gate * Pointer to related element name (GI).
892*0Sstevel@tonic-gate * Pointer to action to take (string - turned into an int).
893*0Sstevel@tonic-gate * FILE pointer to where to write output.
894*0Sstevel@tonic-gate * Flag saying whether to do action on related element (RA_Related)
895*0Sstevel@tonic-gate * or on current element (RA_Current).
896*0Sstevel@tonic-gate * Return:
897*0Sstevel@tonic-gate * Bool, saying whether (1) or not (0) relationship matches.
898*0Sstevel@tonic-gate */
899*0Sstevel@tonic-gate
900*0Sstevel@tonic-gate int
CheckRelation(Element_t * e,char * relname,char * related,char * actname,FILE * fp,RelAction_t flag)901*0Sstevel@tonic-gate CheckRelation(
902*0Sstevel@tonic-gate Element_t *e,
903*0Sstevel@tonic-gate char *relname, /* relationship name */
904*0Sstevel@tonic-gate char *related, /* related element */
905*0Sstevel@tonic-gate char *actname, /* action to take */
906*0Sstevel@tonic-gate FILE *fp,
907*0Sstevel@tonic-gate RelAction_t flag
908*0Sstevel@tonic-gate )
909*0Sstevel@tonic-gate {
910*0Sstevel@tonic-gate Element_t *ep;
911*0Sstevel@tonic-gate Relation_t r;
912*0Sstevel@tonic-gate
913*0Sstevel@tonic-gate if ((r = FindRelByName(relname)) == REL_Unknown) return 0;
914*0Sstevel@tonic-gate if (!(ep=QRelation(e, related, r))) return 0;
915*0Sstevel@tonic-gate
916*0Sstevel@tonic-gate if (!actname) return 1; /* no action - return what we found */
917*0Sstevel@tonic-gate
918*0Sstevel@tonic-gate switch (flag) {
919*0Sstevel@tonic-gate case RA_Related: TranTByAction(ep, actname, fp); break;
920*0Sstevel@tonic-gate case RA_Current: TranTByAction(e, actname, fp); break;
921*0Sstevel@tonic-gate }
922*0Sstevel@tonic-gate return 1;
923*0Sstevel@tonic-gate }
924*0Sstevel@tonic-gate
925*0Sstevel@tonic-gate /* ______________________________________________________________________ */
926*0Sstevel@tonic-gate /* Perform action given by a SpecID on the given element.
927*0Sstevel@tonic-gate * Arguments:
928*0Sstevel@tonic-gate * Pointer to element under consideration.
929*0Sstevel@tonic-gate * SpecID of action to perform.
930*0Sstevel@tonic-gate * FILE pointer to where to write output.
931*0Sstevel@tonic-gate *
932*0Sstevel@tonic-gate */
933*0Sstevel@tonic-gate void
TranByAction(Element_t * e,int n,FILE * fp)934*0Sstevel@tonic-gate TranByAction(
935*0Sstevel@tonic-gate Element_t *e,
936*0Sstevel@tonic-gate int n,
937*0Sstevel@tonic-gate FILE *fp
938*0Sstevel@tonic-gate )
939*0Sstevel@tonic-gate {
940*0Sstevel@tonic-gate Trans_t *t;
941*0Sstevel@tonic-gate
942*0Sstevel@tonic-gate t = FindTranByID(n);
943*0Sstevel@tonic-gate if (!t) {
944*0Sstevel@tonic-gate fprintf(stderr, "Could not find named action for %d.\n", n);
945*0Sstevel@tonic-gate return;
946*0Sstevel@tonic-gate }
947*0Sstevel@tonic-gate TransElement(e, fp, t);
948*0Sstevel@tonic-gate }
949*0Sstevel@tonic-gate
950*0Sstevel@tonic-gate /* ______________________________________________________________________ */
951*0Sstevel@tonic-gate /* Perhaps perform action given by a SpecID on the given element.
952*0Sstevel@tonic-gate * Arguments:
953*0Sstevel@tonic-gate * Pointer to element under consideration.
954*0Sstevel@tonic-gate * SpecID of action to perform. Unlike TranByAction, this is the argument
955*0Sstevel@tonic-gate * as it occurred in the transpec (ASCII) and may end with the letter
956*0Sstevel@tonic-gate * "t" which means that the transpec mustpass criteria selection.
957*0Sstevel@tonic-gate * FILE pointer to where to write output.
958*0Sstevel@tonic-gate */
959*0Sstevel@tonic-gate void
TranTByAction(Element_t * e,char * strn,FILE * fp)960*0Sstevel@tonic-gate TranTByAction(
961*0Sstevel@tonic-gate Element_t *e,
962*0Sstevel@tonic-gate char *strn,
963*0Sstevel@tonic-gate FILE *fp
964*0Sstevel@tonic-gate )
965*0Sstevel@tonic-gate {
966*0Sstevel@tonic-gate int n;
967*0Sstevel@tonic-gate Trans_t *t;
968*0Sstevel@tonic-gate
969*0Sstevel@tonic-gate n = atoi(strn);
970*0Sstevel@tonic-gate if ( strn[strlen(strn)-1] != 't' ) {
971*0Sstevel@tonic-gate t = FindTranByID(n);
972*0Sstevel@tonic-gate if (!t) {
973*0Sstevel@tonic-gate fprintf(stderr, "Could not find named action for %d.\n", n);
974*0Sstevel@tonic-gate return;
975*0Sstevel@tonic-gate }
976*0Sstevel@tonic-gate } else {
977*0Sstevel@tonic-gate t = FindTrans(e, n);
978*0Sstevel@tonic-gate if ( !t || !t->my_id )
979*0Sstevel@tonic-gate return;
980*0Sstevel@tonic-gate }
981*0Sstevel@tonic-gate TransElement(e, fp, t);
982*0Sstevel@tonic-gate }
983*0Sstevel@tonic-gate
984*0Sstevel@tonic-gate /* ______________________________________________________________________ */
985*0Sstevel@tonic-gate /* push the name of a transpec (the new active one) onto the stack
986*0Sstevel@tonic-gate * Arguments:
987*0Sstevel@tonic-gate * transpec name
988*0Sstevel@tonic-gate */
989*0Sstevel@tonic-gate
990*0Sstevel@tonic-gate void
PushTranspecName(Trans_t * t)991*0Sstevel@tonic-gate PushTranspecName(
992*0Sstevel@tonic-gate Trans_t *t
993*0Sstevel@tonic-gate )
994*0Sstevel@tonic-gate {
995*0Sstevel@tonic-gate if ( tsStacki >= MAXTRANSPECDEPTH ) {
996*0Sstevel@tonic-gate fprintf(stderr, "Transpec stack overflow (%d)\n", MAXTRANSPECDEPTH);
997*0Sstevel@tonic-gate exit(1);
998*0Sstevel@tonic-gate }
999*0Sstevel@tonic-gate tsStack[++tsStacki] = t;
1000*0Sstevel@tonic-gate }
1001*0Sstevel@tonic-gate
1002*0Sstevel@tonic-gate /* ______________________________________________________________________ */
1003*0Sstevel@tonic-gate /* pop the top name of a transpec off the stack
1004*0Sstevel@tonic-gate */
1005*0Sstevel@tonic-gate
1006*0Sstevel@tonic-gate void
PopTranspecName(Trans_t * t)1007*0Sstevel@tonic-gate PopTranspecName(
1008*0Sstevel@tonic-gate Trans_t *t
1009*0Sstevel@tonic-gate )
1010*0Sstevel@tonic-gate {
1011*0Sstevel@tonic-gate if ( tsStacki < 0 ) {
1012*0Sstevel@tonic-gate fprintf(stderr, "Transpec stack underflow\n");
1013*0Sstevel@tonic-gate exit(1);
1014*0Sstevel@tonic-gate }
1015*0Sstevel@tonic-gate tsStacki--;
1016*0Sstevel@tonic-gate }
1017