1 /*
2  *  Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
3  *  All rights reserved.
4  */
5 /*
6  * Copyright (c) 1994
7  * Open Software Foundation, Inc.
8  *
9  * Permission is hereby granted to use, copy, modify and freely distribute
10  * the software in this file and its documentation for any purpose without
11  * fee, provided that the above copyright notice appears in all copies and
12  * that both the copyright notice and this permission notice appear in
13  * supporting documentation.  Further, provided that the name of Open
14  * Software Foundation, Inc. ("OSF") not be used in advertising or
15  * publicity pertaining to distribution of the software without prior
16  * written permission from OSF.  OSF makes no representations about the
17  * suitability of this software for any purpose.  It is provided "as is"
18  * without express or implied warranty.
19  */
20 /*
21  * Copyright (c) 1996 X Consortium
22  * Copyright (c) 1995, 1996 Dalrymple Consulting
23  *
24  * Permission is hereby granted, free of charge, to any person obtaining a copy
25  * of this software and associated documentation files (the "Software"), to deal
26  * in the Software without restriction, including without limitation the rights
27  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28  * copies of the Software, and to permit persons to whom the Software is
29  * furnished to do so, subject to the following conditions:
30  *
31  * The above copyright notice and this permission notice shall be included in
32  * all copies or substantial portions of the Software.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
37  * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
38  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
39  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
40  * OTHER DEALINGS IN THE SOFTWARE.
41  *
42  * Except as contained in this notice, the names of the X Consortium and
43  * Dalrymple Consulting shall not be used in advertising or otherwise to
44  * promote the sale, use or other dealings in this Software without prior
45  * written authorization.
46  */
47 
48 /* ________________________________________________________________________
49  *
50  *  Module for interactive browsing.
51  *
52  *  Entry points for this module:
53  *	Browse()		interactive browser
54  * ________________________________________________________________________
55  */
56 
57 #ifndef lint
58 static char *RCSid =
59   "$Header: /home/ncvs/src/usr.bin/sgmls/instant/browse.c,v 1.1.1.1 1996/09/08 01:55:10 jfieber Exp $";
60 #endif
61 
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <ctype.h>
65 #include <string.h>
66 
67 #include "general.h"
68 
69 static void	PrElemPlusID(Element_t *);
70 static void	ls_node(Element_t *, int, char **);
71 static void	do_query(Element_t *, char *, char *);
72 static void	do_find(Element_t *, char **);
73 
74 /* ______________________________________________________________________ */
75 
76 static char *br_help_msg[] = {
77   "  ls            List info about current element in tree",
78   "                (context, children, attributes, etc.)",
79   "  cd N ...      Change to Nth elememt child, where N is shown by 'ls'.",
80   "                N may also be '/' (top) or '..' (up).",
81   "  cd id I       Change to elememt whose ID is I",
82   "  data N        Show data of Nth data node",
83   "  where         Show current position in the tree",
84   "  id I          Show path to element with id I",
85   "                (using '?' for I will lists all IDs and their paths)",
86   "  find S        Find elements matching spec S. Recognized syntaxes:",
87   "                  find attr <name> <value>",
88   "                  find cont <string>",
89   "                  find parent <gi-name>",
90   "                  find child <gi-name>",
91   "                  find gi <gi-name>",
92   "  q rel gi      Query: report if elem 'gi' has relation to current elem",
93   "                ('rel' is one of 'child parent ancestor descendant",
94   "                  sibling sibling+ sibling+1 sibling- sibling-1 cousin')",
95   "",
96   "  tran [outfile]",
97   "                Translate into 'outfile' (stdout)",
98   "  stat          Print statistics (how often elements occur, etc.)",
99   "  sum           Print elem usage summary (# of children, depth, etc.)",
100   "  tree          Print document hierarchy as a tree",
101   "  cont          Print context of each element",
102   NULL
103 };
104 
105 /* ______________________________________________________________________ */
106 
107 void
Browse()108 Browse()
109 {
110     char	buf[256], *cmd, **av, **sv;
111     char	*Prompt;
112     Element_t	*ce;	/* current element */
113     Element_t	*e;
114     int		i, n, ac;
115 
116     if (slave) Prompt = "=>\n";
117     else Prompt = "=> ";
118 
119     ce = DocTree;
120     while (fputs(Prompt, stdout)) {
121 	if (!fgets(buf, 256, stdin)) break;
122 	stripNL(buf);
123 	if (buf[0] == EOS) {
124 	    fputs(Prompt, stdout);
125 	    continue;
126 	}
127 	ac = 20;
128 	av = Split(buf, &ac, S_ALVEC);
129 	if (ac > 0) cmd = av[0];
130 	if (!cmd || !(*cmd)) continue;
131 
132 	if (!strcmp(cmd, "ls")) ls_node(ce, ac, av);
133 
134 	else if (!strcmp(cmd, "cd")) {
135 	    if (av[1]) {
136 		if (ac == 3 && !strcmp(av[1], "id")) {
137 		    if ((e = FindElemByID(av[2]))) ce = e;
138 		    else printf("Element with ID '%s' not found.\n", av[2]);
139 		    continue;
140 		}
141 		for (i=1; i<ac; i++) {
142 		    if (!strcmp(av[i], "..")) {
143 			if (ce->parent) ce = ce->parent;
144 			continue;
145 		    }
146 		    if (!strcmp(av[i], "/")) {
147 			if (ce->parent) ce = DocTree;
148 			continue;
149 		    }
150 		    if (!isdigit(*av[i])) {
151 			printf("Expecting digit, '..', or '/', got '%s'.\n",
152 				    av[i]);
153 			break;
154 		    }
155 		    n = atoi(av[i]);
156 		    if (n < ce->necont) ce = ce->econt[n];
157 		    else {
158 			printf("Must be in range 0 - %d.\n", ce->necont);
159 			break;
160 		    }
161 		}
162 	    }
163 	}
164 
165 	else if (!strcmp(cmd, "data")) {
166 	    if (av[1] && isdigit(*av[1])) {
167 		n = atoi(av[1]);
168 		if (n < ce->ndcont) {
169 		    printf(ce->dcont[n]);
170 		    fputs("\n", stdout);
171 		}
172 		else if (ce->ndcont == 0)
173 		    printf("No data at this node.\n");
174 		else printf("Must be in range 0 - %d.\n", ce->ndcont);
175 	    }
176 	}
177 
178 	/* show where we are in the tree */
179 	else if (!strcmp(cmd, "where")) PrintLocation(ce, stdout);
180 
181 	/* show where we are in the tree */
182 	else if (!strcmp(cmd, "pwd")) PrElemPlusID(ce);
183 
184 	/* perform query with yes/no answer */
185 	else if (!strcmp(cmd, "q") && av[1] && av[2])
186 	    do_query(ce, av[1], av[2]);
187 
188 	/* perform query printing paths to matching elements */
189 	else if (!strcmp(cmd, "find") && av[1] && av[2])
190 	    do_find(ce, av);
191 
192 	/* list locations where specified ID(s) occur */
193 	else if (!strcmp(cmd, "id")) {
194 	    if (ac <= 1) continue;
195 	    if (*av[1] == '?') PrintIDList();
196 	    else {
197 		/* short: "id i1 i2 ...", long: "id -l i1 i2 ..." */
198 		if (!strcmp(av[1], "-l")) n = 2;
199 		else n = 1;
200 		for (i=n; i<ac; i++) {
201 		    if ((e = FindElemByID(av[i]))) {
202 			if (n == 2) {	/* long (multiline) format */
203 			    if (n != i) putchar('\n');
204 			    PrintLocation(e, stdout);
205 			}
206 			else PrElemPlusID(e);
207 		    }
208 		    else printf("Element with ID '%s' not found.\n", av[i]);
209 		}
210 	    }
211 	}
212 
213 	/* show and set variables */
214 	else if (!strcmp(cmd, "show") && av[1]) {
215 	    printf("%s\n", FindMappingVal(Variables, av[1]));
216 	}
217 	else if (!strcmp(cmd, "set") && av[1] && av[2]) {
218 	    SetMappingNV(Variables, av[1], av[2]);
219 	}
220 
221 	/* print summary of tag usage */
222 	else if (!strcmp(cmd, "sum")) {
223 	    if (ac > 1) PrintElemSummary(ce);
224 	    else PrintElemSummary(DocTree);
225 	}
226 	/* print element tree */
227 	else if (!strcmp(cmd, "tree")) {
228 	    if (ac > 1) PrintElemTree(ce);
229 	    else PrintElemTree(DocTree);
230 	}
231 	/* print statistics */
232 	else if (!strcmp(cmd, "stat")) {
233 	    if (ac > 1) PrintStats(ce);
234 	    else PrintStats(DocTree);
235 	}
236 	/* print context of each element of tree */
237 	else if (!strcmp(cmd, "cont")) {
238 	    if (ac > 1) PrintContext(ce);
239 	    else PrintContext(DocTree);
240 	}
241 	/* print translation, given transpec */
242 	else if (!strcmp(cmd, "tran")) {
243 	    FILE *fp;
244 	    if (ac > 1){
245 		if (!(fp = fopen(av[1], "w"))) {
246 		    perror("Can not open output file");
247 		    continue;
248 		}
249 	    }
250 	    else fp = stdout;
251 	    DoTranslate(ce, fp);
252 	    if (ac > 1) fclose(fp);
253 	}
254 
255 	else if (!strcmp(cmd, "help") || *cmd == '?') {
256 	    sv = br_help_msg;
257 	    while (*sv) puts(*sv++);
258 	}
259 
260 	/* quit (control-D also works) */
261 	else if (!strcmp(cmd, "quit")) break;
262 
263 	else
264 	    fprintf(stderr, "Unknown command '%s' - ingored.\n", cmd);
265     }
266     putc(NL, stdout);
267 }
268 
269 /* ______________________________________________________________________ */
270 /*  Do the "ls" command.
271  *  Arguments:
272  *	Pointer to element under consideration.
273  *	Arg count from command line (this command, not the shell command).
274  *	Arg vector.
275  */
276 
277 static void
ls_node(Element_t * e,int ac,char ** av)278 ls_node(
279     Element_t	*e,
280     int		ac,
281     char	**av
282 )
283 {
284     int i;
285     char buf[LINESIZE];
286 
287     if (ac > 1 && !strcmp(av[1], "-n")) {
288 	for(i=0; i<e->ncont; i++) {
289 	    if (IsContElem(e,i)) printf("%s\n", ContElem(e,i)->gi);
290 	    else if (IsContData(e,i)) printf("#data %s\n", ContData(e,i));
291 	    else if (IsContPI(e,i))   printf("#pi %s\n", ContData(e,i));
292 	}
293 	return;
294     }
295 
296     printf("Element: %s\tLineNumber: %d\n", e->gi, e->lineno);
297     if (e->parent)
298 	printf("Context: %s\n", FindContext(e, 20, buf));
299 
300     if (e->natts) {
301 	printf("%d attributes:\n", e->natts);
302 	for (i=0; i<e->natts; i++)
303 	    printf("\t%2d: %s = '%s'\n", i, e->atts[i].name, e->atts[i].sval);
304     }
305     if (e->entity) {
306 	printf("Entity & notation information:\n");
307 	if (e->entity->ename)
308 	    printf("Entity name:   %s\n", e->entity->ename);
309 	if (e->entity->nname)
310 	    printf("Notation name: %s\n", e->entity->nname);
311 	if (e->entity->sysid)
312 	    printf("Sys id:        %s\n", e->entity->sysid);
313 	if (e->entity->pubid)
314 	    printf("Pub id:        %s\n", e->entity->pubid);
315 	if (e->entity->fname)
316 	    printf("Filename:      %s\n", e->entity->fname);
317     }
318 
319     if (e->my_eorder >= 0)
320 	printf("My order among my siblings: %d\n", e->my_eorder);
321 
322     if (e->necont) {
323 	printf("%d child element nodes:\n", e->necont);
324 	for(i=0; i<e->necont; i++) printf("\t%2d: %s\n", i, e->econt[i]->gi);
325     }
326 
327     if (e->ndcont) {
328 	printf("%d child data nodes:\n", e->ndcont);
329 	for(i=0; i<e->ndcont; i++) {
330 	    if (strlen(e->dcont[i]) < 40)
331 		printf("\t%2d: %s\n", i, e->dcont[i]);
332 	    else
333 		printf("\t%2d: %-40.40s...\n", i, e->dcont[i]);
334 	}
335     }
336 }
337 
338 /* ______________________________________________________________________ */
339 /*  Perform query.  Syntax: find relationship gi.  Tells whether gi has
340  *  given relationship to current element.  Result (message) sent to stdout.
341  *  Args:
342  *	Pointer to element under consideration.
343  *	Pointer to name of relationship. (see FindRelByName() for names)
344  *	Pointer to GI to look for.
345  */
346 
347 static void
do_query(Element_t * e,char * rel,char * gi)348 do_query(
349     Element_t	*e,
350     char	*rel,
351     char	*gi
352 )
353 {
354     char	*cp;
355     Relation_t	 r;
356     Element_t	*ep;
357 
358     for (cp=gi; *cp; cp++) if (islower(*cp)) *cp = toupper(*cp);
359 
360     if ((r = FindRelByName(rel)) == REL_Unknown) {
361 	return;
362     }
363     ep = QRelation(e, gi, r);
364     printf("%s, '%s' is%s %s of '%s'.\n", (ep ? "Yes" : "No"), gi,
365 		(ep ? "" : " not"), rel, e->gi);
366 }
367 
368 /* ______________________________________________________________________ */
369 /* Print path to the element and its ID (if it has one) on a single line.
370  *  Arguments:
371  *	Pointer to element under consideration.
372  */
373 static void
PrElemPlusID(Element_t * e)374 PrElemPlusID(
375     Element_t	*e
376 )
377 {
378     char buf[LINESIZE];
379 
380     if (e->id) printf("%s -- ID=%s\n", FindElementPath(e, buf), e->id);
381     else printf("%s\n", FindElementPath(e, buf));
382 }
383 
384 /* ______________________________________________________________________ */
385 /* Print path to the element and its ID (if it has one) on a single line.
386  *  Arguments:
387  *	Pointer to element under consideration.
388  */
389 
390 static void
match_gi(Element_t * e,char ** av)391 match_gi(
392     Element_t	*e,
393     char	**av
394 )
395 {
396     if (!strcmp(av[1], e->gi)) PrElemPlusID(e);
397 }
398 
399 /*  Shorthand for defining simple finctions, which are just interfaces to
400  *  calling QRelation().  DescendTree() only passes ptr to element. */
401 #define MATCH(Fun,Rel)	\
402 	static void Fun(Element_t *e, char **av) \
403 	{ if (QRelation(e, av[1], Rel)) PrElemPlusID(e);  }
404 
MATCH(match_parent,REL_Parent)405 MATCH(match_parent, REL_Parent)
406 MATCH(match_child,  REL_Child)
407 MATCH(match_anc,    REL_Ancestor)
408 MATCH(match_desc,   REL_Descendant)
409 MATCH(match_sib,    REL_Sibling)
410 
411 static void
412 match_attr(
413     Element_t	*e,
414     char	**av
415 )
416 {
417     char	*atval;
418 
419     if ((atval = FindAttValByName(e, av[1])) && !strcmp(av[2], atval))
420 	PrElemPlusID(e);
421 }
422 
423 static void
match_cont(Element_t * e,char ** av)424 match_cont(
425     Element_t	*e,
426     char	**av
427 )
428 {
429     int		i;
430     for (i=0; i<e->ncont; i++) {
431 	if (IsContData(e,i) && strstr(ContData(e,i), av[1])) {
432 	    PrElemPlusID(e);
433 	    return;
434 	}
435     }
436 }
437 
438 /*  Find an element, given the criteria on its command line.
439  *  Arguments:
440  *	Pointer to element under consideration.
441  */
442 static void
do_find(Element_t * e,char ** av)443 do_find(
444     Element_t	*e,
445     char	**av
446 )
447 {
448     av++;
449     if (!strcmp(av[0], ".")) av++;
450     else e = DocTree;
451     if (!strcmp(av[0], "gi"))		DescendTree(e, match_gi, 0, 0, av);
452     else if (!strcmp(av[0], "attr"))	DescendTree(e, match_attr, 0, 0, av);
453     else if (!strcmp(av[0], "parent"))	DescendTree(e, match_parent, 0, 0, av);
454     else if (!strcmp(av[0], "child"))	DescendTree(e, match_child, 0, 0, av);
455     else if (!strcmp(av[0], "cont"))	DescendTree(e, match_cont, 0, 0, av);
456     else if (!strcmp(av[0], "sib"))	DescendTree(e, match_sib, 0, 0, av);
457     else if (!strcmp(av[0], "desc"))	DescendTree(e, match_desc, 0, 0, av);
458     else if (!strcmp(av[0], "anc"))	DescendTree(e, match_anc, 0, 0, av);
459     else fprintf(stderr, "Unknown find command: %s.\n", av[0]);
460 }
461 
462 /* ______________________________________________________________________ */
463