xref: /onnv-gate/usr/src/cmd/man/src/util/instant.src/browse.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  *
51  *  Module for interactive browsing.
52  *
53  *  Entry points for this module:
54  *	Browse()		interactive browser
55  * ________________________________________________________________________
56  */
57 
58 #ifndef lint
59 static char *RCSid =
60   "$Header: /usr/src/docbook-to-man/Instant/RCS/browse.c,v 1.2 1996/06/02 21:46:10 fld Exp $";
61 #endif
62 
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <ctype.h>
66 #include <string.h>
67 
68 #include "general.h"
69 
70 static void	PrElemPlusID(Element_t *);
71 static void	ls_node(Element_t *, int, char **);
72 static void	do_query(Element_t *, char *, char *);
73 static void	do_find(Element_t *, char **);
74 
75 /* ______________________________________________________________________ */
76 
77 static char *br_help_msg[] = {
78   "  ls            List info about current element in tree",
79   "                (context, children, attributes, etc.)",
80   "  cd N ...      Change to Nth elememt child, where N is shown by 'ls'.",
81   "                N may also be '/' (top) or '..' (up).",
82   "  cd id I       Change to elememt whose ID is I",
83   "  data N        Show data of Nth data node",
84   "  where         Show current position in the tree",
85   "  id I          Show path to element with id I",
86   "                (using '?' for I will lists all IDs and their paths)",
87   "  find S        Find elements matching spec S. Recognized syntaxes:",
88   "                  find attr <name> <value>",
89   "                  find cont <string>",
90   "                  find parent <gi-name>",
91   "                  find child <gi-name>",
92   "                  find gi <gi-name>",
93   "  q rel gi      Query: report if elem 'gi' has relation to current elem",
94   "                ('rel' is one of 'child parent ancestor descendant",
95   "                  sibling sibling+ sibling+1 sibling- sibling-1 cousin')",
96   "",
97   "  tran file [outfile]",
98   "                With trans spec in 'file' translate into 'outfile' (stdout)",
99   "  sdata file    Read SDATA map file (for translations).",
100   "  cmap file     Read character map file (for translations).",
101   "  stat          Print statistics (how often elements occur, etc.)",
102   "  sum           Print elem usage summary (# of children, depth, etc.)",
103   "  tree          Print document hierarchy as a tree",
104   "  cont          Print context of each element",
105   NULL
106 };
107 
108 /* ______________________________________________________________________ */
109 
110 void
Browse()111 Browse()
112 {
113     char	buf[256], *cmd, **av, **sv, *cmapfile, *sdatafile;
114     char	*Prompt;
115     Element_t	*ce;	/* current element */
116     Element_t	*e;
117     int		i, n, ac;
118 
119     if (slave) Prompt = "=>\n";
120     else Prompt = "=> ";
121 
122     ce = DocTree;
123     while (fputs(Prompt, stdout)) {
124 	if (!fgets(buf, 256, stdin)) break;
125 	stripNL(buf);
126 	if (buf[0] == EOS) {
127 	    fputs(Prompt, stdout);
128 	    continue;
129 	}
130 	ac = 20;
131 	av = Split(buf, &ac, S_ALVEC);
132 	if (ac > 0) cmd = av[0];
133 	if (!cmd || !(*cmd)) continue;
134 
135 	if (!strcmp(cmd, "ls")) ls_node(ce, ac, av);
136 
137 	else if (!strcmp(cmd, "cd")) {
138 	    if (av[1]) {
139 		if (ac == 3 && !strcmp(av[1], "id")) {
140 		    if ((e = FindElemByID(av[2]))) ce = e;
141 		    else printf("Element with ID '%s' not found.\n", av[2]);
142 		    continue;
143 		}
144 		for (i=1; i<ac; i++) {
145 		    if (!strcmp(av[i], "..")) {
146 			if (ce->parent) ce = ce->parent;
147 			continue;
148 		    }
149 		    if (!strcmp(av[i], "/")) {
150 			if (ce->parent) ce = DocTree;
151 			continue;
152 		    }
153 		    if (!isdigit(*av[i])) {
154 			printf("Expecting digit, '..', or '/', got '%s'.\n",
155 				    av[i]);
156 			break;
157 		    }
158 		    n = atoi(av[i]);
159 		    if (n < ce->necont) ce = ce->econt[n];
160 		    else {
161 			printf("Must be in range 0 - %d.\n", ce->necont);
162 			break;
163 		    }
164 		}
165 	    }
166 	}
167 
168 	else if (!strcmp(cmd, "data")) {
169 	    if (av[1] && isdigit(*av[1])) {
170 		n = atoi(av[1]);
171 		if (n < ce->ndcont) {
172 		    printf(ce->dcont[n]);
173 		    fputs("\n", stdout);
174 		}
175 		else if (ce->ndcont == 0)
176 		    printf("No data at this node.\n");
177 		else printf("Must be in range 0 - %d.\n", ce->ndcont);
178 	    }
179 	}
180 
181 	/* show where we are in the tree */
182 	else if (!strcmp(cmd, "where")) PrintLocation(ce, stdout);
183 
184 	/* show where we are in the tree */
185 	else if (!strcmp(cmd, "pwd")) PrElemPlusID(ce);
186 
187 	/* perform query with yes/no answer */
188 	else if (!strcmp(cmd, "q") && av[1] && av[2])
189 	    do_query(ce, av[1], av[2]);
190 
191 	/* perform query printing paths to matching elements */
192 	else if (!strcmp(cmd, "find") && av[1] && av[2])
193 	    do_find(ce, av);
194 
195 	/* list locations where specified ID(s) occur */
196 	else if (!strcmp(cmd, "id")) {
197 	    if (ac <= 1) continue;
198 	    if (*av[1] == '?') PrintIDList();
199 	    else {
200 		/* short: "id i1 i2 ...", long: "id -l i1 i2 ..." */
201 		if (!strcmp(av[1], "-l")) n = 2;
202 		else n = 1;
203 		for (i=n; i<ac; i++) {
204 		    if ((e = FindElemByID(av[i]))) {
205 			if (n == 2) {	/* long (multiline) format */
206 			    if (n != i) putchar('\n');
207 			    PrintLocation(e, stdout);
208 			}
209 			else PrElemPlusID(e);
210 		    }
211 		    else printf("Element with ID '%s' not found.\n", av[i]);
212 		}
213 	    }
214 	}
215 
216 	/* show and set variables */
217 	else if (!strcmp(cmd, "show") && av[1]) {
218 	    printf("%s\n", FindMappingVal(Variables, av[1]));
219 	}
220 	else if (!strcmp(cmd, "set") && av[1] && av[2]) {
221 	    SetMappingNV(Variables, av[1], av[2]);
222 	}
223 
224 	/* print summary of tag usage */
225 	else if (!strcmp(cmd, "sum")) {
226 	    if (ac > 1) PrintElemSummary(ce);
227 	    else PrintElemSummary(DocTree);
228 	}
229 	/* print element tree */
230 	else if (!strcmp(cmd, "tree")) {
231 	    if (ac > 1) PrintElemTree(ce);
232 	    else PrintElemTree(DocTree);
233 	}
234 	/* print statistics */
235 	else if (!strcmp(cmd, "stat")) {
236 	    if (ac > 1) PrintStats(ce);
237 	    else PrintStats(DocTree);
238 	}
239 	/* print context of each element of tree */
240 	else if (!strcmp(cmd, "cont")) {
241 	    if (ac > 1) PrintContext(ce);
242 	    else PrintContext(DocTree);
243 	}
244 	/* print translation, given transpec */
245 	else if (!strcmp(cmd, "tran")) {
246 	    FILE *fp;
247 	    if (ac > 2){
248 		if (!(fp = fopen(av[2], "w"))) {
249 		    perror("Can not open output file");
250 		    continue;
251 		}
252 	    }
253 	    else fp = stdout;
254 	    DoTranslate(ce, av[1], fp);
255 	    if (ac > 2) fclose(fp);
256 	}
257 	else if (!strcmp(cmd, "sdata")){
258 	    sdatafile = strdup(av[1]);
259 	    ReadSDATA(sdatafile);
260 	}
261 	else if (!strcmp(cmd, "cmap")){
262 	    cmapfile = strdup(av[1]);
263 	    ReadCharMap(cmapfile);
264 	}
265 
266 	else if (!strcmp(cmd, "help") || *cmd == '?') {
267 	    sv = br_help_msg;
268 	    while (*sv) puts(*sv++);
269 	}
270 
271 	/* quit (control-D also works) */
272 	else if (!strcmp(cmd, "quit")) break;
273 
274 	else
275 	    fprintf(stderr, "Unknown command '%s' - ingored.\n", cmd);
276     }
277     putc(NL, stdout);
278 }
279 
280 /* ______________________________________________________________________ */
281 /*  Do the "ls" command.
282  *  Arguments:
283  *	Pointer to element under consideration.
284  *	Arg count from command line (this command, not the shell command).
285  *	Arg vector.
286  */
287 
288 static void
ls_node(Element_t * e,int ac,char ** av)289 ls_node(
290     Element_t	*e,
291     int		ac,
292     char	**av
293 )
294 {
295     int i;
296     char buf[LINESIZE];
297 
298     if (ac > 1 && !strcmp(av[1], "-n")) {
299 	for(i=0; i<e->ncont; i++) {
300 	    if (IsContElem(e,i)) printf("%s\n", ContElem(e,i)->gi);
301 	    else if (IsContData(e,i)) printf("#data %s\n", ContData(e,i));
302 	    else if (IsContPI(e,i))   printf("#pi %s\n", ContData(e,i));
303 	}
304 	return;
305     }
306 
307     printf("Element: %s\tLineNumber: %d\n", e->gi, e->lineno);
308     if (e->parent)
309 	printf("Context: %s\n", FindContext(e, 20, buf));
310 
311     if (e->natts) {
312 	printf("%d attributes:\n", e->natts);
313 	for (i=0; i<e->natts; i++)
314 	    printf("\t%2d: %s = '%s'\n", i, e->atts[i].name, e->atts[i].sval);
315     }
316     if (e->entity) {
317 	printf("Entity & notation information:\n");
318 	if (e->entity->ename)
319 	    printf("Entity name:   %s\n", e->entity->ename);
320 	if (e->entity->nname)
321 	    printf("Notation name: %s\n", e->entity->nname);
322 	if (e->entity->sysid)
323 	    printf("Sys id:        %s\n", e->entity->sysid);
324 	if (e->entity->pubid)
325 	    printf("Pub id:        %s\n", e->entity->pubid);
326 	if (e->entity->fname)
327 	    printf("Filename:      %s\n", e->entity->fname);
328     }
329 
330     if (e->my_eorder >= 0)
331 	printf("My order among my siblings: %d\n", e->my_eorder);
332 
333     if (e->necont) {
334 	printf("%d child element nodes:\n", e->necont);
335 	for(i=0; i<e->necont; i++) printf("\t%2d: %s\n", i, e->econt[i]->gi);
336     }
337 
338     if (e->ndcont) {
339 	printf("%d child data nodes:\n", e->ndcont);
340 	for(i=0; i<e->ndcont; i++) {
341 	    if (strlen(e->dcont[i]) < 40)
342 		printf("\t%2d: %s\n", i, e->dcont[i]);
343 	    else
344 		printf("\t%2d: %-40.40s...\n", i, e->dcont[i]);
345 	}
346     }
347 }
348 
349 /* ______________________________________________________________________ */
350 /*  Perform query.  Syntax: find relationship gi.  Tells whether gi has
351  *  given relationship to current element.  Result (message) sent to stdout.
352  *  Args:
353  *	Pointer to element under consideration.
354  *	Pointer to name of relationship. (see FindRelByName() for names)
355  *	Pointer to GI to look for.
356  */
357 
358 static void
do_query(Element_t * e,char * rel,char * gi)359 do_query(
360     Element_t	*e,
361     char	*rel,
362     char	*gi
363 )
364 {
365     char	*cp;
366     Relation_t	 r;
367     Element_t	*ep;
368 
369     for (cp=gi; *cp; cp++) if (islower(*cp)) *cp = toupper(*cp);
370 
371     if ((r = FindRelByName(rel)) == REL_Unknown) {
372 	return;
373     }
374     ep = QRelation(e, gi, r);
375     printf("%s, '%s' is%s %s of '%s'.\n", (ep ? "Yes" : "No"), gi,
376 		(ep ? "" : " not"), rel, e->gi);
377 }
378 
379 /* ______________________________________________________________________ */
380 /* Print path to the element and its ID (if it has one) on a single line.
381  *  Arguments:
382  *	Pointer to element under consideration.
383  */
384 static void
PrElemPlusID(Element_t * e)385 PrElemPlusID(
386     Element_t	*e
387 )
388 {
389     char buf[LINESIZE];
390 
391     if (e->id) printf("%s -- ID=%s\n", FindElementPath(e, buf), e->id);
392     else printf("%s\n", FindElementPath(e, buf));
393 }
394 
395 /* ______________________________________________________________________ */
396 /* Print path to the element and its ID (if it has one) on a single line.
397  *  Arguments:
398  *	Pointer to element under consideration.
399  */
400 
401 static void
match_gi(Element_t * e,char ** av)402 match_gi(
403     Element_t	*e,
404     char	**av
405 )
406 {
407     if (!strcmp(av[1], e->gi)) PrElemPlusID(e);
408 }
409 
410 /*  Shorthand for defining simple finctions, which are just interfaces to
411  *  calling QRelation().  DescendTree() only passes ptr to element. */
412 #define MATCH(Fun,Rel)	\
413 	static void Fun(Element_t *e, char **av) \
414 	{ if (QRelation(e, av[1], Rel)) PrElemPlusID(e);  }
415 
MATCH(match_parent,REL_Parent)416 MATCH(match_parent, REL_Parent)
417 MATCH(match_child,  REL_Child)
418 MATCH(match_anc,    REL_Ancestor)
419 MATCH(match_desc,   REL_Descendant)
420 MATCH(match_sib,    REL_Sibling)
421 
422 static void
423 match_attr(
424     Element_t	*e,
425     char	**av
426 )
427 {
428     char	*atval;
429 
430     if ((atval = FindAttValByName(e, av[1])) && !strcmp(av[2], atval))
431 	PrElemPlusID(e);
432 }
433 
434 static void
match_cont(Element_t * e,char ** av)435 match_cont(
436     Element_t	*e,
437     char	**av
438 )
439 {
440     int		i;
441     for (i=0; i<e->ncont; i++) {
442 	if (IsContData(e,i) && strstr(ContData(e,i), av[1])) {
443 	    PrElemPlusID(e);
444 	    return;
445 	}
446     }
447 }
448 
449 /*  Find an element, given the criteria on its command line.
450  *  Arguments:
451  *	Pointer to element under consideration.
452  */
453 static void
do_find(Element_t * e,char ** av)454 do_find(
455     Element_t	*e,
456     char	**av
457 )
458 {
459     av++;
460     if (!strcmp(av[0], ".")) av++;
461     else e = DocTree;
462     if (!strcmp(av[0], "gi"))		DescendTree(e, match_gi, 0, 0, av);
463     else if (!strcmp(av[0], "attr"))	DescendTree(e, match_attr, 0, 0, av);
464     else if (!strcmp(av[0], "parent"))	DescendTree(e, match_parent, 0, 0, av);
465     else if (!strcmp(av[0], "child"))	DescendTree(e, match_child, 0, 0, av);
466     else if (!strcmp(av[0], "cont"))	DescendTree(e, match_cont, 0, 0, av);
467     else if (!strcmp(av[0], "sib"))	DescendTree(e, match_sib, 0, 0, av);
468     else if (!strcmp(av[0], "desc"))	DescendTree(e, match_desc, 0, 0, av);
469     else if (!strcmp(av[0], "anc"))	DescendTree(e, match_anc, 0, 0, av);
470     else fprintf(stderr, "Unknown find command: %s.\n", av[0]);
471 }
472 
473 /* ______________________________________________________________________ */
474