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