blob: b91fe53e3919a44e1c0e25a371765cd641ec114e [file] [log] [blame]
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001/*
2 * debugXML.c : This is a set of routines used for debugging the tree
3 * produced by the XML parser.
4 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005 * See Copyright for the status of this software.
6 *
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00007 * Daniel Veillard <Daniel.Veillard@w3.org>
8 */
9
Daniel Veillard3c558c31999-12-22 11:30:41 +000010#ifdef WIN32
11#include "win32config.h"
12#else
13#include "config.h"
14#endif
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000015#include <stdio.h>
Daniel Veillarddbfd6411999-12-28 16:35:14 +000016#ifdef HAVE_STDLIB_H
17#include <stdlib.h>
18#endif
19#include "xmlmemory.h"
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000020#include "tree.h"
21#include "parser.h"
22#include "debugXML.h"
Daniel Veillarddbfd6411999-12-28 16:35:14 +000023#include "HTMLtree.h"
24#include "HTMLparser.h"
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000025
26#define IS_BLANK(c) \
27 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
28
Daniel Veillarddd6b3671999-09-23 22:19:22 +000029void xmlDebugDumpString(FILE *output, const xmlChar *str) {
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000030 int i;
31 for (i = 0;i < 40;i++)
32 if (str[i] == 0) return;
33 else if (IS_BLANK(str[i])) fputc(' ', output);
34 else fputc(str[i], output);
35 fprintf(output, "...");
36}
37
38void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
39 int i;
40 char shift[100];
41
42 for (i = 0;((i < depth) && (i < 25));i++)
43 shift[2 * i] = shift[2 * i + 1] = ' ';
44 shift[2 * i] = shift[2 * i + 1] = 0;
45
46 fprintf(output, shift);
47 if (ns->type == XML_GLOBAL_NAMESPACE)
48 fprintf(output, "old ");
Daniel Veillard5cb5ab81999-12-21 15:35:29 +000049 if (ns->prefix != NULL)
50 fprintf(output, "namespace %s href=", ns->prefix);
51 else
Daniel Veillarddbfd6411999-12-28 16:35:14 +000052 fprintf(output, "default namespace href=");
Daniel Veillard5cb5ab81999-12-21 15:35:29 +000053
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000054 xmlDebugDumpString(output, ns->href);
55 fprintf(output, "\n");
56}
57
58void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
59 while (ns != NULL) {
60 xmlDebugDumpNamespace(output, ns, depth);
61 ns = ns->next;
62 }
63}
64
65void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
66 int i;
67 char shift[100];
68
69 for (i = 0;((i < depth) && (i < 25));i++)
70 shift[2 * i] = shift[2 * i + 1] = ' ';
71 shift[2 * i] = shift[2 * i + 1] = 0;
72
73 fprintf(output, shift);
74 switch (ent->type) {
75 case XML_INTERNAL_GENERAL_ENTITY:
76 fprintf(output, "INTERNAL_GENERAL_ENTITY ");
77 break;
78 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
79 fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
80 break;
81 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
82 fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
83 break;
84 case XML_INTERNAL_PARAMETER_ENTITY:
85 fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
86 break;
87 case XML_EXTERNAL_PARAMETER_ENTITY:
88 fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
89 break;
90 default:
91 fprintf(output, "ENTITY_%d ! ", ent->type);
92 }
93 fprintf(output, "%s\n", ent->name);
94 if (ent->ExternalID) {
95 fprintf(output, shift);
96 fprintf(output, "ExternalID=%s\n", ent->ExternalID);
97 }
98 if (ent->SystemID) {
99 fprintf(output, shift);
100 fprintf(output, "SystemID=%s\n", ent->SystemID);
101 }
102 if (ent->content) {
103 fprintf(output, shift);
104 fprintf(output, "content=");
105 xmlDebugDumpString(output, ent->content);
106 fprintf(output, "\n");
107 }
108}
109
110void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
111 int i;
112 char shift[100];
113
114 for (i = 0;((i < depth) && (i < 25));i++)
115 shift[2 * i] = shift[2 * i + 1] = ' ';
116 shift[2 * i] = shift[2 * i + 1] = 0;
117
118 fprintf(output, shift);
119 fprintf(output, "ATTRIBUTE %s\n", attr->name);
120 if (attr->val != NULL)
121 xmlDebugDumpNodeList(output, attr->val, depth + 1);
122}
123
124void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) {
125 while (attr != NULL) {
126 xmlDebugDumpAttr(output, attr, depth);
127 attr = attr->next;
128 }
129}
130
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000131void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) {
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000132 int i;
133 char shift[100];
134
135 for (i = 0;((i < depth) && (i < 25));i++)
136 shift[2 * i] = shift[2 * i + 1] = ' ';
137 shift[2 * i] = shift[2 * i + 1] = 0;
138
139 fprintf(output, shift);
140 switch (node->type) {
141 case XML_ELEMENT_NODE:
142 fprintf(output, "ELEMENT ");
143 if (node->ns != NULL)
144 fprintf(output, "%s:%s\n", node->ns->prefix, node->name);
145 else
146 fprintf(output, "%s\n", node->name);
147 break;
148 case XML_ATTRIBUTE_NODE:
149 fprintf(output, "Error, ATTRIBUTE found here\n");
150 break;
151 case XML_TEXT_NODE:
152 fprintf(output, "TEXT\n");
153 break;
154 case XML_CDATA_SECTION_NODE:
155 fprintf(output, "CDATA_SECTION\n");
156 break;
157 case XML_ENTITY_REF_NODE:
158 fprintf(output, "ENTITY_REF\n");
159 break;
160 case XML_ENTITY_NODE:
161 fprintf(output, "ENTITY\n");
162 break;
163 case XML_PI_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000164 fprintf(output, "PI %s\n", node->name);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000165 break;
166 case XML_COMMENT_NODE:
167 fprintf(output, "COMMENT\n");
168 break;
169 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000170 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000171 fprintf(output, "Error, DOCUMENT found here\n");
172 break;
173 case XML_DOCUMENT_TYPE_NODE:
174 fprintf(output, "DOCUMENT_TYPE\n");
175 break;
176 case XML_DOCUMENT_FRAG_NODE:
177 fprintf(output, "DOCUMENT_FRAG\n");
178 break;
179 case XML_NOTATION_NODE:
180 fprintf(output, "NOTATION\n");
181 break;
182 default:
183 fprintf(output, "NODE_%d\n", node->type);
184 }
185 if (node->doc == NULL) {
186 fprintf(output, shift);
187 fprintf(output, "doc == NULL !!!\n");
188 }
189 if (node->nsDef != NULL)
190 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
191 if (node->properties != NULL)
192 xmlDebugDumpAttrList(output, node->properties, depth + 1);
193 if (node->type != XML_ENTITY_REF_NODE) {
194 if (node->content != NULL) {
195 fprintf(output, shift);
196 fprintf(output, "content=");
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000197#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000198 xmlDebugDumpString(output, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000199#else
200 xmlDebugDumpString(output, xmlBufferContent(node->content));
201#endif
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000202 fprintf(output, "\n");
203 }
204 } else {
205 xmlEntityPtr ent;
206 ent = xmlGetDocEntity(node->doc, node->name);
207 if (ent != NULL)
208 xmlDebugDumpEntity(output, ent, depth + 1);
209 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000210}
211
212void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
213 xmlDebugDumpOneNode(output, node, depth);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000214 if (node->childs != NULL)
215 xmlDebugDumpNodeList(output, node->childs, depth + 1);
216}
217
218void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
219 while (node != NULL) {
220 xmlDebugDumpNode(output, node, depth);
221 node = node->next;
222 }
223}
224
225
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000226void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000227 if (output == NULL) output = stdout;
228 if (doc == NULL) {
229 fprintf(output, "DOCUMENT == NULL !\n");
230 return;
231 }
232
233 switch (doc->type) {
234 case XML_ELEMENT_NODE:
235 fprintf(output, "Error, ELEMENT found here ");
236 break;
237 case XML_ATTRIBUTE_NODE:
238 fprintf(output, "Error, ATTRIBUTE found here\n");
239 break;
240 case XML_TEXT_NODE:
241 fprintf(output, "Error, TEXT\n");
242 break;
243 case XML_CDATA_SECTION_NODE:
244 fprintf(output, "Error, CDATA_SECTION\n");
245 break;
246 case XML_ENTITY_REF_NODE:
247 fprintf(output, "Error, ENTITY_REF\n");
248 break;
249 case XML_ENTITY_NODE:
250 fprintf(output, "Error, ENTITY\n");
251 break;
252 case XML_PI_NODE:
253 fprintf(output, "Error, PI\n");
254 break;
255 case XML_COMMENT_NODE:
256 fprintf(output, "Error, COMMENT\n");
257 break;
258 case XML_DOCUMENT_NODE:
259 fprintf(output, "DOCUMENT\n");
260 break;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000261 case XML_HTML_DOCUMENT_NODE:
262 fprintf(output, "HTML DOCUMENT\n");
263 break;
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000264 case XML_DOCUMENT_TYPE_NODE:
265 fprintf(output, "Error, DOCUMENT_TYPE\n");
266 break;
267 case XML_DOCUMENT_FRAG_NODE:
268 fprintf(output, "Error, DOCUMENT_FRAG\n");
269 break;
270 case XML_NOTATION_NODE:
271 fprintf(output, "Error, NOTATION\n");
272 break;
273 default:
274 fprintf(output, "NODE_%d\n", doc->type);
275 }
276 if (doc->name != NULL) {
277 fprintf(output, "name=");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000278 xmlDebugDumpString(output, BAD_CAST doc->name);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000279 fprintf(output, "\n");
280 }
281 if (doc->version != NULL) {
282 fprintf(output, "version=");
283 xmlDebugDumpString(output, doc->version);
284 fprintf(output, "\n");
285 }
286 if (doc->encoding != NULL) {
287 fprintf(output, "encoding=");
288 xmlDebugDumpString(output, doc->encoding);
289 fprintf(output, "\n");
290 }
291 if (doc->standalone)
292 fprintf(output, "standalone=true\n");
293 if (doc->oldNs != NULL)
294 xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000295}
Daniel Veillard10a2c651999-12-12 13:03:50 +0000296
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000297void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
298 if (output == NULL) output = stdout;
299 if (doc == NULL) {
300 fprintf(output, "DOCUMENT == NULL !\n");
301 return;
302 }
303 xmlDebugDumpDocumentHead(output, doc);
304 if (((doc->type == XML_DOCUMENT_NODE) ||
305 (doc->type == XML_HTML_DOCUMENT_NODE)) &&
306 (doc->root != NULL))
307 xmlDebugDumpNodeList(output, doc->root, 1);
308}
309
Daniel Veillard10a2c651999-12-12 13:03:50 +0000310void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
311 int i;
312 xmlEntityPtr cur;
313
314 if (output == NULL) output = stdout;
315 if (doc == NULL) {
316 fprintf(output, "DOCUMENT == NULL !\n");
317 return;
318 }
319
320 switch (doc->type) {
321 case XML_ELEMENT_NODE:
322 fprintf(output, "Error, ELEMENT found here ");
323 break;
324 case XML_ATTRIBUTE_NODE:
325 fprintf(output, "Error, ATTRIBUTE found here\n");
326 break;
327 case XML_TEXT_NODE:
328 fprintf(output, "Error, TEXT\n");
329 break;
330 case XML_CDATA_SECTION_NODE:
331 fprintf(output, "Error, CDATA_SECTION\n");
332 break;
333 case XML_ENTITY_REF_NODE:
334 fprintf(output, "Error, ENTITY_REF\n");
335 break;
336 case XML_ENTITY_NODE:
337 fprintf(output, "Error, ENTITY\n");
338 break;
339 case XML_PI_NODE:
340 fprintf(output, "Error, PI\n");
341 break;
342 case XML_COMMENT_NODE:
343 fprintf(output, "Error, COMMENT\n");
344 break;
345 case XML_DOCUMENT_NODE:
346 fprintf(output, "DOCUMENT\n");
347 break;
348 case XML_HTML_DOCUMENT_NODE:
349 fprintf(output, "HTML DOCUMENT\n");
350 break;
351 case XML_DOCUMENT_TYPE_NODE:
352 fprintf(output, "Error, DOCUMENT_TYPE\n");
353 break;
354 case XML_DOCUMENT_FRAG_NODE:
355 fprintf(output, "Error, DOCUMENT_FRAG\n");
356 break;
357 case XML_NOTATION_NODE:
358 fprintf(output, "Error, NOTATION\n");
359 break;
360 default:
361 fprintf(output, "NODE_%d\n", doc->type);
362 }
363 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
364 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
365 doc->intSubset->entities;
366 fprintf(output, "Entities in internal subset\n");
367 for (i = 0;i < table->nb_entities;i++) {
368 cur = &table->table[i];
369 fprintf(output, "%d : %s : ", i, cur->name);
370 switch (cur->type) {
371 case XML_INTERNAL_GENERAL_ENTITY:
372 fprintf(output, "INTERNAL GENERAL");
373 break;
374 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
375 fprintf(output, "EXTERNAL PARSED");
376 break;
377 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
378 fprintf(output, "EXTERNAL UNPARSED");
379 break;
380 case XML_INTERNAL_PARAMETER_ENTITY:
381 fprintf(output, "INTERNAL PARAMETER");
382 break;
383 case XML_EXTERNAL_PARAMETER_ENTITY:
384 fprintf(output, "EXTERNAL PARAMETER");
385 break;
386 default:
387 fprintf(output, "UNKNOWN TYPE %d",
388 cur->type);
389 }
390 if (cur->ExternalID != NULL)
391 fprintf(output, "ID \"%s\"", cur->ExternalID);
392 if (cur->SystemID != NULL)
393 fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
394 if (cur->orig != NULL)
395 fprintf(output, "\n orig \"%s\"", cur->orig);
396 if (cur->content != NULL)
397 fprintf(output, "\n content \"%s\"", cur->content);
398 fprintf(output, "\n");
399 }
400 } else
401 fprintf(output, "No entities in internal subset\n");
402 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
403 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
404 doc->extSubset->entities;
405 fprintf(output, "Entities in external subset\n");
406 for (i = 0;i < table->nb_entities;i++) {
407 cur = &table->table[i];
408 fprintf(output, "%d : %s : ", i, cur->name);
409 switch (cur->type) {
410 case XML_INTERNAL_GENERAL_ENTITY:
411 fprintf(output, "INTERNAL GENERAL");
412 break;
413 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
414 fprintf(output, "EXTERNAL PARSED");
415 break;
416 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
417 fprintf(output, "EXTERNAL UNPARSED");
418 break;
419 case XML_INTERNAL_PARAMETER_ENTITY:
420 fprintf(output, "INTERNAL PARAMETER");
421 break;
422 case XML_EXTERNAL_PARAMETER_ENTITY:
423 fprintf(output, "EXTERNAL PARAMETER");
424 break;
425 default:
426 fprintf(output, "UNKNOWN TYPE %d",
427 cur->type);
428 }
429 if (cur->ExternalID != NULL)
430 fprintf(output, "ID \"%s\"", cur->ExternalID);
431 if (cur->SystemID != NULL)
432 fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
433 if (cur->orig != NULL)
434 fprintf(output, "\n orig \"%s\"", cur->orig);
435 if (cur->content != NULL)
436 fprintf(output, "\n content \"%s\"", cur->content);
437 fprintf(output, "\n");
438 }
439 } else
440 fprintf(output, "No entities in external subset\n");
441}
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000442
443static int xmlLsCountNode(xmlNodePtr node) {
444 int ret = 0;
445 xmlNodePtr list = NULL;
446
447 switch (node->type) {
448 case XML_ELEMENT_NODE:
449 list = node->childs;
450 break;
451 case XML_DOCUMENT_NODE:
452 case XML_HTML_DOCUMENT_NODE:
453 list = ((xmlDocPtr) node)->root;
454 break;
455 case XML_ATTRIBUTE_NODE:
456 list = ((xmlAttrPtr) node)->val;
457 break;
458 case XML_TEXT_NODE:
459 case XML_CDATA_SECTION_NODE:
460 case XML_PI_NODE:
461 case XML_COMMENT_NODE:
462 if (node->content != NULL) {
463#ifndef XML_USE_BUFFER_CONTENT
464 ret = xmlStrlen(node->content);
465#else
466 ret = xmlBufferLength(node->content);
467#endif
468 }
469 break;
470 case XML_ENTITY_REF_NODE:
471 case XML_DOCUMENT_TYPE_NODE:
472 case XML_ENTITY_NODE:
473 case XML_DOCUMENT_FRAG_NODE:
474 case XML_NOTATION_NODE:
475 ret = 1;
476 break;
477 }
478 for (;list != NULL;ret++)
479 list = list->next;
480 return(ret);
481}
482
483void xmlLsOneNode(FILE *output, xmlNodePtr node) {
484 switch (node->type) {
485 case XML_ELEMENT_NODE:
486 fprintf(output, "-");
487 break;
488 case XML_ATTRIBUTE_NODE:
489 fprintf(output, "a");
490 break;
491 case XML_TEXT_NODE:
492 fprintf(output, "t");
493 break;
494 case XML_CDATA_SECTION_NODE:
495 fprintf(output, "c");
496 break;
497 case XML_ENTITY_REF_NODE:
498 fprintf(output, "e");
499 break;
500 case XML_ENTITY_NODE:
501 fprintf(output, "E");
502 break;
503 case XML_PI_NODE:
504 fprintf(output, "p");
505 break;
506 case XML_COMMENT_NODE:
507 fprintf(output, "c");
508 break;
509 case XML_DOCUMENT_NODE:
510 fprintf(output, "d");
511 break;
512 case XML_HTML_DOCUMENT_NODE:
513 fprintf(output, "h");
514 break;
515 case XML_DOCUMENT_TYPE_NODE:
516 fprintf(output, "T");
517 break;
518 case XML_DOCUMENT_FRAG_NODE:
519 fprintf(output, "F");
520 break;
521 case XML_NOTATION_NODE:
522 fprintf(output, "N");
523 break;
524 default:
525 fprintf(output, "?");
526 }
527 if (node->properties != NULL)
528 fprintf(output, "a");
529 else
530 fprintf(output, "-");
531 if (node->nsDef != NULL)
532 fprintf(output, "n");
533 else
534 fprintf(output, "-");
535
536 fprintf(output, " %8d ", xmlLsCountNode(node));
537
538 switch (node->type) {
539 case XML_ELEMENT_NODE:
540 if (node->name != NULL)
541 fprintf(output, "%s", node->name);
542 break;
543 case XML_ATTRIBUTE_NODE:
544 if (node->name != NULL)
545 fprintf(output, "%s", node->name);
546 break;
547 case XML_TEXT_NODE:
548 if (node->content != NULL) {
549#ifndef XML_USE_BUFFER_CONTENT
550 xmlDebugDumpString(output, node->content);
551#else
552 xmlDebugDumpString(output, xmlBufferContent(node->content));
553#endif
554 }
555 break;
556 case XML_CDATA_SECTION_NODE:
557 break;
558 case XML_ENTITY_REF_NODE:
559 if (node->name != NULL)
560 fprintf(output, "%s", node->name);
561 break;
562 case XML_ENTITY_NODE:
563 if (node->name != NULL)
564 fprintf(output, "%s", node->name);
565 break;
566 case XML_PI_NODE:
567 if (node->name != NULL)
568 fprintf(output, "%s", node->name);
569 break;
570 case XML_COMMENT_NODE:
571 break;
572 case XML_DOCUMENT_NODE:
573 break;
574 case XML_HTML_DOCUMENT_NODE:
575 break;
576 case XML_DOCUMENT_TYPE_NODE:
577 break;
578 case XML_DOCUMENT_FRAG_NODE:
579 break;
580 case XML_NOTATION_NODE:
581 break;
582 default:
583 if (node->name != NULL)
584 fprintf(output, "%s", node->name);
585 }
586 fprintf(output, "\n");
587}
588
589/****************************************************************
590 * *
591 * The XML shell related functions *
592 * *
593 ****************************************************************/
594
595/*
596 * TODO: Improvement/cleanups for the XML shell
597 * - allow to shell out an editor on a subpart
598 * - cleanup function registrations (with help) and calling
599 * - provide registration routines
600 */
601
602/**
603 * xmlShellList:
604 * @ctxt: the shell context
605 * @arg: unused
606 * @node: a node
607 * @node2: unused
608 *
609 * Implements the XML shell function "ls"
610 * Does an Unix like listing of the given node (like a directory)
611 *
612 * Returns 0
613 */
614int
615xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
616 xmlNodePtr node2) {
617 xmlNodePtr cur;
618
619 if ((node->type == XML_DOCUMENT_NODE) ||
620 (node->type == XML_HTML_DOCUMENT_NODE)) {
621 cur = ((xmlDocPtr) node)->root;
622 } else if (node->childs != NULL) {
623 cur = node->childs;
624 } else {
625 xmlLsOneNode(stdout, node);
626 return(0);
627 }
628 while (cur != NULL) {
629 xmlLsOneNode(stdout, cur);
630 cur = cur->next;
631 }
632 return(0);
633}
634
635/**
636 * xmlShellDir:
637 * @ctxt: the shell context
638 * @arg: unused
639 * @node: a node
640 * @node2: unused
641 *
642 * Implements the XML shell function "dir"
643 * dumps informations about the node (namespace, attributes, content).
644 *
645 * Returns 0
646 */
647int
648xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
649 xmlNodePtr node2) {
650 if ((node->type == XML_DOCUMENT_NODE) ||
651 (node->type == XML_HTML_DOCUMENT_NODE)) {
652 xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
653 } else if (node->type == XML_ATTRIBUTE_NODE) {
654 xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
655 } else {
656 xmlDebugDumpOneNode(stdout, node, 0);
657 }
658 return(0);
659}
660
661/**
662 * xmlShellCat:
663 * @ctxt: the shell context
664 * @arg: unused
665 * @node: a node
666 * @node2: unused
667 *
668 * Implements the XML shell function "cat"
669 * dumps the serialization node content (XML or HTML).
670 *
671 * Returns 0
672 */
673int
674xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
675 xmlNodePtr node2) {
Daniel Veillardaeea04f2000-01-25 19:27:27 +0000676 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
677 if (node->type == XML_HTML_DOCUMENT_NODE)
678 htmlDocDump(stdout, (htmlDocPtr) node);
679 else
680 htmlNodeDump(stdout, ctxt->doc, node);
681 } else {
682 if (node->type == XML_DOCUMENT_NODE)
683 xmlDocDump(stdout, (xmlDocPtr) node);
684 else
685 xmlElemDump(stdout, ctxt->doc, node);
686 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000687 printf("\n");
688 return(0);
689}
690
691/**
692 * xmlShellLoad:
693 * @ctxt: the shell context
694 * @filename: the file name
695 * @node: unused
696 * @node2: unused
697 *
698 * Implements the XML shell function "load"
699 * loads a new document specified by the filename
700 *
701 * Returns 0 or -1 if loading failed
702 */
703int
704xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
705 xmlNodePtr node2) {
706 xmlDocPtr doc;
707 int html = 0;
708
709 if (ctxt->doc != NULL)
710 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
711
712 if (html) {
713 doc = htmlParseFile(filename, NULL);
714 } else {
715 doc = xmlParseFile(filename);
716 }
717 if (doc != NULL) {
718 if (ctxt->loaded == 1) {
719 xmlFreeDoc(ctxt->doc);
720 }
721 ctxt->loaded = 1;
722 xmlXPathFreeContext(ctxt->pctxt);
723 xmlFree(ctxt->filename);
724 ctxt->doc = doc;
725 ctxt->node = (xmlNodePtr) doc;
726 ctxt->pctxt = xmlXPathNewContext(doc);
727 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
728 } else
729 return(-1);
730 return(0);
731}
732
733/**
734 * xmlShellWrite:
735 * @ctxt: the shell context
736 * @filename: the file name
737 * @node: a node in the tree
738 * @node2: unused
739 *
740 * Implements the XML shell function "write"
741 * Write the current node to the filename, it saves the serailization
742 * of the subtree under the @node specified
743 *
744 * Returns 0 or -1 in case of error
745 */
746int
747xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
748 xmlNodePtr node2) {
749 if (node == NULL)
750 return(-1);
751 if ((filename == NULL) || (filename[0] == 0)) {
752 fprintf(stderr, "Write command requires a filename argument\n");
753 return(-1);
754 }
755#ifdef W_OK
756 if (access((char *) filename, W_OK)) {
757 fprintf(stderr, "Cannot write to %s\n", filename);
758 return(-1);
759 }
760#endif
761 switch(node->type) {
762 case XML_DOCUMENT_NODE:
763 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
764 fprintf(stderr, "Failed to write to %s\n", filename);
765 return(-1);
766 }
767 break;
768 case XML_HTML_DOCUMENT_NODE:
769 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
770 fprintf(stderr, "Failed to write to %s\n", filename);
771 return(-1);
772 }
773 break;
774 default: {
775 FILE *f;
776
777 f = fopen((char *) filename, "w");
778 if (f == NULL) {
779 fprintf(stderr, "Failed to write to %s\n", filename);
780 return(-1);
781 }
782 xmlElemDump(f, ctxt->doc, node);
783 fclose(f);
784 }
785 }
786 return(0);
787}
788
789/**
790 * xmlShellSave:
791 * @ctxt: the shell context
792 * @filename: the file name (optionnal)
793 * @node: unused
794 * @node2: unused
795 *
796 * Implements the XML shell function "save"
797 * Write the current document to the filename, or it's original name
798 *
799 * Returns 0 or -1 in case of error
800 */
801int
802xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
803 xmlNodePtr node2) {
804 if (ctxt->doc == NULL)
805 return(-1);
806 if ((filename == NULL) || (filename[0] == 0))
807 filename = ctxt->filename;
808#ifdef W_OK
809 if (access((char *) filename, W_OK)) {
810 fprintf(stderr, "Cannot save to %s\n", filename);
811 return(-1);
812 }
813#endif
814 switch(ctxt->doc->type) {
815 case XML_DOCUMENT_NODE:
816 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
817 fprintf(stderr, "Failed to save to %s\n", filename);
818 }
819 break;
820 case XML_HTML_DOCUMENT_NODE:
821 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
822 fprintf(stderr, "Failed to save to %s\n", filename);
823 }
824 break;
825 default:
826 fprintf(stderr,
827 "To save to subparts of a document use the 'write' command\n");
828 return(-1);
829
830 }
831 return(0);
832}
833
834/**
835 * xmlShellValidate:
836 * @ctxt: the shell context
837 * @dtd: the DTD URI (optionnal)
838 * @node: unused
839 * @node2: unused
840 *
841 * Implements the XML shell function "validate"
842 * Validate the document, if a DTD path is provided, then the validation
843 * is done against the given DTD.
844 *
845 * Returns 0 or -1 in case of error
846 */
847int
848xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
849 xmlNodePtr node2) {
850 xmlValidCtxt vctxt;
851 int res = -1;
852
853 vctxt.userData = stderr;
854 vctxt.error = (xmlValidityErrorFunc) fprintf;
855 vctxt.warning = (xmlValidityWarningFunc) fprintf;
856
857 if ((dtd == NULL) || (dtd[0] == 0)) {
858 res = xmlValidateDocument(&vctxt, ctxt->doc);
859 } else {
860 xmlDtdPtr subset;
861
862 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
863 if (subset != NULL) {
864 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
865
866 xmlFreeDtd(subset);
867 }
868 }
869 return(res);
870}
871
872/**
873 * xmlShellDu:
874 * @ctxt: the shell context
875 * @arg: unused
876 * @tree: a node defining a subtree
877 * @node2: unused
878 *
879 * Implements the XML shell function "du"
880 * show the structure of the subtree under node @tree
881 * If @tree is null, the command works on the current node.
882 *
883 * Returns 0 or -1 in case of error
884 */
885int
886xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
887 xmlNodePtr node2) {
888 xmlNodePtr node;
889 int indent = 0,i;
890
891 if (tree == NULL) return(-1);
892 node = tree;
893 while (node != NULL) {
894 if ((node->type == XML_DOCUMENT_NODE) ||
895 (node->type == XML_HTML_DOCUMENT_NODE)) {
896 printf("/\n");
897 } else if (node->type == XML_ELEMENT_NODE) {
898 for (i = 0;i < indent;i++)
899 printf(" ");
900 printf("%s\n", node->name);
901 } else {
902 }
903
904 /*
905 * Browse the full subtree, deep first
906 */
907
908 if ((node->type == XML_DOCUMENT_NODE) ||
909 (node->type == XML_HTML_DOCUMENT_NODE)) {
910 node = ((xmlDocPtr) node)->root;
911 } else if (node->childs != NULL) {
912 /* deep first */
913 node = node->childs;
914 indent++;
915 } else if ((node != tree) && (node->next != NULL)) {
916 /* then siblings */
917 node = node->next;
918 } else if (node != tree) {
919 /* go up to parents->next if needed */
920 while (node != tree) {
921 if (node->parent != NULL) {
922 node = node->parent;
923 indent--;
924 }
925 if ((node != tree) && (node->next != NULL)) {
926 node = node->next;
927 break;
928 }
929 if (node->parent == NULL) {
930 node = NULL;
931 break;
932 }
933 if (node == tree) {
934 node = NULL;
935 break;
936 }
937 }
938 /* exit condition */
939 if (node == tree)
940 node = NULL;
941 } else
942 node = NULL;
943 }
944 return(0);
945}
946
947/**
948 * xmlShellPwd:
949 * @ctxt: the shell context
950 * @buffer: the output buffer
951 * @tree: a node
952 * @node2: unused
953 *
954 * Implements the XML shell function "pwd"
955 * Show the full path from the root to the node, if needed building
956 * thumblers when similar elements exists at a given ancestor level.
957 * The output is compatible with XPath commands.
958 *
959 * Returns 0 or -1 in case of error
960 */
961int
962xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
963 xmlNodePtr node2) {
964 xmlNodePtr cur, tmp, next;
965 char buf[500];
966 char sep;
967 const char *name;
968 int occur = 0;
969
970 buffer[0] = 0;
971 if (node == NULL) return(-1);
972 cur = node;
973 do {
974 name = "";
975 sep= '?';
976 occur = 0;
977 if ((cur->type == XML_DOCUMENT_NODE) ||
978 (cur->type == XML_HTML_DOCUMENT_NODE)) {
979 sep = '/';
980 next = NULL;
981 } else if (cur->type == XML_ELEMENT_NODE) {
982 sep = '/';
983 name = (const char *)cur->name;
984 next = cur->parent;
985
986 /*
987 * Thumbler index computation
988 */
989 tmp = cur->prev;
990 while (tmp != NULL) {
991 if (!xmlStrcmp(cur->name, tmp->name))
992 occur++;
993 tmp = tmp->prev;
994 }
995 if (occur == 0) {
996 tmp = cur->next;
997 while (tmp != NULL) {
998 if (!xmlStrcmp(cur->name, tmp->name))
999 occur++;
1000 tmp = tmp->next;
1001 }
1002 if (occur != 0) occur = 1;
1003 } else
1004 occur++;
1005 } else if (cur->type == XML_ATTRIBUTE_NODE) {
1006 sep = '@';
1007 name = (const char *) (((xmlAttrPtr) cur)->name);
1008 next = ((xmlAttrPtr) cur)->node;
1009 } else {
1010 next = cur->parent;
1011 }
1012 if (occur == 0)
1013 sprintf(buf, "%c%s%s", sep, name, buffer);
1014 else
1015 sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
1016 strcpy(buffer, buf);
1017 cur = next;
1018 } while (cur != NULL);
1019 return(0);
1020}
1021
1022/**
1023 * xmlShell
1024 * @doc: the initial document
1025 * @filename: the output buffer
1026 * @input: the line reading function
1027 * @output: the output FILE*
1028 *
1029 * Implements the XML shell
1030 * This allow to load, validate, view, modify and save a document
1031 * using a environment similar to a UNIX commandline.
1032 */
1033void
1034xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1035 FILE *output) {
1036 char prompt[500] = "/ > ";
1037 char *cmdline = NULL;
1038 int nbargs;
1039 char command[100];
1040 char arg[400];
1041 xmlShellCtxtPtr ctxt;
1042 xmlXPathObjectPtr list;
1043
1044 if (doc == NULL)
1045 return;
1046 if (filename == NULL)
1047 return;
1048 if (input == NULL)
1049 return;
1050 if (output == NULL)
1051 return;
1052 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1053 if (ctxt == NULL)
1054 return;
1055 ctxt->loaded = 0;
1056 ctxt->doc = doc;
1057 ctxt->input = input;
1058 ctxt->output = output;
1059 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1060 ctxt->node = (xmlNodePtr) ctxt->doc;
1061
1062 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1063 if (ctxt->pctxt == NULL) {
1064 xmlFree(ctxt);
1065 return;
1066 }
1067 while (1) {
1068 if (ctxt->node == (xmlNodePtr) ctxt->doc)
1069 sprintf(prompt, "%s > ", "/");
1070 else if (ctxt->node->name)
1071 sprintf(prompt, "%s > ", ctxt->node->name);
1072 else
1073 sprintf(prompt, "? > ");
1074
1075 cmdline = ctxt->input(prompt);
1076 if (cmdline == NULL) break;
1077
1078 command[0] = 0;
1079 arg[0] = 0;
1080 nbargs = sscanf(cmdline, "%s %s", command, arg);
1081
1082 if (command[0] == 0) continue;
1083 if (!strcmp(command, "exit"))
1084 break;
1085 if (!strcmp(command, "quit"))
1086 break;
1087 if (!strcmp(command, "bye"))
1088 break;
1089 if (!strcmp(command, "validate")) {
1090 xmlShellValidate(ctxt, arg, NULL, NULL);
1091 } else if (!strcmp(command, "load")) {
1092 xmlShellLoad(ctxt, arg, NULL, NULL);
1093 } else if (!strcmp(command, "save")) {
1094 xmlShellSave(ctxt, arg, NULL, NULL);
1095 } else if (!strcmp(command, "write")) {
1096 xmlShellWrite(ctxt, arg, NULL, NULL);
1097 } else if (!strcmp(command, "free")) {
1098 if (arg[0] == 0) {
1099 xmlMemShow(stdout, 0);
1100 } else {
1101 int len = 0;
1102 sscanf(arg, "%d", &len);
1103 xmlMemShow(stdout, len);
1104 }
1105 } else if (!strcmp(command, "pwd")) {
1106 char dir[500];
1107 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
1108 printf("%s\n", dir);
1109 } else if (!strcmp(command, "du")) {
1110 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
1111 } else if ((!strcmp(command, "ls")) ||
1112 (!strcmp(command, "dir"))) {
1113 int dir = (!strcmp(command, "dir"));
1114 if (arg[0] == 0) {
1115 if (dir)
1116 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
1117 else
1118 xmlShellList(ctxt, NULL, ctxt->node, NULL);
1119 } else {
1120 ctxt->pctxt->node = ctxt->node;
1121 if (ctxt->pctxt->nodelist != NULL)
1122 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1123 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1124 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1125 if (list != NULL) {
1126 switch (list->type) {
1127 case XPATH_UNDEFINED:
1128 fprintf(stderr, "%s: no such node\n", arg);
1129 break;
1130 case XPATH_NODESET: {
1131 int i;
1132
1133 for (i = 0;i < list->nodesetval->nodeNr;i++) {
1134 if (dir)
1135 xmlShellDir(ctxt, NULL,
1136 list->nodesetval->nodeTab[i], NULL);
1137 else
1138 xmlShellList(ctxt, NULL,
1139 list->nodesetval->nodeTab[i], NULL);
1140 }
1141 break;
1142 }
1143 case XPATH_BOOLEAN:
1144 fprintf(stderr, "%s is a Boolean\n", arg);
1145 break;
1146 case XPATH_NUMBER:
1147 fprintf(stderr, "%s is a number\n", arg);
1148 break;
1149 case XPATH_STRING:
1150 fprintf(stderr, "%s is a string\n", arg);
1151 break;
1152 }
1153 xmlXPathFreeNodeSetList(list);
1154 } else {
1155 fprintf(stderr, "%s: no such node\n", arg);
1156 }
1157 if (ctxt->pctxt->nodelist != NULL)
1158 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1159 ctxt->pctxt->nodelist = NULL;
1160 }
1161 } else if (!strcmp(command, "cd")) {
1162 if (arg[0] == 0) {
1163 ctxt->node = (xmlNodePtr) ctxt->doc;
1164 } else {
1165 ctxt->pctxt->node = ctxt->node;
1166 if (ctxt->pctxt->nodelist != NULL)
1167 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1168 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1169 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1170 if (list != NULL) {
1171 switch (list->type) {
1172 case XPATH_UNDEFINED:
1173 fprintf(stderr, "%s: no such node\n", arg);
1174 break;
1175 case XPATH_NODESET:
1176 if (list->nodesetval->nodeNr == 1) {
1177 ctxt->node = list->nodesetval->nodeTab[0];
1178 } else
1179 fprintf(stderr, "%s is a %d Node Set\n",
1180 arg, list->nodesetval->nodeNr);
1181 break;
1182 case XPATH_BOOLEAN:
1183 fprintf(stderr, "%s is a Boolean\n", arg);
1184 break;
1185 case XPATH_NUMBER:
1186 fprintf(stderr, "%s is a number\n", arg);
1187 break;
1188 case XPATH_STRING:
1189 fprintf(stderr, "%s is a string\n", arg);
1190 break;
1191 }
1192 xmlXPathFreeNodeSetList(list);
1193 } else {
1194 fprintf(stderr, "%s: no such node\n", arg);
1195 }
1196 if (ctxt->pctxt->nodelist != NULL)
1197 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1198 ctxt->pctxt->nodelist = NULL;
1199 }
1200 } else if (!strcmp(command, "cat")) {
1201 if (arg[0] == 0) {
1202 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
1203 } else {
1204 ctxt->pctxt->node = ctxt->node;
1205 if (ctxt->pctxt->nodelist != NULL)
1206 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1207 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1208 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1209 if (list != NULL) {
1210 switch (list->type) {
1211 case XPATH_UNDEFINED:
1212 fprintf(stderr, "%s: no such node\n", arg);
1213 break;
1214 case XPATH_NODESET: {
1215 int i;
1216
1217 for (i = 0;i < list->nodesetval->nodeNr;i++) {
1218 if (i > 0) printf(" -------\n");
1219 xmlShellCat(ctxt, NULL,
1220 list->nodesetval->nodeTab[i], NULL);
1221 }
1222 break;
1223 }
1224 case XPATH_BOOLEAN:
1225 fprintf(stderr, "%s is a Boolean\n", arg);
1226 break;
1227 case XPATH_NUMBER:
1228 fprintf(stderr, "%s is a number\n", arg);
1229 break;
1230 case XPATH_STRING:
1231 fprintf(stderr, "%s is a string\n", arg);
1232 break;
1233 }
1234 xmlXPathFreeNodeSetList(list);
1235 } else {
1236 fprintf(stderr, "%s: no such node\n", arg);
1237 }
1238 if (ctxt->pctxt->nodelist != NULL)
1239 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1240 ctxt->pctxt->nodelist = NULL;
1241 }
1242 } else {
1243 fprintf(stderr, "Unknown command %s\n", command);
1244 }
1245 free(cmdline); /* not xmlFree here ! */
1246 }
1247 xmlXPathFreeContext(ctxt->pctxt);
1248 if (ctxt->loaded) {
1249 xmlFreeDoc(ctxt->doc);
1250 }
1251 xmlFree(ctxt);
1252 if (cmdline != NULL)
1253 free(cmdline); /* not xmlFree here ! */
1254}
1255