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