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