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 read an SGML document instance, creating any of several things:
51*0Sstevel@tonic-gate *
52*0Sstevel@tonic-gate * "translated" output for formatting applications (given a trans. spec)
53*0Sstevel@tonic-gate * validation report (given a appropriate trans spec)
54*0Sstevel@tonic-gate * tree of the document's structure
55*0Sstevel@tonic-gate * statistics about the element usage
56*0Sstevel@tonic-gate * summary of the elements used
57*0Sstevel@tonic-gate * context of each element used
58*0Sstevel@tonic-gate * IDs of each element
59*0Sstevel@tonic-gate *
60*0Sstevel@tonic-gate * A C structure is created for each element, which includes:
61*0Sstevel@tonic-gate * name, attributes, parent, children, content
62*0Sstevel@tonic-gate * The tree is descended, and the desired actions performed.
63*0Sstevel@tonic-gate *
64*0Sstevel@tonic-gate * Takes input from James Clark's "sgmls" program (v. 1.1).
65*0Sstevel@tonic-gate * ________________________________________________________________________
66*0Sstevel@tonic-gate */
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gate #ifndef lint
69*0Sstevel@tonic-gate static char *RCSid =
70*0Sstevel@tonic-gate "$Header: /usr/src/docbook-to-man/Instant/RCS/main.c,v 1.12 1998/06/28 20:10:39 fld Exp fld $";
71*0Sstevel@tonic-gate #endif
72*0Sstevel@tonic-gate
73*0Sstevel@tonic-gate #include <stdio.h>
74*0Sstevel@tonic-gate #include <stdlib.h>
75*0Sstevel@tonic-gate #include <ctype.h>
76*0Sstevel@tonic-gate #include <string.h>
77*0Sstevel@tonic-gate #include <memory.h>
78*0Sstevel@tonic-gate #include <errno.h>
79*0Sstevel@tonic-gate #include <sys/types.h>
80*0Sstevel@tonic-gate #include <sys/stat.h>
81*0Sstevel@tonic-gate #include <sys/file.h>
82*0Sstevel@tonic-gate #include <time.h>
83*0Sstevel@tonic-gate
84*0Sstevel@tonic-gate #define STORAGE
85*0Sstevel@tonic-gate #include "general.h"
86*0Sstevel@tonic-gate
87*0Sstevel@tonic-gate static int do_context, do_tree, do_summ, do_stats, do_validate, do_idlist;
88*0Sstevel@tonic-gate static int do_DATAhack = 0;
89*0Sstevel@tonic-gate static char *this_prog;
90*0Sstevel@tonic-gate static char *in_file, *out_file;
91*0Sstevel@tonic-gate static char *tranfile, *cmapfile, *sdatafile;
92*0Sstevel@tonic-gate static char *start_id;
93*0Sstevel@tonic-gate static char *last_file;
94*0Sstevel@tonic-gate static int last_lineno;
95*0Sstevel@tonic-gate
96*0Sstevel@tonic-gate extern int BOFTTextThresh;
97*0Sstevel@tonic-gate
98*0Sstevel@tonic-gate /* forward references */
99*0Sstevel@tonic-gate static void HandleArgs(int, char *[]);
100*0Sstevel@tonic-gate static void Initialize1();
101*0Sstevel@tonic-gate static void Initialize2();
102*0Sstevel@tonic-gate static void ReadInstance(char *);
103*0Sstevel@tonic-gate static void DoHelpMessage();
104*0Sstevel@tonic-gate extern void Browse();
105*0Sstevel@tonic-gate
106*0Sstevel@tonic-gate /* external reference to version number */
107*0Sstevel@tonic-gate extern char _HeadVeRsIoN_[];
108*0Sstevel@tonic-gate
109*0Sstevel@tonic-gate /* ______________________________________________________________________ */
110*0Sstevel@tonic-gate /* Program entry point. Look at args, read instance, dispatch to the
111*0Sstevel@tonic-gate * correct routines to do the work, and finish.
112*0Sstevel@tonic-gate */
113*0Sstevel@tonic-gate
114*0Sstevel@tonic-gate int
main(int ac,char * av[])115*0Sstevel@tonic-gate main(
116*0Sstevel@tonic-gate int ac,
117*0Sstevel@tonic-gate char *av[]
118*0Sstevel@tonic-gate )
119*0Sstevel@tonic-gate {
120*0Sstevel@tonic-gate Initialize1(av[0]);
121*0Sstevel@tonic-gate HandleArgs(ac, av);
122*0Sstevel@tonic-gate Initialize2();
123*0Sstevel@tonic-gate
124*0Sstevel@tonic-gate ReadInstance(in_file);
125*0Sstevel@tonic-gate
126*0Sstevel@tonic-gate if (interactive) {
127*0Sstevel@tonic-gate Browse(); /* this will handle interactive commands */
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate else {
130*0Sstevel@tonic-gate /* Perform tasks based on command line flags... */
131*0Sstevel@tonic-gate if (tranfile) {
132*0Sstevel@tonic-gate Element_t *e;
133*0Sstevel@tonic-gate /* If user wants to start at a particular ID, point to that
134*0Sstevel@tonic-gate * element. Else, point to the top of the tree. */
135*0Sstevel@tonic-gate if (start_id) {
136*0Sstevel@tonic-gate if (!(e=FindElemByID(start_id))) {
137*0Sstevel@tonic-gate fprintf(stderr, "Error: Can not find element with ID %s\n",
138*0Sstevel@tonic-gate start_id);
139*0Sstevel@tonic-gate exit(1);
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate else e = DocTree;
143*0Sstevel@tonic-gate if (sdatafile) ReadSDATA(sdatafile);
144*0Sstevel@tonic-gate if (cmapfile) ReadCharMap(cmapfile);
145*0Sstevel@tonic-gate /* If we're doing validation, make output file pointer null.
146*0Sstevel@tonic-gate * This means that we generate no output, except error messages. */
147*0Sstevel@tonic-gate if (do_validate) outfp = NULL;
148*0Sstevel@tonic-gate DoTranslate(e, tranfile, outfp);
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate if (do_summ) PrintElemSummary(DocTree);
151*0Sstevel@tonic-gate if (do_tree) PrintElemTree(DocTree);
152*0Sstevel@tonic-gate if (do_stats) PrintStats(DocTree);
153*0Sstevel@tonic-gate if (do_context) PrintContext(DocTree);
154*0Sstevel@tonic-gate if (do_idlist) PrintIDList();
155*0Sstevel@tonic-gate }
156*0Sstevel@tonic-gate if (out_file && outfp) fclose(outfp);
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gate return 0;
159*0Sstevel@tonic-gate }
160*0Sstevel@tonic-gate
161*0Sstevel@tonic-gate /* ______________________________________________________________________ */
162*0Sstevel@tonic-gate /* Initialization stuff done before dealing with args.
163*0Sstevel@tonic-gate * Arguments:
164*0Sstevel@tonic-gate * Name of program (string).
165*0Sstevel@tonic-gate */
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate static void
Initialize1(char * myname)168*0Sstevel@tonic-gate Initialize1(
169*0Sstevel@tonic-gate char *myname
170*0Sstevel@tonic-gate )
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate time_t tnow;
173*0Sstevel@tonic-gate struct tm *nowtm;
174*0Sstevel@tonic-gate char *cp, buf[100];
175*0Sstevel@tonic-gate extern int gethostname(char *, int); /* not in a system .h file... */
176*0Sstevel@tonic-gate
177*0Sstevel@tonic-gate /* where we try to find data/library files */
178*0Sstevel@tonic-gate if (!(tpt_lib=getenv(TPT_LIB))) tpt_lib = DEF_TPT_LIB;
179*0Sstevel@tonic-gate
180*0Sstevel@tonic-gate /* set some global variables */
181*0Sstevel@tonic-gate warnings = 1;
182*0Sstevel@tonic-gate fold_case = 1;
183*0Sstevel@tonic-gate this_prog = myname;
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate /* setup global variable mapping */
186*0Sstevel@tonic-gate Variables = NewMap(IMS_variables);
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate /* set some pre-defined variables */
189*0Sstevel@tonic-gate SetMappingNV(Variables, "user", (cp=getenv("USER")) ? cp : "UnknownUser" );
190*0Sstevel@tonic-gate time(&tnow);
191*0Sstevel@tonic-gate nowtm = localtime(&tnow);
192*0Sstevel@tonic-gate strftime(buf, 100, "%a %d %b %Y, %R", nowtm);
193*0Sstevel@tonic-gate SetMappingNV(Variables, "date", buf);
194*0Sstevel@tonic-gate if (gethostname(buf, 100) < 0) strcpy(buf, "unknown-host");
195*0Sstevel@tonic-gate SetMappingNV(Variables, "host", buf);
196*0Sstevel@tonic-gate SetMappingNV(Variables, "transpec", tranfile ? tranfile : "??");
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gate /* Initialization stuff done after dealing with args. */
200*0Sstevel@tonic-gate
201*0Sstevel@tonic-gate static void
Initialize2()202*0Sstevel@tonic-gate Initialize2()
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate SetMappingNV(Variables, "transpec", tranfile ? tranfile : "??");
205*0Sstevel@tonic-gate
206*0Sstevel@tonic-gate /* If user wants to send output to a file, open the file, and set
207*0Sstevel@tonic-gate * the file pointer. Else we send output to standard out. */
208*0Sstevel@tonic-gate if (out_file) {
209*0Sstevel@tonic-gate if (!(outfp = fopen(out_file, "w"))) {
210*0Sstevel@tonic-gate fprintf(stderr, "Could not open output '%s' file for writing.\n%s",
211*0Sstevel@tonic-gate out_file, strerror(errno));
212*0Sstevel@tonic-gate exit(1);
213*0Sstevel@tonic-gate }
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate else outfp = stdout;
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate
218*0Sstevel@tonic-gate /* ______________________________________________________________________ */
219*0Sstevel@tonic-gate /* Set a variable. If it is one of the "known" variables, set the
220*0Sstevel@tonic-gate * variable in the C code (this program).
221*0Sstevel@tonic-gate * Arguments:
222*0Sstevel@tonic-gate * Variable name/value string - separated by an '=' (eg, "myname=Sally").
223*0Sstevel@tonic-gate */
224*0Sstevel@tonic-gate static void
CmdLineSetVariable(char * var)225*0Sstevel@tonic-gate CmdLineSetVariable(
226*0Sstevel@tonic-gate char *var
227*0Sstevel@tonic-gate )
228*0Sstevel@tonic-gate {
229*0Sstevel@tonic-gate char *cp, buf[100], **tok;
230*0Sstevel@tonic-gate int n;
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate /* Turn '=' into a space, to isolate the name. Then set variable. */
233*0Sstevel@tonic-gate strcpy(buf, var);
234*0Sstevel@tonic-gate if ((cp=strchr(buf, '='))) {
235*0Sstevel@tonic-gate /* we have "var=value" */
236*0Sstevel@tonic-gate *cp = ' ';
237*0Sstevel@tonic-gate n = 2;
238*0Sstevel@tonic-gate tok = Split(buf, &n, 0);
239*0Sstevel@tonic-gate /* see if variable name matches one of our internal ones */
240*0Sstevel@tonic-gate if (!strcmp(tok[0], "verbose")) verbose = atoi(tok[1]);
241*0Sstevel@tonic-gate else if (!strcmp(tok[0], "warnings")) warnings = atoi(tok[1]);
242*0Sstevel@tonic-gate else if (!strcmp(tok[0], "foldcase")) fold_case = atoi(tok[1]);
243*0Sstevel@tonic-gate else SetMappingNV(Variables, tok[0], tok[1]);
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate else {
246*0Sstevel@tonic-gate fprintf(stderr, "Expected an '=' in variable assignment: %s. Ignored\n",
247*0Sstevel@tonic-gate var);
248*0Sstevel@tonic-gate }
249*0Sstevel@tonic-gate }
250*0Sstevel@tonic-gate
251*0Sstevel@tonic-gate /* ______________________________________________________________________ */
252*0Sstevel@tonic-gate /* Bounce through arguments, setting variables and flags.
253*0Sstevel@tonic-gate * Arguments:
254*0Sstevel@tonic-gate * Argc and Argv, as passed to main().
255*0Sstevel@tonic-gate */
256*0Sstevel@tonic-gate static void
HandleArgs(int ac,char * av[])257*0Sstevel@tonic-gate HandleArgs(
258*0Sstevel@tonic-gate int ac,
259*0Sstevel@tonic-gate char *av[]
260*0Sstevel@tonic-gate )
261*0Sstevel@tonic-gate {
262*0Sstevel@tonic-gate int c, errflag=0;
263*0Sstevel@tonic-gate extern char *optarg;
264*0Sstevel@tonic-gate extern int optind;
265*0Sstevel@tonic-gate
266*0Sstevel@tonic-gate while ((c=getopt(ac, av, "df:t:vc:s:o:huSxIl:bHVWi:D:Z")) != EOF) {
267*0Sstevel@tonic-gate switch (c) {
268*0Sstevel@tonic-gate case 't': tranfile = optarg; break;
269*0Sstevel@tonic-gate case 'v': do_validate = 1; break;
270*0Sstevel@tonic-gate case 's': sdatafile = optarg; break;
271*0Sstevel@tonic-gate case 'c': cmapfile = optarg; break;
272*0Sstevel@tonic-gate case 'h': do_tree = 1; break;
273*0Sstevel@tonic-gate case 'u': do_summ = 1; break;
274*0Sstevel@tonic-gate case 'S': do_stats = 1; break;
275*0Sstevel@tonic-gate case 'x': do_context = 1; break;
276*0Sstevel@tonic-gate case 'I': do_idlist = 1; break;
277*0Sstevel@tonic-gate case 'l': tpt_lib = optarg; break;
278*0Sstevel@tonic-gate case 'i': start_id = optarg; break;
279*0Sstevel@tonic-gate case 'o': out_file = optarg; break;
280*0Sstevel@tonic-gate case 'd': do_DATAhack = 1; break;
281*0Sstevel@tonic-gate case 'f': BOFTTextThresh = atoi(optarg); break;
282*0Sstevel@tonic-gate case 'b': interactive = 1; break;
283*0Sstevel@tonic-gate case 'W': warnings = 0; break;
284*0Sstevel@tonic-gate case 'V': verbose = 1; break;
285*0Sstevel@tonic-gate case 'Z': slave = 1; break;
286*0Sstevel@tonic-gate case 'H': DoHelpMessage(); exit(0); break;
287*0Sstevel@tonic-gate case 'D': CmdLineSetVariable(optarg); break;
288*0Sstevel@tonic-gate case '?': errflag = 1; break;
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate if (errflag) {
291*0Sstevel@tonic-gate fprintf(stderr, "Try '%s -H' for help.\n", this_prog);
292*0Sstevel@tonic-gate exit(1);
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate }
295*0Sstevel@tonic-gate
296*0Sstevel@tonic-gate /* input (ESIS) file name */
297*0Sstevel@tonic-gate if (optind < ac) in_file = av[optind];
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate /* If doing interactive/browsing, we can't take ESIS from stdin. */
300*0Sstevel@tonic-gate if (interactive && !in_file) {
301*0Sstevel@tonic-gate fprintf(stderr,
302*0Sstevel@tonic-gate "You must specify ESIS file on cmd line for browser mode.\n");
303*0Sstevel@tonic-gate exit(1);
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate /* ______________________________________________________________________ */
308*0Sstevel@tonic-gate /* Simply print out a help/usage message.
309*0Sstevel@tonic-gate */
310*0Sstevel@tonic-gate
311*0Sstevel@tonic-gate static char *help_msg[] = {
312*0Sstevel@tonic-gate "",
313*0Sstevel@tonic-gate " -t file Print translated output using translation spec in <file>",
314*0Sstevel@tonic-gate " -s file <file> contains a list of SDATA entity mappings",
315*0Sstevel@tonic-gate " -c file <file> contains a list of character mappings",
316*0Sstevel@tonic-gate " -v Validate using translation spec specified with -t",
317*0Sstevel@tonic-gate " -i id Consider only subtree starting at element with ID <id>",
318*0Sstevel@tonic-gate " -b Interactive browser",
319*0Sstevel@tonic-gate " -S Print statistics (how often elements occur, etc.)",
320*0Sstevel@tonic-gate " -u Print element usage summary (# of children, depth, etc.)",
321*0Sstevel@tonic-gate " -x Print context of each element",
322*0Sstevel@tonic-gate " -h Print document hierarchy as a tree",
323*0Sstevel@tonic-gate " -o file Write output to <file>. Default is standard output.",
324*0Sstevel@tonic-gate " -l dir Set library directory to <dir>. (or env. variable TPT_LIB)",
325*0Sstevel@tonic-gate " -I List all IDs used in the instance",
326*0Sstevel@tonic-gate " -W Do not print warning messages",
327*0Sstevel@tonic-gate " -H Print this help message",
328*0Sstevel@tonic-gate " -Dvar=val Set variable 'var' to value 'val'",
329*0Sstevel@tonic-gate " file Take input from named file. If not specified, assume stdin.",
330*0Sstevel@tonic-gate " File should be output from the 'sgmls' program (ESIS).",
331*0Sstevel@tonic-gate NULL
332*0Sstevel@tonic-gate };
333*0Sstevel@tonic-gate
334*0Sstevel@tonic-gate static void
DoHelpMessage()335*0Sstevel@tonic-gate DoHelpMessage()
336*0Sstevel@tonic-gate {
337*0Sstevel@tonic-gate char **s = help_msg;
338*0Sstevel@tonic-gate printf("usage: %s [option ...] [file]", this_prog);
339*0Sstevel@tonic-gate while (*s) puts(*s++);
340*0Sstevel@tonic-gate printf("\nVersion: %s\n", _HeadVeRsIoN_);
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate
343*0Sstevel@tonic-gate /* ______________________________________________________________________ */
344*0Sstevel@tonic-gate /* Remember an external entity for future reference.
345*0Sstevel@tonic-gate * Arguments:
346*0Sstevel@tonic-gate * Pointer to entity structure to remember.
347*0Sstevel@tonic-gate */
348*0Sstevel@tonic-gate
349*0Sstevel@tonic-gate static void
AddEntity(Entity_t * ent)350*0Sstevel@tonic-gate AddEntity(
351*0Sstevel@tonic-gate Entity_t *ent
352*0Sstevel@tonic-gate )
353*0Sstevel@tonic-gate {
354*0Sstevel@tonic-gate static Entity_t *last_ent;
355*0Sstevel@tonic-gate
356*0Sstevel@tonic-gate if (!Entities) {
357*0Sstevel@tonic-gate Malloc(1, Entities, Entity_t);
358*0Sstevel@tonic-gate last_ent = Entities;
359*0Sstevel@tonic-gate }
360*0Sstevel@tonic-gate else {
361*0Sstevel@tonic-gate Malloc(1, last_ent->next, Entity_t);
362*0Sstevel@tonic-gate last_ent = last_ent->next;
363*0Sstevel@tonic-gate }
364*0Sstevel@tonic-gate *last_ent = *ent;
365*0Sstevel@tonic-gate
366*0Sstevel@tonic-gate }
367*0Sstevel@tonic-gate
368*0Sstevel@tonic-gate /* Find an entity, given its entity name.
369*0Sstevel@tonic-gate * Arguments:
370*0Sstevel@tonic-gate * Name of entity to retrieve.
371*0Sstevel@tonic-gate */
372*0Sstevel@tonic-gate Entity_t *
FindEntity(char * ename)373*0Sstevel@tonic-gate FindEntity(
374*0Sstevel@tonic-gate char *ename
375*0Sstevel@tonic-gate )
376*0Sstevel@tonic-gate {
377*0Sstevel@tonic-gate Entity_t *n;
378*0Sstevel@tonic-gate for (n=Entities; n; n=n->next)
379*0Sstevel@tonic-gate if (StrEq(ename, n->ename)) return n;
380*0Sstevel@tonic-gate return 0;
381*0Sstevel@tonic-gate }
382*0Sstevel@tonic-gate
383*0Sstevel@tonic-gate /* Accumulate lines up to the open tag. Attributes, line number,
384*0Sstevel@tonic-gate * entity info, notation info, etc., all come before the open tag.
385*0Sstevel@tonic-gate */
386*0Sstevel@tonic-gate static Element_t *
AccumElemInfo(FILE * fp)387*0Sstevel@tonic-gate AccumElemInfo(
388*0Sstevel@tonic-gate FILE *fp
389*0Sstevel@tonic-gate )
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate char buf[LINESIZE+1];
392*0Sstevel@tonic-gate int c;
393*0Sstevel@tonic-gate int i, na;
394*0Sstevel@tonic-gate char *cp, *atval;
395*0Sstevel@tonic-gate Mapping_t a[100];
396*0Sstevel@tonic-gate Element_t *e;
397*0Sstevel@tonic-gate Entity_t ent, *ent2;
398*0Sstevel@tonic-gate char **tok;
399*0Sstevel@tonic-gate static int Index=0;
400*0Sstevel@tonic-gate static Element_t *last_e;
401*0Sstevel@tonic-gate
402*0Sstevel@tonic-gate
403*0Sstevel@tonic-gate Calloc(1, e, Element_t);
404*0Sstevel@tonic-gate memset(&ent, 0, sizeof ent); /* clean space for entity info */
405*0Sstevel@tonic-gate
406*0Sstevel@tonic-gate /* Also, keep a linked list of elements, so we can easily scan through */
407*0Sstevel@tonic-gate if (last_e) last_e->next = e;
408*0Sstevel@tonic-gate last_e = e;
409*0Sstevel@tonic-gate
410*0Sstevel@tonic-gate e->index = Index++; /* just a unique number for identification */
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gate /* in case these are not set for this element in the ESIS */
413*0Sstevel@tonic-gate e->lineno = last_lineno;
414*0Sstevel@tonic-gate e->infile = last_file;
415*0Sstevel@tonic-gate
416*0Sstevel@tonic-gate na = 0;
417*0Sstevel@tonic-gate while (1) {
418*0Sstevel@tonic-gate if ((c = getc(fp)) == EOF) break;
419*0Sstevel@tonic-gate fgets(buf, LINESIZE, fp);
420*0Sstevel@tonic-gate stripNL(buf);
421*0Sstevel@tonic-gate switch (c) {
422*0Sstevel@tonic-gate case EOF: /* End of input */
423*0Sstevel@tonic-gate fprintf(stderr, "Error: Unexpectedly reached end of ESIS.\n");
424*0Sstevel@tonic-gate exit(1);
425*0Sstevel@tonic-gate break;
426*0Sstevel@tonic-gate
427*0Sstevel@tonic-gate case CMD_OPEN: /* (gi */
428*0Sstevel@tonic-gate e->gi = AddElemName(buf);
429*0Sstevel@tonic-gate if (na > 0) {
430*0Sstevel@tonic-gate Malloc(na, e->atts, Mapping_t);
431*0Sstevel@tonic-gate memcpy(e->atts, a, na*sizeof(Mapping_t));
432*0Sstevel@tonic-gate e->natts = na;
433*0Sstevel@tonic-gate na = 0;
434*0Sstevel@tonic-gate }
435*0Sstevel@tonic-gate /* Check if this elem has a notation attr. If yes, and there
436*0Sstevel@tonic-gate is no notation specified, recall the previous one. (feature
437*0Sstevel@tonic-gate of sgmls - it does not repeat notation stuff if we the same
438*0Sstevel@tonic-gate is used twice in a row) */
439*0Sstevel@tonic-gate if (((atval=FindAttValByName(e, "NAME")) ||
440*0Sstevel@tonic-gate (atval=FindAttValByName(e, "ENTITYREF")) ||
441*0Sstevel@tonic-gate (atval=FindAttValByName(e, "EXTERNAL"))) && /* HACK */
442*0Sstevel@tonic-gate (ent2=FindEntity(atval))) {
443*0Sstevel@tonic-gate e->entity = ent2;
444*0Sstevel@tonic-gate }
445*0Sstevel@tonic-gate
446*0Sstevel@tonic-gate return e;
447*0Sstevel@tonic-gate break;
448*0Sstevel@tonic-gate
449*0Sstevel@tonic-gate case CMD_ATT: /* Aname val */
450*0Sstevel@tonic-gate i = 3;
451*0Sstevel@tonic-gate tok = Split(buf, &i, 0);
452*0Sstevel@tonic-gate if (!strcmp(tok[1], "IMPLIED")) break; /* skip IMPLIED atts. */
453*0Sstevel@tonic-gate if (!strcmp(tok[1], "CDATA") || !strcmp(tok[1], "TOKEN") ||
454*0Sstevel@tonic-gate !strcmp(tok[1], "ENTITY") ||!strcmp(tok[1], "NOTATION"))
455*0Sstevel@tonic-gate {
456*0Sstevel@tonic-gate a[na].name = AddAttName(tok[0]);
457*0Sstevel@tonic-gate a[na].sval = AddAttName(tok[2]);
458*0Sstevel@tonic-gate na++;
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate else {
461*0Sstevel@tonic-gate fprintf(stderr, "Error: Bad attr line (%d): A%s %s...\n",
462*0Sstevel@tonic-gate e->lineno, tok[0], tok[1]);
463*0Sstevel@tonic-gate }
464*0Sstevel@tonic-gate break;
465*0Sstevel@tonic-gate
466*0Sstevel@tonic-gate case CMD_LINE: /* Llineno */
467*0Sstevel@tonic-gate /* These lines come in 2 forms: "L123" and "L123 file.sgml".
468*0Sstevel@tonic-gate * Filename is given only at 1st occurance. Remember it.
469*0Sstevel@tonic-gate */
470*0Sstevel@tonic-gate if ((cp = strchr(buf, ' '))) {
471*0Sstevel@tonic-gate cp++;
472*0Sstevel@tonic-gate last_file = strdup(cp);
473*0Sstevel@tonic-gate }
474*0Sstevel@tonic-gate last_lineno = e->lineno = atoi(buf);
475*0Sstevel@tonic-gate e->infile = last_file;
476*0Sstevel@tonic-gate break;
477*0Sstevel@tonic-gate
478*0Sstevel@tonic-gate case CMD_DATA: /* -data */
479*0Sstevel@tonic-gate fprintf(stderr, "Error: Data in AccumElemInfo, line %d:\n%c%s\n",
480*0Sstevel@tonic-gate e->lineno, c,buf);
481*0Sstevel@tonic-gate /*return e;*/
482*0Sstevel@tonic-gate exit(1);
483*0Sstevel@tonic-gate break;
484*0Sstevel@tonic-gate
485*0Sstevel@tonic-gate case CMD_D_ATT: /* Dename name val */
486*0Sstevel@tonic-gate
487*0Sstevel@tonic-gate case CMD_NOTATION: /* Nnname */
488*0Sstevel@tonic-gate case CMD_PI: /* ?pi */
489*0Sstevel@tonic-gate /* This should be reworked soon, as it
490*0Sstevel@tonic-gate forces all PI's before the first GI
491*0Sstevel@tonic-gate to be ignored. -CSS */
492*0Sstevel@tonic-gate break;
493*0Sstevel@tonic-gate
494*0Sstevel@tonic-gate case CMD_EXT_ENT: /* Eename typ nname */
495*0Sstevel@tonic-gate i = 3;
496*0Sstevel@tonic-gate tok = Split(buf, &i, 0);
497*0Sstevel@tonic-gate ent.ename = strdup(tok[0]);
498*0Sstevel@tonic-gate ent.type = strdup(tok[1]);
499*0Sstevel@tonic-gate ent.nname = strdup(tok[2]);
500*0Sstevel@tonic-gate AddEntity(&ent);
501*0Sstevel@tonic-gate break;
502*0Sstevel@tonic-gate case CMD_INT_ENT: /* Iename typ text */
503*0Sstevel@tonic-gate fprintf(stderr, "Error: Got CMD_INT_ENT in AccumElemInfo: %s\n", buf);
504*0Sstevel@tonic-gate break;
505*0Sstevel@tonic-gate case CMD_SYSID: /* ssysid */
506*0Sstevel@tonic-gate ent.sysid = strdup(buf);
507*0Sstevel@tonic-gate break;
508*0Sstevel@tonic-gate case CMD_PUBID: /* ppubid */
509*0Sstevel@tonic-gate ent.pubid = strdup(buf);
510*0Sstevel@tonic-gate break;
511*0Sstevel@tonic-gate case CMD_FILENAME: /* ffilename */
512*0Sstevel@tonic-gate ent.fname = strdup(buf);
513*0Sstevel@tonic-gate break;
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate case CMD_CLOSE: /* )gi */
516*0Sstevel@tonic-gate case CMD_SUBDOC: /* Sename */
517*0Sstevel@tonic-gate case CMD_SUBDOC_S: /* {ename */
518*0Sstevel@tonic-gate case CMD_SUBDOC_E: /* }ename */
519*0Sstevel@tonic-gate case CMD_EXT_REF: /* &name */
520*0Sstevel@tonic-gate case CMD_APPINFO: /* #text */
521*0Sstevel@tonic-gate case CMD_CONFORM: /* C */
522*0Sstevel@tonic-gate default:
523*0Sstevel@tonic-gate fprintf(stderr, "Error: Unexpected input in AccumElemInfo, %d:\n%c%s\n",
524*0Sstevel@tonic-gate e->lineno, c,buf);
525*0Sstevel@tonic-gate exit(1);
526*0Sstevel@tonic-gate break;
527*0Sstevel@tonic-gate }
528*0Sstevel@tonic-gate }
529*0Sstevel@tonic-gate if ( e && e->gi )
530*0Sstevel@tonic-gate fprintf(stderr, "Error: End of AccumElemInfo - should not be here: %s\n", e->gi);
531*0Sstevel@tonic-gate else
532*0Sstevel@tonic-gate fprintf(stderr, "Invalid SGML. File cannot be formatted\n");
533*0Sstevel@tonic-gate /* return e;*/
534*0Sstevel@tonic-gate exit(1);
535*0Sstevel@tonic-gate }
536*0Sstevel@tonic-gate
537*0Sstevel@tonic-gate /* Read ESIS lines.
538*0Sstevel@tonic-gate */
539*0Sstevel@tonic-gate
540*0Sstevel@tonic-gate #define BASECONTSIZE 500 /* starting size for number of children */
541*0Sstevel@tonic-gate #define GROWCONTSIZE 500 /* if we need to grow that, by this much */
542*0Sstevel@tonic-gate
543*0Sstevel@tonic-gate static Element_t *
ReadESIS(FILE * fp,int depth)544*0Sstevel@tonic-gate ReadESIS(
545*0Sstevel@tonic-gate FILE *fp,
546*0Sstevel@tonic-gate int depth
547*0Sstevel@tonic-gate )
548*0Sstevel@tonic-gate {
549*0Sstevel@tonic-gate char *buf;
550*0Sstevel@tonic-gate int i, c, ncont, contsize;
551*0Sstevel@tonic-gate Element_t *e;
552*0Sstevel@tonic-gate Content_t *cont;
553*0Sstevel@tonic-gate
554*0Sstevel@tonic-gate Malloc( LINESIZE+1, buf, char );
555*0Sstevel@tonic-gate contsize = BASECONTSIZE; /* starting content size */
556*0Sstevel@tonic-gate Malloc( contsize, cont, Content_t );
557*0Sstevel@tonic-gate
558*0Sstevel@tonic-gate /* Read input stream - the output of "sgmls", called "ESIS". */
559*0Sstevel@tonic-gate e = AccumElemInfo(fp);
560*0Sstevel@tonic-gate e->depth = depth;
561*0Sstevel@tonic-gate
562*0Sstevel@tonic-gate ncont = 0;
563*0Sstevel@tonic-gate while (1) {
564*0Sstevel@tonic-gate if ((c = getc(fp)) == EOF) break;
565*0Sstevel@tonic-gate if ( ncont >= contsize ) {
566*0Sstevel@tonic-gate contsize += GROWCONTSIZE;
567*0Sstevel@tonic-gate Realloc( contsize, cont, Content_t );
568*0Sstevel@tonic-gate }
569*0Sstevel@tonic-gate
570*0Sstevel@tonic-gate switch (c) {
571*0Sstevel@tonic-gate case EOF: /* End of input */
572*0Sstevel@tonic-gate break;
573*0Sstevel@tonic-gate
574*0Sstevel@tonic-gate case CMD_DATA: /* -data */
575*0Sstevel@tonic-gate fgets(buf, LINESIZE, fp);
576*0Sstevel@tonic-gate stripNL(buf);
577*0Sstevel@tonic-gate if (do_DATAhack && (buf[0] == '\\') && (buf[1] == 'n') ) {
578*0Sstevel@tonic-gate buf[0] = -1; /* simulate "^" command */
579*0Sstevel@tonic-gate memcpy(&buf[1], &buf[2], strlen(buf)-1);
580*0Sstevel@tonic-gate }
581*0Sstevel@tonic-gate cont[ncont].ch.data = strdup(buf);
582*0Sstevel@tonic-gate cont[ncont].type = CMD_DATA;
583*0Sstevel@tonic-gate ncont++;
584*0Sstevel@tonic-gate break;
585*0Sstevel@tonic-gate
586*0Sstevel@tonic-gate case CMD_PI: /* ?pi */
587*0Sstevel@tonic-gate fgets(buf, LINESIZE, fp);
588*0Sstevel@tonic-gate stripNL(buf);
589*0Sstevel@tonic-gate cont[ncont].type = CMD_PI;
590*0Sstevel@tonic-gate cont[ncont].ch.data = strdup(buf);
591*0Sstevel@tonic-gate ncont++;
592*0Sstevel@tonic-gate break;
593*0Sstevel@tonic-gate
594*0Sstevel@tonic-gate case CMD_CLOSE: /* )gi */
595*0Sstevel@tonic-gate fgets(buf, LINESIZE, fp);
596*0Sstevel@tonic-gate stripNL(buf);
597*0Sstevel@tonic-gate if (ncont) {
598*0Sstevel@tonic-gate e->ncont = ncont;
599*0Sstevel@tonic-gate Malloc(ncont, e->cont, Content_t);
600*0Sstevel@tonic-gate for (i=0; i<ncont; i++) e->cont[i] = cont[i];
601*0Sstevel@tonic-gate }
602*0Sstevel@tonic-gate free(buf);
603*0Sstevel@tonic-gate free(cont);
604*0Sstevel@tonic-gate return e;
605*0Sstevel@tonic-gate break;
606*0Sstevel@tonic-gate
607*0Sstevel@tonic-gate case CMD_OPEN: /* (gi */
608*0Sstevel@tonic-gate /*fprintf(stderr, "+++++ OPEN +++\n");*/
609*0Sstevel@tonic-gate /* break;*/
610*0Sstevel@tonic-gate
611*0Sstevel@tonic-gate case CMD_ATT: /* Aname val */
612*0Sstevel@tonic-gate case CMD_D_ATT: /* Dename name val */
613*0Sstevel@tonic-gate case CMD_NOTATION: /* Nnname */
614*0Sstevel@tonic-gate case CMD_EXT_ENT: /* Eename typ nname */
615*0Sstevel@tonic-gate case CMD_INT_ENT: /* Iename typ text */
616*0Sstevel@tonic-gate case CMD_SYSID: /* ssysid */
617*0Sstevel@tonic-gate case CMD_PUBID: /* ppubid */
618*0Sstevel@tonic-gate case CMD_FILENAME: /* ffilename */
619*0Sstevel@tonic-gate ungetc(c, fp);
620*0Sstevel@tonic-gate cont[ncont].ch.elem = ReadESIS(fp, depth+1);
621*0Sstevel@tonic-gate cont[ncont].type = CMD_OPEN;
622*0Sstevel@tonic-gate cont[ncont].ch.elem->parent = e;
623*0Sstevel@tonic-gate ncont++;
624*0Sstevel@tonic-gate break;
625*0Sstevel@tonic-gate
626*0Sstevel@tonic-gate case CMD_LINE: /* Llineno */
627*0Sstevel@tonic-gate fgets(buf, LINESIZE, fp);
628*0Sstevel@tonic-gate break; /* ignore these here */
629*0Sstevel@tonic-gate
630*0Sstevel@tonic-gate case CMD_SUBDOC: /* Sename */
631*0Sstevel@tonic-gate case CMD_SUBDOC_S: /* {ename */
632*0Sstevel@tonic-gate case CMD_SUBDOC_E: /* }ename */
633*0Sstevel@tonic-gate case CMD_EXT_REF: /* &name */
634*0Sstevel@tonic-gate case CMD_APPINFO: /* #text */
635*0Sstevel@tonic-gate case CMD_CONFORM: /* C */
636*0Sstevel@tonic-gate default:
637*0Sstevel@tonic-gate fgets(buf, LINESIZE, fp);
638*0Sstevel@tonic-gate fprintf(stderr, "Error: Unexpected input at %d: '%c%s'\n",
639*0Sstevel@tonic-gate e->lineno, c, buf);
640*0Sstevel@tonic-gate exit(1);
641*0Sstevel@tonic-gate break;
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate }
644*0Sstevel@tonic-gate if( e && e->gi)
645*0Sstevel@tonic-gate fprintf(stderr, "Error: End of ReadESIS - should not be here: %s\n", e->gi);
646*0Sstevel@tonic-gate else
647*0Sstevel@tonic-gate fprintf(stderr, "Error: Invalid SGML: End of ReadESIS - should not be here:\n");
648*0Sstevel@tonic-gate
649*0Sstevel@tonic-gate free(buf);
650*0Sstevel@tonic-gate free(cont);
651*0Sstevel@tonic-gate return NULL;
652*0Sstevel@tonic-gate }
653*0Sstevel@tonic-gate
654*0Sstevel@tonic-gate /* ______________________________________________________________________ */
655*0Sstevel@tonic-gate /* Read input stream, creating a tree in memory of the elements and data.
656*0Sstevel@tonic-gate * Arguments:
657*0Sstevel@tonic-gate * Filename where instance's ESIS is.
658*0Sstevel@tonic-gate */
659*0Sstevel@tonic-gate static void
ReadInstance(char * filename)660*0Sstevel@tonic-gate ReadInstance(
661*0Sstevel@tonic-gate char *filename
662*0Sstevel@tonic-gate )
663*0Sstevel@tonic-gate {
664*0Sstevel@tonic-gate int i, n;
665*0Sstevel@tonic-gate FILE *fp;
666*0Sstevel@tonic-gate Element_t *e;
667*0Sstevel@tonic-gate char *idatt;
668*0Sstevel@tonic-gate
669*0Sstevel@tonic-gate if (filename) { /* if we specified input file. else stdin */
670*0Sstevel@tonic-gate if ((fp=fopen(filename, "r")) == NULL) {
671*0Sstevel@tonic-gate perror(filename);
672*0Sstevel@tonic-gate exit(1);
673*0Sstevel@tonic-gate }
674*0Sstevel@tonic-gate }
675*0Sstevel@tonic-gate else fp = stdin;
676*0Sstevel@tonic-gate last_file = filename;
677*0Sstevel@tonic-gate DocTree = ReadESIS(fp, 0);
678*0Sstevel@tonic-gate if (filename) fclose(fp);
679*0Sstevel@tonic-gate
680*0Sstevel@tonic-gate /* Traverse tree, filling in econt and figuring out which child
681*0Sstevel@tonic-gate * (ie. what birth order) each element is. */
682*0Sstevel@tonic-gate DocTree->my_eorder = -1;
683*0Sstevel@tonic-gate for (e=DocTree; e; e=e->next) {
684*0Sstevel@tonic-gate
685*0Sstevel@tonic-gate /* count element children */
686*0Sstevel@tonic-gate for (i=0,n=0; i<e->ncont; i++) if (IsContElem(e,i)) n++;
687*0Sstevel@tonic-gate if (n > 0) Calloc(n, e->econt, Element_t *);
688*0Sstevel@tonic-gate for (i=0; i<e->ncont; i++)
689*0Sstevel@tonic-gate if (IsContElem(e,i)) e->econt[e->necont++] = ContElem(e,i);
690*0Sstevel@tonic-gate
691*0Sstevel@tonic-gate /* count data children */
692*0Sstevel@tonic-gate for (i=0,n=0; i<e->ncont; i++) if (IsContData(e,i)) n++;
693*0Sstevel@tonic-gate if (n > 0) Calloc(n, e->dcont, char *);
694*0Sstevel@tonic-gate for (i=0; i<e->ncont; i++)
695*0Sstevel@tonic-gate if (IsContData(e,i)) e->dcont[e->ndcont++] = ContData(e,i);
696*0Sstevel@tonic-gate
697*0Sstevel@tonic-gate /* where in child order order */
698*0Sstevel@tonic-gate for (i=0; i<e->necont; i++)
699*0Sstevel@tonic-gate e->econt[i]->my_eorder = i;
700*0Sstevel@tonic-gate
701*0Sstevel@tonic-gate /* Does this element have an ID? */
702*0Sstevel@tonic-gate for (i=0; i<e->natts; i++) {
703*0Sstevel@tonic-gate if ((idatt=FindAttValByName(e, "ID"))) {
704*0Sstevel@tonic-gate AddID(e, idatt);
705*0Sstevel@tonic-gate /* remember ID value for quick reference */
706*0Sstevel@tonic-gate e->id = idatt;
707*0Sstevel@tonic-gate break;
708*0Sstevel@tonic-gate }
709*0Sstevel@tonic-gate }
710*0Sstevel@tonic-gate }
711*0Sstevel@tonic-gate return;
712*0Sstevel@tonic-gate }
713*0Sstevel@tonic-gate
714*0Sstevel@tonic-gate /* ______________________________________________________________________ */
715