Initial revision
[TestXSLT.git] / libxml2 / debugXML.c
1 /*
2  * debugXML.c : This is a set of routines used for debugging the tree
3  *              produced by the XML parser.
4  *
5  * See Copyright for the status of this software.
6  *
7  * Daniel Veillard <daniel@veillard.com>
8  */
9
10 #define IN_LIBXML
11 #include "libxml.h"
12 #ifdef LIBXML_DEBUG_ENABLED
13
14 #include <string.h>
15 #ifdef HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18 #ifdef HAVE_STRING_H
19 #include <string.h>
20 #endif
21 #include <libxml/xmlmemory.h>
22 #include <libxml/tree.h>
23 #include <libxml/parser.h>
24 #include <libxml/parserInternals.h>
25 #include <libxml/valid.h>
26 #include <libxml/debugXML.h>
27 #include <libxml/HTMLtree.h>
28 #include <libxml/HTMLparser.h>
29 #include <libxml/xmlerror.h>
30 #include <libxml/globals.h>
31 #include <libxml/xpathInternals.h>
32
33 /**
34  * xmlDebugDumpString:
35  * @output:  the FILE * for the output
36  * @str:  the string
37  *
38  * Dumps informations about the string, shorten it if necessary
39  */
40 void
41 xmlDebugDumpString(FILE * output, const xmlChar * str)
42 {
43     int i;
44
45     if (output == NULL)
46         output = stdout;
47     if (str == NULL) {
48         fprintf(output, "(NULL)");
49         return;
50     }
51     for (i = 0; i < 40; i++)
52         if (str[i] == 0)
53             return;
54         else if (IS_BLANK(str[i]))
55             fputc(' ', output);
56         else if (str[i] >= 0x80)
57             fprintf(output, "#%X", str[i]);
58         else
59             fputc(str[i], output);
60     fprintf(output, "...");
61 }
62
63 static void
64 xmlDebugDumpDtdNode(FILE *output, xmlDtdPtr dtd, int depth) {
65     int i;
66     char shift[100];
67
68     for (i = 0;((i < depth) && (i < 25));i++)
69         shift[2 * i] = shift[2 * i + 1] = ' ';
70     shift[2 * i] = shift[2 * i + 1] = 0;
71
72     fprintf(output, shift);
73
74     if (dtd == NULL) {
75         fprintf(output, "DTD node is NULL\n");
76         return;
77     }
78
79     if (dtd->type != XML_DTD_NODE) {
80         fprintf(output, "PBM: not a DTD\n");
81         return;
82     }
83     if (dtd->name != NULL)
84         fprintf(output, "DTD(%s)", dtd->name);
85     else
86         fprintf(output, "DTD");
87     if (dtd->ExternalID != NULL)
88         fprintf(output, ", PUBLIC %s", dtd->ExternalID);
89     if (dtd->SystemID != NULL)
90         fprintf(output, ", SYSTEM %s", dtd->SystemID);
91     fprintf(output, "\n");
92     /*
93      * Do a bit of checking
94      */
95     if (dtd->parent == NULL)
96         fprintf(output, "PBM: DTD has no parent\n");
97     if (dtd->doc == NULL)
98         fprintf(output, "PBM: DTD has no doc\n");
99     if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
100         fprintf(output, "PBM: DTD doc differs from parent's one\n");
101     if (dtd->prev == NULL) {
102         if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
103             fprintf(output, "PBM: DTD has no prev and not first of list\n");
104     } else {
105         if (dtd->prev->next != (xmlNodePtr) dtd)
106             fprintf(output, "PBM: DTD prev->next : back link wrong\n");
107     }
108     if (dtd->next == NULL) {
109         if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
110             fprintf(output, "PBM: DTD has no next and not last of list\n");
111     } else {
112         if (dtd->next->prev != (xmlNodePtr) dtd)
113             fprintf(output, "PBM: DTD next->prev : forward link wrong\n");
114     }
115 }
116
117 static void
118 xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) {
119     int i;
120     char shift[100];
121
122     for (i = 0;((i < depth) && (i < 25));i++)
123         shift[2 * i] = shift[2 * i + 1] = ' ';
124     shift[2 * i] = shift[2 * i + 1] = 0;
125
126     fprintf(output, shift);
127
128     if (attr == NULL) {
129         fprintf(output, "Attribute declaration is NULL\n");
130         return;
131     }
132     if (attr->type != XML_ATTRIBUTE_DECL) {
133         fprintf(output, "PBM: not a Attr\n");
134         return;
135     }
136     if (attr->name != NULL)
137         fprintf(output, "ATTRDECL(%s)", attr->name);
138     else
139         fprintf(output, "PBM ATTRDECL noname!!!");
140     if (attr->elem != NULL)
141         fprintf(output, " for %s", attr->elem);
142     else
143         fprintf(output, " PBM noelem!!!");
144     switch (attr->atype) {
145         case XML_ATTRIBUTE_CDATA:
146             fprintf(output, " CDATA");
147             break;
148         case XML_ATTRIBUTE_ID:
149             fprintf(output, " ID");
150             break;
151         case XML_ATTRIBUTE_IDREF:
152             fprintf(output, " IDREF");
153             break;
154         case XML_ATTRIBUTE_IDREFS:
155             fprintf(output, " IDREFS");
156             break;
157         case XML_ATTRIBUTE_ENTITY:
158             fprintf(output, " ENTITY");
159             break;
160         case XML_ATTRIBUTE_ENTITIES:
161             fprintf(output, " ENTITIES");
162             break;
163         case XML_ATTRIBUTE_NMTOKEN:
164             fprintf(output, " NMTOKEN");
165             break;
166         case XML_ATTRIBUTE_NMTOKENS:
167             fprintf(output, " NMTOKENS");
168             break;
169         case XML_ATTRIBUTE_ENUMERATION:
170             fprintf(output, " ENUMERATION");
171             break;
172         case XML_ATTRIBUTE_NOTATION:
173             fprintf(output, " NOTATION ");
174             break;
175     }
176     if (attr->tree != NULL) {
177         int indx;
178         xmlEnumerationPtr cur = attr->tree;
179
180         for (indx = 0;indx < 5; indx++) {
181             if (indx != 0)
182                 fprintf(output, "|%s", cur->name);
183             else
184                 fprintf(output, " (%s", cur->name);
185             cur = cur->next;
186             if (cur == NULL) break;
187         }
188         if (cur == NULL)
189             fprintf(output, ")");
190         else
191             fprintf(output, "...)");
192     }
193     switch (attr->def) {
194         case XML_ATTRIBUTE_NONE:
195             break;
196         case XML_ATTRIBUTE_REQUIRED:
197             fprintf(output, " REQUIRED");
198             break;
199         case XML_ATTRIBUTE_IMPLIED:
200             fprintf(output, " IMPLIED");
201             break;
202         case XML_ATTRIBUTE_FIXED:
203             fprintf(output, " FIXED");
204             break;
205     }
206     if (attr->defaultValue != NULL) {
207         fprintf(output, "\"");
208         xmlDebugDumpString(output, attr->defaultValue);
209         fprintf(output, "\"");
210     }
211     fprintf(output, "\n");
212
213     /*
214      * Do a bit of checking
215      */
216     if (attr->parent == NULL)
217         fprintf(output, "PBM: Attr has no parent\n");
218     if (attr->doc == NULL)
219         fprintf(output, "PBM: Attr has no doc\n");
220     if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
221         fprintf(output, "PBM: Attr doc differs from parent's one\n");
222     if (attr->prev == NULL) {
223         if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr))
224             fprintf(output, "PBM: Attr has no prev and not first of list\n");
225     } else {
226         if (attr->prev->next != (xmlNodePtr) attr)
227             fprintf(output, "PBM: Attr prev->next : back link wrong\n");
228     }
229     if (attr->next == NULL) {
230         if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr))
231             fprintf(output, "PBM: Attr has no next and not last of list\n");
232     } else {
233         if (attr->next->prev != (xmlNodePtr) attr)
234             fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
235     }
236 }
237
238 static void
239 xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) {
240     int i;
241     char shift[100];
242
243     for (i = 0;((i < depth) && (i < 25));i++)
244         shift[2 * i] = shift[2 * i + 1] = ' ';
245     shift[2 * i] = shift[2 * i + 1] = 0;
246
247     fprintf(output, shift);
248
249     if (elem == NULL) {
250         fprintf(output, "Element declaration is NULL\n");
251         return;
252     }
253     if (elem->type != XML_ELEMENT_DECL) {
254         fprintf(output, "PBM: not a Elem\n");
255         return;
256     }
257     if (elem->name != NULL) {
258         fprintf(output, "ELEMDECL(");
259         xmlDebugDumpString(output, elem->name);
260         fprintf(output, ")");
261     } else
262         fprintf(output, "PBM ELEMDECL noname!!!");
263     switch (elem->etype) {
264         case XML_ELEMENT_TYPE_UNDEFINED: 
265             fprintf(output, ", UNDEFINED");
266             break;
267         case XML_ELEMENT_TYPE_EMPTY: 
268             fprintf(output, ", EMPTY");
269             break;
270         case XML_ELEMENT_TYPE_ANY: 
271             fprintf(output, ", ANY");
272             break;
273         case XML_ELEMENT_TYPE_MIXED: 
274             fprintf(output, ", MIXED ");
275             break;
276         case XML_ELEMENT_TYPE_ELEMENT: 
277             fprintf(output, ", MIXED ");
278             break;
279     }
280     if ((elem->type != XML_ELEMENT_NODE) &&
281         (elem->content != NULL)) {
282         char buf[5001];
283
284         buf[0] = 0;
285         xmlSnprintfElementContent(buf, 5000, elem->content, 1);
286         buf[5000] = 0;
287         fprintf(output, "%s", buf);
288     }
289     fprintf(output, "\n");
290
291     /*
292      * Do a bit of checking
293      */
294     if (elem->parent == NULL)
295         fprintf(output, "PBM: Elem has no parent\n");
296     if (elem->doc == NULL)
297         fprintf(output, "PBM: Elem has no doc\n");
298     if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
299         fprintf(output, "PBM: Elem doc differs from parent's one\n");
300     if (elem->prev == NULL) {
301         if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem))
302             fprintf(output, "PBM: Elem has no prev and not first of list\n");
303     } else {
304         if (elem->prev->next != (xmlNodePtr) elem)
305             fprintf(output, "PBM: Elem prev->next : back link wrong\n");
306     }
307     if (elem->next == NULL) {
308         if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem))
309             fprintf(output, "PBM: Elem has no next and not last of list\n");
310     } else {
311         if (elem->next->prev != (xmlNodePtr) elem)
312             fprintf(output, "PBM: Elem next->prev : forward link wrong\n");
313     }
314 }
315
316 static void
317 xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) {
318     int i;
319     char shift[100];
320
321     for (i = 0;((i < depth) && (i < 25));i++)
322         shift[2 * i] = shift[2 * i + 1] = ' ';
323     shift[2 * i] = shift[2 * i + 1] = 0;
324
325     fprintf(output, shift);
326
327     if (ent == NULL) {
328         fprintf(output, "Entity declaration is NULL\n");
329         return;
330     }
331     if (ent->type != XML_ENTITY_DECL) {
332         fprintf(output, "PBM: not a Entity decl\n");
333         return;
334     }
335     if (ent->name != NULL) {
336         fprintf(output, "ENTITYDECL(");
337         xmlDebugDumpString(output, ent->name);
338         fprintf(output, ")");
339     } else
340         fprintf(output, "PBM ENTITYDECL noname!!!");
341     switch (ent->etype) {
342         case XML_INTERNAL_GENERAL_ENTITY: 
343             fprintf(output, ", internal\n");
344             break;
345         case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 
346             fprintf(output, ", external parsed\n");
347             break;
348         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 
349             fprintf(output, ", unparsed\n");
350             break;
351         case XML_INTERNAL_PARAMETER_ENTITY: 
352             fprintf(output, ", parameter\n");
353             break;
354         case XML_EXTERNAL_PARAMETER_ENTITY: 
355             fprintf(output, ", external parameter\n");
356             break;
357         case XML_INTERNAL_PREDEFINED_ENTITY: 
358             fprintf(output, ", predefined\n");
359             break;
360     }
361     if (ent->ExternalID) {
362         fprintf(output, shift);
363         fprintf(output, " ExternalID=%s\n", ent->ExternalID);
364     }
365     if (ent->SystemID) {
366         fprintf(output, shift);
367         fprintf(output, " SystemID=%s\n", ent->SystemID);
368     }
369     if (ent->URI != NULL) {
370         fprintf(output, shift);
371         fprintf(output, " URI=%s\n", ent->URI);
372     }
373     if (ent->content) {
374         fprintf(output, shift);
375         fprintf(output, " content=");
376         xmlDebugDumpString(output, ent->content);
377         fprintf(output, "\n");
378     }
379
380     /*
381      * Do a bit of checking
382      */
383     if (ent->parent == NULL)
384         fprintf(output, "PBM: Ent has no parent\n");
385     if (ent->doc == NULL)
386         fprintf(output, "PBM: Ent has no doc\n");
387     if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
388         fprintf(output, "PBM: Ent doc differs from parent's one\n");
389     if (ent->prev == NULL) {
390         if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent))
391             fprintf(output, "PBM: Ent has no prev and not first of list\n");
392     } else {
393         if (ent->prev->next != (xmlNodePtr) ent)
394             fprintf(output, "PBM: Ent prev->next : back link wrong\n");
395     }
396     if (ent->next == NULL) {
397         if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent))
398             fprintf(output, "PBM: Ent has no next and not last of list\n");
399     } else {
400         if (ent->next->prev != (xmlNodePtr) ent)
401             fprintf(output, "PBM: Ent next->prev : forward link wrong\n");
402     }
403 }
404
405 static void
406 xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
407     int i;
408     char shift[100];
409
410     for (i = 0;((i < depth) && (i < 25));i++)
411         shift[2 * i] = shift[2 * i + 1] = ' ';
412     shift[2 * i] = shift[2 * i + 1] = 0;
413
414     fprintf(output, shift);
415
416     if (ns == NULL) {
417         fprintf(output, "namespace node is NULL\n");
418         return;
419     }
420     if (ns->type != XML_NAMESPACE_DECL) {
421         fprintf(output, "invalid namespace node %d\n", ns->type);
422         return;
423     }
424     if (ns->href == NULL) {
425         if (ns->prefix != NULL)
426             fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix);
427         else
428             fprintf(output, "incomplete default namespace href=NULL\n");
429     } else {
430         if (ns->prefix != NULL)
431             fprintf(output, "namespace %s href=", ns->prefix);
432         else
433             fprintf(output, "default namespace href=");
434
435         xmlDebugDumpString(output, ns->href);
436         fprintf(output, "\n");
437     }
438 }
439
440 static void
441 xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
442     while (ns != NULL) {
443         xmlDebugDumpNamespace(output, ns, depth);
444         ns = ns->next;
445     }
446 }
447
448 static void
449 xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
450     int i;
451     char shift[100];
452
453     for (i = 0;((i < depth) && (i < 25));i++)
454         shift[2 * i] = shift[2 * i + 1] = ' ';
455     shift[2 * i] = shift[2 * i + 1] = 0;
456
457     fprintf(output, shift);
458     
459     if (ent == NULL) {
460         fprintf(output, "Entity is NULL\n");
461         return;
462     }
463     switch (ent->etype) {
464         case XML_INTERNAL_GENERAL_ENTITY:
465             fprintf(output, "INTERNAL_GENERAL_ENTITY ");
466             break;
467         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
468             fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
469             break;
470         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
471             fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
472             break;
473         case XML_INTERNAL_PARAMETER_ENTITY:
474             fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
475             break;
476         case XML_EXTERNAL_PARAMETER_ENTITY:
477             fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
478             break;
479         default:
480             fprintf(output, "ENTITY_%d ! ", ent->etype);
481     }
482     fprintf(output, "%s\n", ent->name);
483     if (ent->ExternalID) {
484         fprintf(output, shift);
485         fprintf(output, "ExternalID=%s\n", ent->ExternalID);
486     }
487     if (ent->SystemID) {
488         fprintf(output, shift);
489         fprintf(output, "SystemID=%s\n", ent->SystemID);
490     }
491     if (ent->URI) {
492         fprintf(output, shift);
493         fprintf(output, "URI=%s\n", ent->URI);
494     }
495     if (ent->content) {
496         fprintf(output, shift);
497         fprintf(output, "content=");
498         xmlDebugDumpString(output, ent->content);
499         fprintf(output, "\n");
500     }
501 }
502
503 /**
504  * xmlDebugDumpAttr:
505  * @output:  the FILE * for the output
506  * @attr:  the attribute
507  * @depth:  the indentation level.
508  *
509  * Dumps debug information for the attribute
510  */
511 void
512 xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
513     int i;
514     char shift[100];
515
516     for (i = 0;((i < depth) && (i < 25));i++)
517         shift[2 * i] = shift[2 * i + 1] = ' ';
518     shift[2 * i] = shift[2 * i + 1] = 0;
519
520     fprintf(output, shift);
521     
522     if (attr == NULL) {
523         fprintf(output, "Attr is NULL");
524         return;
525     }
526     fprintf(output, "ATTRIBUTE ");
527     xmlDebugDumpString(output, attr->name);
528     fprintf(output, "\n");
529     if (attr->children != NULL) 
530         xmlDebugDumpNodeList(output, attr->children, depth + 1);
531
532     /*
533      * Do a bit of checking
534      */
535     if (attr->parent == NULL)
536         fprintf(output, "PBM: Attr has no parent\n");
537     if (attr->doc == NULL)
538         fprintf(output, "PBM: Attr has no doc\n");
539     if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
540         fprintf(output, "PBM: Attr doc differs from parent's one\n");
541     if (attr->prev == NULL) {
542         if ((attr->parent != NULL) && (attr->parent->properties != attr))
543             fprintf(output, "PBM: Attr has no prev and not first of list\n");
544     } else {
545         if (attr->prev->next != attr)
546             fprintf(output, "PBM: Attr prev->next : back link wrong\n");
547     }
548     if (attr->next != NULL) {
549         if (attr->next->prev != attr)
550             fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
551     }
552 }
553
554 /**
555  * xmlDebugDumpAttrList:
556  * @output:  the FILE * for the output
557  * @attr:  the attribute list
558  * @depth:  the indentation level.
559  *
560  * Dumps debug information for the attribute list
561  */
562 void
563 xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
564 {
565     if (output == NULL)
566         output = stdout;
567     while (attr != NULL) {
568         xmlDebugDumpAttr(output, attr, depth);
569         attr = attr->next;
570     }
571 }
572
573 /**
574  * xmlDebugDumpOneNode:
575  * @output:  the FILE * for the output
576  * @node:  the node
577  * @depth:  the indentation level.
578  *
579  * Dumps debug information for the element node, it is not recursive
580  */
581 void
582 xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
583 {
584     int i;
585     char shift[100];
586
587     if (output == NULL)
588         output = stdout;
589     for (i = 0; ((i < depth) && (i < 25)); i++)
590         shift[2 * i] = shift[2 * i + 1] = ' ';
591     shift[2 * i] = shift[2 * i + 1] = 0;
592
593     if (node == NULL) {
594         fprintf(output, shift);
595         fprintf(output, "node is NULL\n");
596         return;
597     }
598     switch (node->type) {
599         case XML_ELEMENT_NODE:
600             fprintf(output, shift);
601             fprintf(output, "ELEMENT ");
602             if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
603                 xmlDebugDumpString(output, node->ns->prefix);
604                 fprintf(output, ":");
605             }
606             xmlDebugDumpString(output, node->name);
607             fprintf(output, "\n");
608             break;
609         case XML_ATTRIBUTE_NODE:
610             fprintf(output, shift);
611             fprintf(output, "Error, ATTRIBUTE found here\n");
612             break;
613         case XML_TEXT_NODE:
614             fprintf(output, shift);
615             if (node->name == (const xmlChar *) xmlStringTextNoenc)
616                 fprintf(output, "TEXT no enc\n");
617             else
618                 fprintf(output, "TEXT\n");
619             break;
620         case XML_CDATA_SECTION_NODE:
621             fprintf(output, shift);
622             fprintf(output, "CDATA_SECTION\n");
623             break;
624         case XML_ENTITY_REF_NODE:
625             fprintf(output, shift);
626             fprintf(output, "ENTITY_REF(%s)\n", node->name);
627             break;
628         case XML_ENTITY_NODE:
629             fprintf(output, shift);
630             fprintf(output, "ENTITY\n");
631             break;
632         case XML_PI_NODE:
633             fprintf(output, shift);
634             fprintf(output, "PI %s\n", node->name);
635             break;
636         case XML_COMMENT_NODE:
637             fprintf(output, shift);
638             fprintf(output, "COMMENT\n");
639             break;
640         case XML_DOCUMENT_NODE:
641         case XML_HTML_DOCUMENT_NODE:
642             fprintf(output, shift);
643             fprintf(output, "Error, DOCUMENT found here\n");
644             break;
645         case XML_DOCUMENT_TYPE_NODE:
646             fprintf(output, shift);
647             fprintf(output, "DOCUMENT_TYPE\n");
648             break;
649         case XML_DOCUMENT_FRAG_NODE:
650             fprintf(output, shift);
651             fprintf(output, "DOCUMENT_FRAG\n");
652             break;
653         case XML_NOTATION_NODE:
654             fprintf(output, shift);
655             fprintf(output, "NOTATION\n");
656             break;
657         case XML_DTD_NODE:
658             xmlDebugDumpDtdNode(output, (xmlDtdPtr) node, depth);
659             return;
660         case XML_ELEMENT_DECL:
661             xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
662             return;
663         case XML_ATTRIBUTE_DECL:
664             xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
665             return;
666         case XML_ENTITY_DECL:
667             xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
668             return;
669         case XML_NAMESPACE_DECL:
670             xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
671             return;
672         case XML_XINCLUDE_START:
673             fprintf(output, shift);
674             fprintf(output, "INCLUDE START\n");
675             return;
676         case XML_XINCLUDE_END:
677             fprintf(output, shift);
678             fprintf(output, "INCLUDE END\n");
679             return;
680         default:
681             fprintf(output, shift);
682             fprintf(output, "NODE_%d !!!\n", node->type);
683             return;
684     }
685     if (node->doc == NULL) {
686         fprintf(output, shift);
687         fprintf(output, "doc == NULL !!!\n");
688     }
689     if (node->nsDef != NULL)
690         xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
691     if (node->properties != NULL)
692         xmlDebugDumpAttrList(output, node->properties, depth + 1);
693     if (node->type != XML_ENTITY_REF_NODE) {
694         if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
695             shift[2 * i] = shift[2 * i + 1] = ' ';
696             shift[2 * i + 2] = shift[2 * i + 3] = 0;
697             fprintf(output, shift);
698             fprintf(output, "content=");
699             xmlDebugDumpString(output, node->content);
700             fprintf(output, "\n");
701         }
702     } else {
703         xmlEntityPtr ent;
704
705         ent = xmlGetDocEntity(node->doc, node->name);
706         if (ent != NULL)
707             xmlDebugDumpEntity(output, ent, depth + 1);
708     }
709     /*
710      * Do a bit of checking
711      */
712     if (node->parent == NULL)
713         fprintf(output, "PBM: Node has no parent\n");
714     if (node->doc == NULL)
715         fprintf(output, "PBM: Node has no doc\n");
716     if ((node->parent != NULL) && (node->doc != node->parent->doc))
717         fprintf(output, "PBM: Node doc differs from parent's one\n");
718     if (node->prev == NULL) {
719         if ((node->parent != NULL) && (node->parent->children != node))
720             fprintf(output,
721                     "PBM: Node has no prev and not first of list\n");
722     } else {
723         if (node->prev->next != node)
724             fprintf(output, "PBM: Node prev->next : back link wrong\n");
725     }
726     if (node->next == NULL) {
727         if ((node->parent != NULL) && (node->parent->last != node))
728             fprintf(output,
729                     "PBM: Node has no next and not last of list\n");
730     } else {
731         if (node->next->prev != node)
732             fprintf(output, "PBM: Node next->prev : forward link wrong\n");
733     }
734 }
735
736 /**
737  * xmlDebugDumpNode:
738  * @output:  the FILE * for the output
739  * @node:  the node
740  * @depth:  the indentation level.
741  *
742  * Dumps debug information for the element node, it is recursive
743  */
744 void
745 xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
746 {
747     if (output == NULL)
748         output = stdout;
749     if (node == NULL) {
750         int i;
751         char shift[100];
752         
753         for (i = 0; ((i < depth) && (i < 25)); i++)
754             shift[2 * i] = shift[2 * i + 1] = ' ';
755         shift[2 * i] = shift[2 * i + 1] = 0;
756         
757         fprintf(output, shift);
758         fprintf(output, "node is NULL\n");
759         return;
760     }   
761     xmlDebugDumpOneNode(output, node, depth);
762     if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
763         xmlDebugDumpNodeList(output, node->children, depth + 1);
764 }
765
766 /**
767  * xmlDebugDumpNodeList:
768  * @output:  the FILE * for the output
769  * @node:  the node list
770  * @depth:  the indentation level.
771  *
772  * Dumps debug information for the list of element node, it is recursive
773  */
774 void
775 xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
776 {
777     if (output == NULL)
778         output = stdout;
779     while (node != NULL) {
780         xmlDebugDumpNode(output, node, depth);
781         node = node->next;
782     }
783 }
784
785
786 /**
787  * xmlDebugDumpDocumentHead:
788  * @output:  the FILE * for the output
789  * @doc:  the document
790  *
791  * Dumps debug information cncerning the document, not recursive
792  */
793 void
794 xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
795 {
796     if (output == NULL)
797         output = stdout;
798     if (doc == NULL) {
799         fprintf(output, "DOCUMENT == NULL !\n");
800         return;
801     }
802
803     switch (doc->type) {
804         case XML_ELEMENT_NODE:
805             fprintf(output, "Error, ELEMENT found here ");
806             break;
807         case XML_ATTRIBUTE_NODE:
808             fprintf(output, "Error, ATTRIBUTE found here\n");
809             break;
810         case XML_TEXT_NODE:
811             fprintf(output, "Error, TEXT\n");
812             break;
813         case XML_CDATA_SECTION_NODE:
814             fprintf(output, "Error, CDATA_SECTION\n");
815             break;
816         case XML_ENTITY_REF_NODE:
817             fprintf(output, "Error, ENTITY_REF\n");
818             break;
819         case XML_ENTITY_NODE:
820             fprintf(output, "Error, ENTITY\n");
821             break;
822         case XML_PI_NODE:
823             fprintf(output, "Error, PI\n");
824             break;
825         case XML_COMMENT_NODE:
826             fprintf(output, "Error, COMMENT\n");
827             break;
828         case XML_DOCUMENT_NODE:
829             fprintf(output, "DOCUMENT\n");
830             break;
831         case XML_HTML_DOCUMENT_NODE:
832             fprintf(output, "HTML DOCUMENT\n");
833             break;
834         case XML_DOCUMENT_TYPE_NODE:
835             fprintf(output, "Error, DOCUMENT_TYPE\n");
836             break;
837         case XML_DOCUMENT_FRAG_NODE:
838             fprintf(output, "Error, DOCUMENT_FRAG\n");
839             break;
840         case XML_NOTATION_NODE:
841             fprintf(output, "Error, NOTATION\n");
842             break;
843         default:
844             fprintf(output, "NODE_%d\n", doc->type);
845     }
846     if (doc->name != NULL) {
847         fprintf(output, "name=");
848         xmlDebugDumpString(output, BAD_CAST doc->name);
849         fprintf(output, "\n");
850     }
851     if (doc->version != NULL) {
852         fprintf(output, "version=");
853         xmlDebugDumpString(output, doc->version);
854         fprintf(output, "\n");
855     }
856     if (doc->encoding != NULL) {
857         fprintf(output, "encoding=");
858         xmlDebugDumpString(output, doc->encoding);
859         fprintf(output, "\n");
860     }
861     if (doc->URL != NULL) {
862         fprintf(output, "URL=");
863         xmlDebugDumpString(output, doc->URL);
864         fprintf(output, "\n");
865     }
866     if (doc->standalone)
867         fprintf(output, "standalone=true\n");
868     if (doc->oldNs != NULL)
869         xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
870 }
871
872 /**
873  * xmlDebugDumpDocument:
874  * @output:  the FILE * for the output
875  * @doc:  the document
876  *
877  * Dumps debug information for the document, it's recursive
878  */
879 void
880 xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
881 {
882     if (output == NULL)
883         output = stdout;
884     if (doc == NULL) {
885         fprintf(output, "DOCUMENT == NULL !\n");
886         return;
887     }
888     xmlDebugDumpDocumentHead(output, doc);
889     if (((doc->type == XML_DOCUMENT_NODE) ||
890          (doc->type == XML_HTML_DOCUMENT_NODE)) && (doc->children != NULL))
891         xmlDebugDumpNodeList(output, doc->children, 1);
892 }
893
894 /**
895  * xmlDebugDumpDTD:
896  * @output:  the FILE * for the output
897  * @dtd:  the DTD
898  *
899  * Dumps debug information for the DTD
900  */
901 void
902 xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
903 {
904     if (output == NULL)
905         output = stdout;
906     if (dtd == NULL) {
907         fprintf(output, "DTD is NULL\n");
908         return;
909     }
910     if (dtd->type != XML_DTD_NODE) {
911         fprintf(output, "PBM: not a DTD\n");
912         return;
913     }
914     if (dtd->name != NULL)
915         fprintf(output, "DTD(%s)", dtd->name);
916     else
917         fprintf(output, "DTD");
918     if (dtd->ExternalID != NULL)
919         fprintf(output, ", PUBLIC %s", dtd->ExternalID);
920     if (dtd->SystemID != NULL)
921         fprintf(output, ", SYSTEM %s", dtd->SystemID);
922     fprintf(output, "\n");
923     /*
924      * Do a bit of checking
925      */
926     if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
927         fprintf(output, "PBM: DTD doc differs from parent's one\n");
928     if (dtd->prev == NULL) {
929         if ((dtd->parent != NULL)
930             && (dtd->parent->children != (xmlNodePtr) dtd))
931             fprintf(output,
932                     "PBM: DTD has no prev and not first of list\n");
933     } else {
934         if (dtd->prev->next != (xmlNodePtr) dtd)
935             fprintf(output, "PBM: DTD prev->next : back link wrong\n");
936     }
937     if (dtd->next == NULL) {
938         if ((dtd->parent != NULL)
939             && (dtd->parent->last != (xmlNodePtr) dtd))
940             fprintf(output, "PBM: DTD has no next and not last of list\n");
941     } else {
942         if (dtd->next->prev != (xmlNodePtr) dtd)
943             fprintf(output, "PBM: DTD next->prev : forward link wrong\n");
944     }
945     if (dtd->children == NULL)
946         fprintf(output, "    DTD is empty\n");
947     else
948         xmlDebugDumpNodeList(output, dtd->children, 1);
949 }
950
951 static void
952 xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output) {
953     if (cur == NULL) {
954         fprintf(output, "Entity is NULL");
955         return;
956     }
957     fprintf(output, "%s : ", cur->name);
958     switch (cur->etype) {
959         case XML_INTERNAL_GENERAL_ENTITY:
960             fprintf(output, "INTERNAL GENERAL, ");
961             break;
962         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
963             fprintf(output, "EXTERNAL PARSED, ");
964             break;
965         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
966             fprintf(output, "EXTERNAL UNPARSED, ");
967             break;
968         case XML_INTERNAL_PARAMETER_ENTITY:
969             fprintf(output, "INTERNAL PARAMETER, ");
970             break;
971         case XML_EXTERNAL_PARAMETER_ENTITY:
972             fprintf(output, "EXTERNAL PARAMETER, ");
973             break;
974         default:
975             fprintf(output, "UNKNOWN TYPE %d",
976                     cur->etype);
977     }
978     if (cur->ExternalID != NULL) 
979         fprintf(output, "ID \"%s\"", cur->ExternalID);
980     if (cur->SystemID != NULL)
981         fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
982     if (cur->orig != NULL)
983         fprintf(output, "\n orig \"%s\"", cur->orig);
984     if ((cur->type != XML_ELEMENT_NODE) &&
985         (cur->content != NULL))
986         fprintf(output, "\n content \"%s\"", cur->content);
987     fprintf(output, "\n");      
988 }
989
990 /**
991  * xmlDebugDumpEntities:
992  * @output:  the FILE * for the output
993  * @doc:  the document
994  *
995  * Dumps debug information for all the entities in use by the document
996  */
997 void
998 xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
999 {
1000     if (output == NULL)
1001         output = stdout;
1002     if (doc == NULL) {
1003         fprintf(output, "DOCUMENT == NULL !\n");
1004         return;
1005     }
1006
1007     switch (doc->type) {
1008         case XML_ELEMENT_NODE:
1009             fprintf(output, "Error, ELEMENT found here ");
1010             break;
1011         case XML_ATTRIBUTE_NODE:
1012             fprintf(output, "Error, ATTRIBUTE found here\n");
1013             break;
1014         case XML_TEXT_NODE:
1015             fprintf(output, "Error, TEXT\n");
1016             break;
1017         case XML_CDATA_SECTION_NODE:
1018             fprintf(output, "Error, CDATA_SECTION\n");
1019             break;
1020         case XML_ENTITY_REF_NODE:
1021             fprintf(output, "Error, ENTITY_REF\n");
1022             break;
1023         case XML_ENTITY_NODE:
1024             fprintf(output, "Error, ENTITY\n");
1025             break;
1026         case XML_PI_NODE:
1027             fprintf(output, "Error, PI\n");
1028             break;
1029         case XML_COMMENT_NODE:
1030             fprintf(output, "Error, COMMENT\n");
1031             break;
1032         case XML_DOCUMENT_NODE:
1033             fprintf(output, "DOCUMENT\n");
1034             break;
1035         case XML_HTML_DOCUMENT_NODE:
1036             fprintf(output, "HTML DOCUMENT\n");
1037             break;
1038         case XML_DOCUMENT_TYPE_NODE:
1039             fprintf(output, "Error, DOCUMENT_TYPE\n");
1040             break;
1041         case XML_DOCUMENT_FRAG_NODE:
1042             fprintf(output, "Error, DOCUMENT_FRAG\n");
1043             break;
1044         case XML_NOTATION_NODE:
1045             fprintf(output, "Error, NOTATION\n");
1046             break;
1047         default:
1048             fprintf(output, "NODE_%d\n", doc->type);
1049     }
1050     if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1051         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1052             doc->intSubset->entities;
1053
1054         fprintf(output, "Entities in internal subset\n");
1055         xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
1056                     output);
1057     } else
1058         fprintf(output, "No entities in internal subset\n");
1059     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1060         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1061             doc->extSubset->entities;
1062
1063         fprintf(output, "Entities in external subset\n");
1064         xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
1065                     output);
1066     } else
1067         fprintf(output, "No entities in external subset\n");
1068 }
1069
1070 /**
1071  * xmlLsCountNode:
1072  * @node:  the node to count
1073  *
1074  * Count the children of @node.
1075  *
1076  * Returns the number of children of @node.
1077  */
1078 int
1079 xmlLsCountNode(xmlNodePtr node) {
1080     int ret = 0;
1081     xmlNodePtr list = NULL;
1082     
1083     if (node == NULL)
1084         return(0);
1085
1086     switch (node->type) {
1087         case XML_ELEMENT_NODE:
1088             list = node->children;
1089             break;
1090         case XML_DOCUMENT_NODE:
1091         case XML_HTML_DOCUMENT_NODE:
1092 #ifdef LIBXML_DOCB_ENABLED
1093         case XML_DOCB_DOCUMENT_NODE:
1094 #endif
1095             list = ((xmlDocPtr) node)->children;
1096             break;
1097         case XML_ATTRIBUTE_NODE:
1098             list = ((xmlAttrPtr) node)->children;
1099             break;
1100         case XML_TEXT_NODE:
1101         case XML_CDATA_SECTION_NODE:
1102         case XML_PI_NODE:
1103         case XML_COMMENT_NODE:
1104             if (node->content != NULL) {
1105                 ret = xmlStrlen(node->content);
1106             }
1107             break;
1108         case XML_ENTITY_REF_NODE:
1109         case XML_DOCUMENT_TYPE_NODE:
1110         case XML_ENTITY_NODE:
1111         case XML_DOCUMENT_FRAG_NODE:
1112         case XML_NOTATION_NODE:
1113         case XML_DTD_NODE:
1114         case XML_ELEMENT_DECL:
1115         case XML_ATTRIBUTE_DECL:
1116         case XML_ENTITY_DECL:
1117         case XML_NAMESPACE_DECL:
1118         case XML_XINCLUDE_START:
1119         case XML_XINCLUDE_END:
1120             ret = 1;
1121             break;
1122     }
1123     for (;list != NULL;ret++) 
1124         list = list->next;
1125     return(ret);
1126 }
1127
1128 /**
1129  * xmlLsOneNode:
1130  * @output:  the FILE * for the output
1131  * @node:  the node to dump
1132  *
1133  * Dump to @output the type and name of @node.
1134  */
1135 void
1136 xmlLsOneNode(FILE *output, xmlNodePtr node) {
1137     if (node == NULL) {
1138         fprintf(output, "NULL\n");
1139         return;
1140     }
1141     switch (node->type) {
1142         case XML_ELEMENT_NODE:
1143             fprintf(output, "-");
1144             break;
1145         case XML_ATTRIBUTE_NODE:
1146             fprintf(output, "a");
1147             break;
1148         case XML_TEXT_NODE:
1149             fprintf(output, "t");
1150             break;
1151         case XML_CDATA_SECTION_NODE:
1152             fprintf(output, "C");
1153             break;
1154         case XML_ENTITY_REF_NODE:
1155             fprintf(output, "e");
1156             break;
1157         case XML_ENTITY_NODE:
1158             fprintf(output, "E");
1159             break;
1160         case XML_PI_NODE:
1161             fprintf(output, "p");
1162             break;
1163         case XML_COMMENT_NODE:
1164             fprintf(output, "c");
1165             break;
1166         case XML_DOCUMENT_NODE:
1167             fprintf(output, "d");
1168             break;
1169         case XML_HTML_DOCUMENT_NODE:
1170             fprintf(output, "h");
1171             break;
1172         case XML_DOCUMENT_TYPE_NODE:
1173             fprintf(output, "T");
1174             break;
1175         case XML_DOCUMENT_FRAG_NODE:
1176             fprintf(output, "F");
1177             break;
1178         case XML_NOTATION_NODE:
1179             fprintf(output, "N");
1180             break;
1181         case XML_NAMESPACE_DECL:
1182             fprintf(output, "n");
1183             break;
1184         default:
1185             fprintf(output, "?");
1186     }
1187     if (node->type != XML_NAMESPACE_DECL) {
1188         if (node->properties != NULL)
1189             fprintf(output, "a");
1190         else    
1191             fprintf(output, "-");
1192         if (node->nsDef != NULL) 
1193             fprintf(output, "n");
1194         else    
1195             fprintf(output, "-");
1196     }
1197
1198     fprintf(output, " %8d ", xmlLsCountNode(node));
1199
1200     switch (node->type) {
1201         case XML_ELEMENT_NODE:
1202             if (node->name != NULL)
1203                 fprintf(output, "%s", node->name);
1204             break;
1205         case XML_ATTRIBUTE_NODE:
1206             if (node->name != NULL)
1207                 fprintf(output, "%s", node->name);
1208             break;
1209         case XML_TEXT_NODE:
1210             if (node->content != NULL) {
1211                 xmlDebugDumpString(output, node->content);
1212             }
1213             break;
1214         case XML_CDATA_SECTION_NODE:
1215             break;
1216         case XML_ENTITY_REF_NODE:
1217             if (node->name != NULL)
1218                 fprintf(output, "%s", node->name);
1219             break;
1220         case XML_ENTITY_NODE:
1221             if (node->name != NULL)
1222                 fprintf(output, "%s", node->name);
1223             break;
1224         case XML_PI_NODE:
1225             if (node->name != NULL)
1226                 fprintf(output, "%s", node->name);
1227             break;
1228         case XML_COMMENT_NODE:
1229             break;
1230         case XML_DOCUMENT_NODE:
1231             break;
1232         case XML_HTML_DOCUMENT_NODE:
1233             break;
1234         case XML_DOCUMENT_TYPE_NODE:
1235             break;
1236         case XML_DOCUMENT_FRAG_NODE:
1237             break;
1238         case XML_NOTATION_NODE:
1239             break;
1240         case XML_NAMESPACE_DECL: {
1241             xmlNsPtr ns = (xmlNsPtr) node;
1242
1243             if (ns->prefix == NULL)
1244                 fprintf(output, "default -> %s", ns->href);
1245             else
1246                 fprintf(output, "%s -> %s", ns->prefix, ns->href);
1247             break;
1248         }
1249         default:
1250             if (node->name != NULL)
1251                 fprintf(output, "%s", node->name);
1252     }
1253     fprintf(output, "\n");
1254 }
1255
1256 /**
1257  * xmlBoolToText:
1258  * @boolval: a bool to turn into text
1259  *
1260  * Convenient way to turn bool into text 
1261  *
1262  * Returns a pointer to either "True" or "False"
1263  */
1264 const char *
1265 xmlBoolToText(int boolval)
1266 {
1267     if (boolval)
1268         return("True");
1269     else
1270         return("False");
1271 }
1272
1273 /****************************************************************
1274  *                                                              *
1275  *              The XML shell related functions                 *
1276  *                                                              *
1277  ****************************************************************/
1278
1279
1280
1281 /*
1282  * TODO: Improvement/cleanups for the XML shell
1283  *     - allow to shell out an editor on a subpart
1284  *     - cleanup function registrations (with help) and calling
1285  *     - provide registration routines
1286  */
1287
1288 /**
1289  * xmlShellPrintXPathError:
1290  * @errorType: valid xpath error id
1291  * @arg: the argument that cause xpath to fail
1292  *
1293  * Print the xpath error to libxml default error channel
1294  */
1295 void
1296 xmlShellPrintXPathError(int errorType, const char *arg)
1297 {
1298     const char *default_arg = "Result";
1299
1300     if (!arg)
1301         arg = default_arg;
1302
1303     switch (errorType) {
1304         case XPATH_UNDEFINED:
1305             xmlGenericError(xmlGenericErrorContext,
1306                             "%s: no such node\n", arg);
1307             break;
1308
1309         case XPATH_BOOLEAN:
1310             xmlGenericError(xmlGenericErrorContext,
1311                             "%s is a Boolean\n", arg);
1312             break;
1313         case XPATH_NUMBER:
1314             xmlGenericError(xmlGenericErrorContext,
1315                             "%s is a number\n", arg);
1316             break;
1317         case XPATH_STRING:
1318             xmlGenericError(xmlGenericErrorContext,
1319                             "%s is a string\n", arg);
1320             break;
1321         case XPATH_POINT:
1322             xmlGenericError(xmlGenericErrorContext,
1323                             "%s is a point\n", arg);
1324             break;
1325         case XPATH_RANGE:
1326             xmlGenericError(xmlGenericErrorContext,
1327                             "%s is a range\n", arg);
1328             break;
1329         case XPATH_LOCATIONSET:
1330             xmlGenericError(xmlGenericErrorContext,
1331                             "%s is a range\n", arg);
1332             break;
1333         case XPATH_USERS:
1334             xmlGenericError(xmlGenericErrorContext,
1335                             "%s is user-defined\n", arg);
1336             break;
1337         case XPATH_XSLT_TREE:
1338             xmlGenericError(xmlGenericErrorContext,
1339                             "%s is an XSLT value tree\n", arg);
1340             break;
1341     }
1342     xmlGenericError(xmlGenericErrorContext,
1343                     "Try casting the result string function (xpath builtin)\n",
1344                     arg);
1345 }
1346
1347
1348 /**
1349  * xmlShellPrintNodeCtxt:
1350  * @ctxt : a non-null shell context
1351  * @node : a non-null node to print to the output FILE
1352  *
1353  * Print node to the output FILE
1354  */
1355 static void
1356 xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1357 {
1358     FILE *fp;
1359
1360     if (!node)
1361         return;
1362     if (ctxt == NULL)
1363         fp = stdout;
1364     else
1365         fp = ctxt->output;
1366
1367     if (node->type == XML_DOCUMENT_NODE)
1368         xmlDocDump(fp, (xmlDocPtr) node);
1369     else if (node->type == XML_ATTRIBUTE_NODE)
1370         xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
1371     else
1372         xmlElemDump(fp, node->doc, node);
1373
1374     fprintf(fp, "\n");
1375 }
1376
1377 /**
1378  * xmlShellPrintNode:
1379  * @node : a non-null node to print to the output FILE
1380  *
1381  * Print node to the output FILE
1382  */
1383 void
1384 xmlShellPrintNode(xmlNodePtr node)
1385 {
1386     xmlShellPrintNodeCtxt(NULL, node);
1387 }
1388
1389 /**
1390  * xmlShellPrintXPathResultCtxt:
1391  * @ctxt: a valid shell context
1392  * @list: a valid result generated by an xpath evaluation
1393  *
1394  * Prints result to the output FILE
1395  */
1396 static void
1397 xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
1398 {
1399     int i = 0;
1400     if (!ctxt)
1401        return;
1402
1403     if (list != NULL) {
1404         switch (list->type) {
1405             case XPATH_NODESET:{
1406                     int indx;
1407
1408                     if (list->nodesetval) {
1409                         for (indx = 0; indx < list->nodesetval->nodeNr;
1410                              indx++) {
1411                             if (i > 0)
1412                                 fprintf(stderr, " -------\n");
1413                             xmlShellPrintNodeCtxt(ctxt,
1414                                     list->nodesetval->nodeTab[indx]);
1415                         }
1416                     } else {
1417                         xmlGenericError(xmlGenericErrorContext,
1418                                         "Empty node set\n");
1419                     }
1420                     break;
1421                 }
1422             case XPATH_BOOLEAN:
1423                 xmlGenericError(xmlGenericErrorContext,
1424                                 "Is a Boolean:%s\n",
1425                                 xmlBoolToText(list->boolval));
1426                 break;
1427             case XPATH_NUMBER:
1428                 xmlGenericError(xmlGenericErrorContext,
1429                                 "Is a number:%0g\n", list->floatval);
1430                 break;
1431             case XPATH_STRING:
1432                 xmlGenericError(xmlGenericErrorContext,
1433                                 "Is a string:%s\n", list->stringval);
1434                 break;
1435
1436             default:
1437                 xmlShellPrintXPathError(list->type, NULL);
1438         }
1439     }
1440 }
1441
1442 /**
1443  * xmlShellPrintXPathResult:
1444  * @list: a valid result generated by an xpath evaluation
1445  *
1446  * Prints result to the output FILE
1447  */
1448 void
1449 xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1450 {
1451     xmlShellPrintXPathResultCtxt(NULL, list);
1452 }
1453
1454 /**
1455  * xmlShellList:
1456  * @ctxt:  the shell context
1457  * @arg:  unused
1458  * @node:  a node
1459  * @node2:  unused
1460  *
1461  * Implements the XML shell function "ls"
1462  * Does an Unix like listing of the given node (like a directory)
1463  *
1464  * Returns 0
1465  */
1466 int
1467 xmlShellList(xmlShellCtxtPtr ctxt,
1468              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1469              xmlNodePtr node2 ATTRIBUTE_UNUSED)
1470 {
1471     xmlNodePtr cur;
1472     if (!ctxt)
1473         return (0);
1474     if (node == NULL) {
1475         fprintf(ctxt->output, "NULL\n");
1476         return (0);
1477     }
1478     if ((node->type == XML_DOCUMENT_NODE) ||
1479         (node->type == XML_HTML_DOCUMENT_NODE)) {
1480         cur = ((xmlDocPtr) node)->children;
1481     } else if (node->type == XML_NAMESPACE_DECL) {
1482         xmlLsOneNode(ctxt->output, node);
1483         return (0);
1484     } else if (node->children != NULL) {
1485         cur = node->children;
1486     } else {
1487         xmlLsOneNode(ctxt->output, node);
1488         return (0);
1489     }
1490     while (cur != NULL) {
1491         xmlLsOneNode(ctxt->output, cur);
1492         cur = cur->next;
1493     }
1494     return (0);
1495 }
1496
1497 /**
1498  * xmlShellBase:
1499  * @ctxt:  the shell context
1500  * @arg:  unused
1501  * @node:  a node
1502  * @node2:  unused
1503  *
1504  * Implements the XML shell function "base"
1505  * dumps the current XML base of the node
1506  *
1507  * Returns 0
1508  */
1509 int
1510 xmlShellBase(xmlShellCtxtPtr ctxt,
1511              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1512              xmlNodePtr node2 ATTRIBUTE_UNUSED)
1513 {
1514     xmlChar *base;
1515     if (!ctxt)
1516         return 0;
1517     if (node == NULL) {
1518         fprintf(ctxt->output, "NULL\n");
1519         return (0);
1520     }    
1521
1522     base = xmlNodeGetBase(node->doc, node);
1523
1524     if (base == NULL) {
1525         fprintf(ctxt->output, " No base found !!!\n");
1526     } else {
1527         fprintf(ctxt->output, "%s\n", base);
1528         xmlFree(base);
1529     }
1530     return (0);
1531 }
1532
1533 /**
1534  * xmlShellSetBase:
1535  * @ctxt:  the shell context
1536  * @arg:  the new base
1537  * @node:  a node
1538  * @node2:  unused
1539  *
1540  * Implements the XML shell function "setbase"
1541  * change the current XML base of the node
1542  *
1543  * Returns 0
1544  */
1545 static int
1546 xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1547              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1548              xmlNodePtr node2 ATTRIBUTE_UNUSED)
1549 {
1550     xmlNodeSetBase(node, (xmlChar*) arg);
1551     return (0);
1552 }
1553
1554 /**
1555  * xmlShellGrep:
1556  * @ctxt:  the shell context
1557  * @arg:  the string or regular expression to find
1558  * @node:  a node
1559  * @node2:  unused
1560  *
1561  * Implements the XML shell function "grep"
1562  * dumps informations about the node (namespace, attributes, content).
1563  *
1564  * Returns 0
1565  */
1566 static int
1567 xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1568             char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1569 {
1570     if (!ctxt)
1571         return (0);
1572     if (node == NULL)
1573         return (0);
1574     if (arg == NULL)
1575         return (0);
1576 #ifdef LIBXML_REGEXP_ENABLED
1577     if ((xmlStrchr((xmlChar *) arg, '?')) ||
1578         (xmlStrchr((xmlChar *) arg, '*')) ||
1579         (xmlStrchr((xmlChar *) arg, '.')) ||
1580         (xmlStrchr((xmlChar *) arg, '['))) {
1581     }
1582 #endif
1583     while (node != NULL) {
1584         if (node->type == XML_COMMENT_NODE) {
1585             if (xmlStrstr(node->content, (xmlChar *) arg)) {
1586
1587                 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
1588                 xmlShellList(ctxt, NULL, node, NULL);
1589             }
1590         } else if (node->type == XML_TEXT_NODE) {
1591             if (xmlStrstr(node->content, (xmlChar *) arg)) {
1592
1593                 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
1594                 xmlShellList(ctxt, NULL, node->parent, NULL);
1595             }
1596         }
1597
1598         /*
1599          * Browse the full subtree, deep first
1600          */
1601
1602         if ((node->type == XML_DOCUMENT_NODE) ||
1603             (node->type == XML_HTML_DOCUMENT_NODE)) {
1604             node = ((xmlDocPtr) node)->children;
1605         } else if ((node->children != NULL)
1606                    && (node->type != XML_ENTITY_REF_NODE)) {
1607             /* deep first */
1608             node = node->children;
1609         } else if (node->next != NULL) {
1610             /* then siblings */
1611             node = node->next;
1612         } else {
1613             /* go up to parents->next if needed */
1614             while (node != NULL) {
1615                 if (node->parent != NULL) {
1616                     node = node->parent;
1617                 }
1618                 if (node->next != NULL) {
1619                     node = node->next;
1620                     break;
1621                 }
1622                 if (node->parent == NULL) {
1623                     node = NULL;
1624                     break;
1625                 }
1626             }
1627         }
1628     }
1629     return (0);
1630 }
1631
1632 /**
1633  * xmlShellDir:
1634  * @ctxt:  the shell context
1635  * @arg:  unused
1636  * @node:  a node
1637  * @node2:  unused
1638  *
1639  * Implements the XML shell function "dir"
1640  * dumps informations about the node (namespace, attributes, content).
1641  *
1642  * Returns 0
1643  */
1644 int
1645 xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1646             char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1647             xmlNodePtr node2 ATTRIBUTE_UNUSED)
1648 {
1649     if (!ctxt)
1650         return (0);
1651     if (node == NULL) {
1652         fprintf(ctxt->output, "NULL\n");
1653         return (0);
1654     }    
1655     if ((node->type == XML_DOCUMENT_NODE) ||
1656         (node->type == XML_HTML_DOCUMENT_NODE)) {
1657         xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
1658     } else if (node->type == XML_ATTRIBUTE_NODE) {
1659         xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
1660     } else {
1661         xmlDebugDumpOneNode(ctxt->output, node, 0);
1662     }
1663     return (0);
1664 }
1665
1666 /**
1667  * xmlShellCat:
1668  * @ctxt:  the shell context
1669  * @arg:  unused
1670  * @node:  a node
1671  * @node2:  unused
1672  *
1673  * Implements the XML shell function "cat"
1674  * dumps the serialization node content (XML or HTML).
1675  *
1676  * Returns 0
1677  */
1678 int
1679 xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
1680             xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1681 {
1682     if (!ctxt)
1683         return (0);
1684     if (node == NULL) {
1685         fprintf(ctxt->output, "NULL\n");
1686         return (0);
1687     }    
1688     if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1689 #ifdef LIBXML_HTML_ENABLED
1690         if (node->type == XML_HTML_DOCUMENT_NODE)
1691             htmlDocDump(ctxt->output, (htmlDocPtr) node);
1692         else
1693             htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
1694 #else
1695         if (node->type == XML_DOCUMENT_NODE)
1696             xmlDocDump(ctxt->output, (xmlDocPtr) node);
1697         else
1698             xmlElemDump(ctxt->output, ctxt->doc, node);
1699 #endif /* LIBXML_HTML_ENABLED */
1700     } else {
1701         if (node->type == XML_DOCUMENT_NODE)
1702             xmlDocDump(ctxt->output, (xmlDocPtr) node);
1703         else
1704             xmlElemDump(ctxt->output, ctxt->doc, node);
1705     }
1706     fprintf(ctxt->output, "\n");
1707     return (0);
1708 }
1709
1710 /**
1711  * xmlShellLoad:
1712  * @ctxt:  the shell context
1713  * @filename:  the file name
1714  * @node:  unused
1715  * @node2:  unused
1716  *
1717  * Implements the XML shell function "load"
1718  * loads a new document specified by the filename
1719  *
1720  * Returns 0 or -1 if loading failed
1721  */
1722 int
1723 xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
1724              xmlNodePtr node ATTRIBUTE_UNUSED,
1725              xmlNodePtr node2 ATTRIBUTE_UNUSED)
1726 {
1727     xmlDocPtr doc;
1728     int html = 0;
1729
1730     if (ctxt->doc != NULL)
1731         html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
1732
1733     if (html) {
1734 #ifdef LIBXML_HTML_ENABLED
1735         doc = htmlParseFile(filename, NULL);
1736 #else
1737         fprintf(ctxt->output, "HTML support not compiled in\n");
1738         doc = NULL;
1739 #endif /* LIBXML_HTML_ENABLED */
1740     } else {
1741         doc = xmlParseFile(filename);
1742     }
1743     if (doc != NULL) {
1744         if (ctxt->loaded == 1) {
1745             xmlFreeDoc(ctxt->doc);
1746         }
1747         ctxt->loaded = 1;
1748 #ifdef LIBXML_XPATH_ENABLED
1749         xmlXPathFreeContext(ctxt->pctxt);
1750 #endif /* LIBXML_XPATH_ENABLED */
1751         xmlFree(ctxt->filename);
1752         ctxt->doc = doc;
1753         ctxt->node = (xmlNodePtr) doc;
1754 #ifdef LIBXML_XPATH_ENABLED
1755         ctxt->pctxt = xmlXPathNewContext(doc);
1756 #endif /* LIBXML_XPATH_ENABLED */
1757         ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1758     } else
1759         return (-1);
1760     return (0);
1761 }
1762
1763 /**
1764  * xmlShellWrite:
1765  * @ctxt:  the shell context
1766  * @filename:  the file name
1767  * @node:  a node in the tree
1768  * @node2:  unused
1769  *
1770  * Implements the XML shell function "write"
1771  * Write the current node to the filename, it saves the serialization
1772  * of the subtree under the @node specified
1773  *
1774  * Returns 0 or -1 in case of error
1775  */
1776 int
1777 xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1778               xmlNodePtr node2 ATTRIBUTE_UNUSED)
1779 {
1780     if (node == NULL)
1781         return (-1);
1782     if ((filename == NULL) || (filename[0] == 0)) {
1783         xmlGenericError(xmlGenericErrorContext,
1784                         "Write command requires a filename argument\n");
1785         return (-1);
1786     }
1787 #ifdef W_OK
1788     if (access((char *) filename, W_OK)) {
1789         xmlGenericError(xmlGenericErrorContext,
1790                         "Cannot write to %s\n", filename);
1791         return (-1);
1792     }
1793 #endif
1794     switch (node->type) {
1795         case XML_DOCUMENT_NODE:
1796             if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1797                 xmlGenericError(xmlGenericErrorContext,
1798                                 "Failed to write to %s\n", filename);
1799                 return (-1);
1800             }
1801             break;
1802         case XML_HTML_DOCUMENT_NODE:
1803 #ifdef LIBXML_HTML_ENABLED
1804             if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1805                 xmlGenericError(xmlGenericErrorContext,
1806                                 "Failed to write to %s\n", filename);
1807                 return (-1);
1808             }
1809 #else
1810             if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1811                 xmlGenericError(xmlGenericErrorContext,
1812                                 "Failed to write to %s\n", filename);
1813                 return (-1);
1814             }
1815 #endif /* LIBXML_HTML_ENABLED */
1816             break;
1817         default:{
1818                 FILE *f;
1819
1820                 f = fopen((char *) filename, "w");
1821                 if (f == NULL) {
1822                     xmlGenericError(xmlGenericErrorContext,
1823                                     "Failed to write to %s\n", filename);
1824                     return (-1);
1825                 }
1826                 xmlElemDump(f, ctxt->doc, node);
1827                 fclose(f);
1828             }
1829     }
1830     return (0);
1831 }
1832
1833 /**
1834  * xmlShellSave:
1835  * @ctxt:  the shell context
1836  * @filename:  the file name (optional)
1837  * @node:  unused
1838  * @node2:  unused
1839  *
1840  * Implements the XML shell function "save"
1841  * Write the current document to the filename, or it's original name
1842  *
1843  * Returns 0 or -1 in case of error
1844  */
1845 int
1846 xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
1847              xmlNodePtr node ATTRIBUTE_UNUSED,
1848              xmlNodePtr node2 ATTRIBUTE_UNUSED)
1849 {
1850     if (ctxt->doc == NULL)
1851         return (-1);
1852     if ((filename == NULL) || (filename[0] == 0))
1853         filename = ctxt->filename;
1854 #ifdef W_OK
1855     if (access((char *) filename, W_OK)) {
1856         xmlGenericError(xmlGenericErrorContext,
1857                         "Cannot save to %s\n", filename);
1858         return (-1);
1859     }
1860 #endif
1861     switch (ctxt->doc->type) {
1862         case XML_DOCUMENT_NODE:
1863             if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1864                 xmlGenericError(xmlGenericErrorContext,
1865                                 "Failed to save to %s\n", filename);
1866             }
1867             break;
1868         case XML_HTML_DOCUMENT_NODE:
1869 #ifdef LIBXML_HTML_ENABLED
1870             if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1871                 xmlGenericError(xmlGenericErrorContext,
1872                                 "Failed to save to %s\n", filename);
1873             }
1874 #else
1875             if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1876                 xmlGenericError(xmlGenericErrorContext,
1877                                 "Failed to save to %s\n", filename);
1878             }
1879 #endif /* LIBXML_HTML_ENABLED */
1880             break;
1881         default:
1882             xmlGenericError(xmlGenericErrorContext,
1883             "To save to subparts of a document use the 'write' command\n");
1884             return (-1);
1885
1886     }
1887     return (0);
1888 }
1889
1890 /**
1891  * xmlShellValidate:
1892  * @ctxt:  the shell context
1893  * @dtd:  the DTD URI (optional)
1894  * @node:  unused
1895  * @node2:  unused
1896  *
1897  * Implements the XML shell function "validate"
1898  * Validate the document, if a DTD path is provided, then the validation
1899  * is done against the given DTD.
1900  *
1901  * Returns 0 or -1 in case of error
1902  */
1903 int
1904 xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
1905                  xmlNodePtr node ATTRIBUTE_UNUSED,
1906                  xmlNodePtr node2 ATTRIBUTE_UNUSED)
1907 {
1908     xmlValidCtxt vctxt;
1909     int res = -1;
1910
1911     vctxt.userData = stderr;
1912     vctxt.error = (xmlValidityErrorFunc) fprintf;
1913     vctxt.warning = (xmlValidityWarningFunc) fprintf;
1914
1915     if ((dtd == NULL) || (dtd[0] == 0)) {
1916         res = xmlValidateDocument(&vctxt, ctxt->doc);
1917     } else {
1918         xmlDtdPtr subset;
1919
1920         subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1921         if (subset != NULL) {
1922             res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1923
1924             xmlFreeDtd(subset);
1925         }
1926     }
1927     return (res);
1928 }
1929
1930 /**
1931  * xmlShellDu:
1932  * @ctxt:  the shell context
1933  * @arg:  unused
1934  * @tree:  a node defining a subtree
1935  * @node2:  unused
1936  *
1937  * Implements the XML shell function "du"
1938  * show the structure of the subtree under node @tree
1939  * If @tree is null, the command works on the current node.
1940  *
1941  * Returns 0 or -1 in case of error
1942  */
1943 int
1944 xmlShellDu(xmlShellCtxtPtr ctxt,
1945            char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
1946            xmlNodePtr node2 ATTRIBUTE_UNUSED)
1947 {
1948     xmlNodePtr node;
1949     int indent = 0, i;
1950
1951     if (!ctxt)
1952         return (-1);
1953
1954     if (tree == NULL)
1955         return (-1);
1956     node = tree;
1957     while (node != NULL) {
1958         if ((node->type == XML_DOCUMENT_NODE) ||
1959             (node->type == XML_HTML_DOCUMENT_NODE)) {
1960             fprintf(ctxt->output, "/\n");
1961         } else if (node->type == XML_ELEMENT_NODE) {
1962             for (i = 0; i < indent; i++)
1963                 fprintf(ctxt->output, "  ");
1964             fprintf(ctxt->output, "%s\n", node->name);
1965         } else {
1966         }
1967
1968         /*
1969          * Browse the full subtree, deep first
1970          */
1971
1972         if ((node->type == XML_DOCUMENT_NODE) ||
1973             (node->type == XML_HTML_DOCUMENT_NODE)) {
1974             node = ((xmlDocPtr) node)->children;
1975         } else if ((node->children != NULL)
1976                    && (node->type != XML_ENTITY_REF_NODE)) {
1977             /* deep first */
1978             node = node->children;
1979             indent++;
1980         } else if ((node != tree) && (node->next != NULL)) {
1981             /* then siblings */
1982             node = node->next;
1983         } else if (node != tree) {
1984             /* go up to parents->next if needed */
1985             while (node != tree) {
1986                 if (node->parent != NULL) {
1987                     node = node->parent;
1988                     indent--;
1989                 }
1990                 if ((node != tree) && (node->next != NULL)) {
1991                     node = node->next;
1992                     break;
1993                 }
1994                 if (node->parent == NULL) {
1995                     node = NULL;
1996                     break;
1997                 }
1998                 if (node == tree) {
1999                     node = NULL;
2000                     break;
2001                 }
2002             }
2003             /* exit condition */
2004             if (node == tree)
2005                 node = NULL;
2006         } else
2007             node = NULL;
2008     }
2009     return (0);
2010 }
2011
2012 /**
2013  * xmlShellPwd:
2014  * @ctxt:  the shell context
2015  * @buffer:  the output buffer
2016  * @node:  a node 
2017  * @node2:  unused
2018  *
2019  * Implements the XML shell function "pwd"
2020  * Show the full path from the root to the node, if needed building
2021  * thumblers when similar elements exists at a given ancestor level.
2022  * The output is compatible with XPath commands.
2023  *
2024  * Returns 0 or -1 in case of error
2025  */
2026 int
2027 xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2028             xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2029 {
2030     xmlChar *path;
2031
2032     if (node == NULL)
2033         return (-1);
2034
2035     path = xmlGetNodePath(node);
2036     if (path == NULL)
2037         return (-1);
2038
2039     /*
2040      * This test prevents buffer overflow, because this routine
2041      * is only called by xmlShell, in which the second argument is
2042      * 500 chars long.
2043      * It is a dirty hack before a cleaner solution is found.
2044      * Documentation should mention that the second argument must
2045      * be at least 500 chars long, and could be stripped if too long.
2046      */
2047     snprintf(buffer, 499, "%s", path);
2048     buffer[499] = '0';
2049     xmlFree(path);
2050
2051     return (0);
2052 }
2053
2054 /**
2055  * xmlShell:
2056  * @doc:  the initial document
2057  * @filename:  the output buffer
2058  * @input:  the line reading function
2059  * @output:  the output FILE*, defaults to stdout if NULL
2060  *
2061  * Implements the XML shell 
2062  * This allow to load, validate, view, modify and save a document
2063  * using a environment similar to a UNIX commandline.
2064  */
2065 void
2066 xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
2067          FILE * output)
2068 {
2069     char prompt[500] = "/ > ";
2070     char *cmdline = NULL, *cur;
2071     int nbargs;
2072     char command[100];
2073     char arg[400];
2074     int i;
2075     xmlShellCtxtPtr ctxt;
2076     xmlXPathObjectPtr list;
2077
2078     if (doc == NULL)
2079         return;
2080     if (filename == NULL)
2081         return;
2082     if (input == NULL)
2083         return;
2084     if (output == NULL)
2085         output = stdout;
2086     ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
2087     if (ctxt == NULL)
2088         return;
2089     ctxt->loaded = 0;
2090     ctxt->doc = doc;
2091     ctxt->input = input;
2092     ctxt->output = output;
2093     ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
2094     ctxt->node = (xmlNodePtr) ctxt->doc;
2095
2096 #ifdef LIBXML_XPATH_ENABLED
2097     ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2098     if (ctxt->pctxt == NULL) {
2099         xmlFree(ctxt);
2100         return;
2101     }
2102 #endif /* LIBXML_XPATH_ENABLED */
2103     while (1) {
2104         if (ctxt->node == (xmlNodePtr) ctxt->doc)
2105             snprintf(prompt, sizeof(prompt), "%s > ", "/");
2106         else if (ctxt->node->name)
2107             snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
2108         else
2109             snprintf(prompt, sizeof(prompt), "? > ");
2110         prompt[sizeof(prompt) - 1] = 0;
2111
2112         /*
2113          * Get a new command line
2114          */
2115         cmdline = ctxt->input(prompt);
2116         if (cmdline == NULL)
2117             break;
2118
2119         /*
2120          * Parse the command itself
2121          */
2122         cur = cmdline;
2123         nbargs = 0;
2124         while ((*cur == ' ') || (*cur == '\t'))
2125             cur++;
2126         i = 0;
2127         while ((*cur != ' ') && (*cur != '\t') &&
2128                (*cur != '\n') && (*cur != '\r')) {
2129             if (*cur == 0)
2130                 break;
2131             command[i++] = *cur++;
2132         }
2133         command[i] = 0;
2134         if (i == 0)
2135             continue;
2136         nbargs++;
2137
2138         /*
2139          * Parse the argument
2140          */
2141         while ((*cur == ' ') || (*cur == '\t'))
2142             cur++;
2143         i = 0;
2144         while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2145             if (*cur == 0)
2146                 break;
2147             arg[i++] = *cur++;
2148         }
2149         arg[i] = 0;
2150         if (i != 0)
2151             nbargs++;
2152
2153         /*
2154          * start interpreting the command
2155          */
2156         if (!strcmp(command, "exit"))
2157             break;
2158         if (!strcmp(command, "quit"))
2159             break;
2160         if (!strcmp(command, "bye"))
2161             break;
2162                 if (!strcmp(command, "help")) {
2163                   fprintf(ctxt->output, "\tbase         display XML base of the node\n");
2164                   fprintf(ctxt->output, "\tsetbase URI  change the XML base of the node\n");
2165                   fprintf(ctxt->output, "\tbye          leave shell\n");
2166                   fprintf(ctxt->output, "\tcat [node]   display node or current node\n");
2167                   fprintf(ctxt->output, "\tcd [path]    change directory to path or to root\n");
2168                   fprintf(ctxt->output, "\tdir [path]   dumps informations about the node (namespace, attributes, content)\n");
2169                   fprintf(ctxt->output, "\tdu [path]    show the structure of the subtree under path or the current node\n");
2170                   fprintf(ctxt->output, "\texit         leave shell\n");
2171                   fprintf(ctxt->output, "\thelp         display this help\n");
2172                   fprintf(ctxt->output, "\tfree         display memory usage\n");
2173                   fprintf(ctxt->output, "\tload [name]  load a new document with name\n");
2174                   fprintf(ctxt->output, "\tls [path]    list contents of path or the current directory\n");
2175 #ifdef LIBXML_XPATH_ENABLED
2176                   fprintf(ctxt->output, "\txpath expr   evaluate the XPath expression in that context and print the result\n");
2177 #endif /* LIBXML_XPATH_ENABLED */
2178                   fprintf(ctxt->output, "\tpwd          display current working directory\n");
2179                   fprintf(ctxt->output, "\tquit         leave shell\n");
2180                   fprintf(ctxt->output, "\tsave [name]  save this document to name or the original name\n");
2181                   fprintf(ctxt->output, "\tvalidate     check the document for errors\n");
2182                   fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
2183                   fprintf(ctxt->output, "\tgrep string  search for a string in the subtree\n");
2184         } else if (!strcmp(command, "validate")) {
2185             xmlShellValidate(ctxt, arg, NULL, NULL);
2186         } else if (!strcmp(command, "load")) {
2187             xmlShellLoad(ctxt, arg, NULL, NULL);
2188         } else if (!strcmp(command, "save")) {
2189             xmlShellSave(ctxt, arg, NULL, NULL);
2190         } else if (!strcmp(command, "write")) {
2191             xmlShellWrite(ctxt, arg, NULL, NULL);
2192         } else if (!strcmp(command, "grep")) {
2193             xmlShellGrep(ctxt, arg, ctxt->node, NULL);
2194         } else if (!strcmp(command, "free")) {
2195             if (arg[0] == 0) {
2196                 xmlMemShow(ctxt->output, 0);
2197             } else {
2198                 int len = 0;
2199
2200                 sscanf(arg, "%d", &len);
2201                 xmlMemShow(ctxt->output, len);
2202             }
2203         } else if (!strcmp(command, "pwd")) {
2204             char dir[500];
2205
2206             if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
2207                 fprintf(ctxt->output, "%s\n", dir);
2208         } else if (!strcmp(command, "du")) {
2209             xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2210         } else if (!strcmp(command, "base")) {
2211             xmlShellBase(ctxt, NULL, ctxt->node, NULL);
2212 #ifdef LIBXML_XPATH_ENABLED
2213         } else if (!strcmp(command, "xpath")) {
2214             if (arg[0] == 0) {
2215                 xmlGenericError(xmlGenericErrorContext,
2216                                 "xpath: expression required\n");
2217             } else {
2218                 ctxt->pctxt->node = ctxt->node;
2219                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2220                 xmlXPathDebugDumpObject(ctxt->output, list, 0);
2221                 xmlXPathFreeObject(list);
2222             }
2223 #endif /* LIBXML_XPATH_ENABLED */
2224         } else if (!strcmp(command, "setbase")) {
2225             xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
2226         } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2227             int dir = (!strcmp(command, "dir"));
2228
2229             if (arg[0] == 0) {
2230                 if (dir)
2231                     xmlShellDir(ctxt, NULL, ctxt->node, NULL);
2232                 else
2233                     xmlShellList(ctxt, NULL, ctxt->node, NULL);
2234             } else {
2235                 ctxt->pctxt->node = ctxt->node;
2236 #ifdef LIBXML_XPATH_ENABLED
2237                 ctxt->pctxt->node = ctxt->node;
2238                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2239 #else
2240                 list = NULL;
2241 #endif /* LIBXML_XPATH_ENABLED */
2242                 if (list != NULL) {
2243                     switch (list->type) {
2244                         case XPATH_UNDEFINED:
2245                             xmlGenericError(xmlGenericErrorContext,
2246                                             "%s: no such node\n", arg);
2247                             break;
2248                         case XPATH_NODESET:{
2249                                 int indx;
2250
2251                                 if (list->nodesetval == NULL)
2252                                     break;
2253
2254                                 for (indx = 0;
2255                                      indx < list->nodesetval->nodeNr;
2256                                      indx++) {
2257                                     if (dir)
2258                                         xmlShellDir(ctxt, NULL,
2259                                                     list->nodesetval->
2260                                                     nodeTab[indx], NULL);
2261                                     else
2262                                         xmlShellList(ctxt, NULL,
2263                                                      list->nodesetval->
2264                                                      nodeTab[indx], NULL);
2265                                 }
2266                                 break;
2267                             }
2268                         case XPATH_BOOLEAN:
2269                             xmlGenericError(xmlGenericErrorContext,
2270                                             "%s is a Boolean\n", arg);
2271                             break;
2272                         case XPATH_NUMBER:
2273                             xmlGenericError(xmlGenericErrorContext,
2274                                             "%s is a number\n", arg);
2275                             break;
2276                         case XPATH_STRING:
2277                             xmlGenericError(xmlGenericErrorContext,
2278                                             "%s is a string\n", arg);
2279                             break;
2280                         case XPATH_POINT:
2281                             xmlGenericError(xmlGenericErrorContext,
2282                                             "%s is a point\n", arg);
2283                             break;
2284                         case XPATH_RANGE:
2285                             xmlGenericError(xmlGenericErrorContext,
2286                                             "%s is a range\n", arg);
2287                             break;
2288                         case XPATH_LOCATIONSET:
2289                             xmlGenericError(xmlGenericErrorContext,
2290                                             "%s is a range\n", arg);
2291                             break;
2292                         case XPATH_USERS:
2293                             xmlGenericError(xmlGenericErrorContext,
2294                                             "%s is user-defined\n", arg);
2295                             break;
2296                         case XPATH_XSLT_TREE:
2297                             xmlGenericError(xmlGenericErrorContext,
2298                                             "%s is an XSLT value tree\n",
2299                                             arg);
2300                             break;
2301                     }
2302 #ifdef LIBXML_XPATH_ENABLED
2303                     xmlXPathFreeObject(list);
2304 #endif
2305                 } else {
2306                     xmlGenericError(xmlGenericErrorContext,
2307                                     "%s: no such node\n", arg);
2308                 }
2309                 ctxt->pctxt->node = NULL;
2310             }
2311         } else if (!strcmp(command, "cd")) {
2312             if (arg[0] == 0) {
2313                 ctxt->node = (xmlNodePtr) ctxt->doc;
2314             } else {
2315 #ifdef LIBXML_XPATH_ENABLED
2316                 ctxt->pctxt->node = ctxt->node;
2317                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2318 #else
2319                 list = NULL;
2320 #endif /* LIBXML_XPATH_ENABLED */
2321                 if (list != NULL) {
2322                     switch (list->type) {
2323                         case XPATH_UNDEFINED:
2324                             xmlGenericError(xmlGenericErrorContext,
2325                                             "%s: no such node\n", arg);
2326                             break;
2327                         case XPATH_NODESET:
2328                             if (list->nodesetval != NULL) {
2329                                 if (list->nodesetval->nodeNr == 1) {
2330                                     ctxt->node = list->nodesetval->nodeTab[0];
2331                                 } else
2332                                     xmlGenericError(xmlGenericErrorContext,
2333                                                     "%s is a %d Node Set\n",
2334                                                     arg,
2335                                                     list->nodesetval->nodeNr);
2336                             } else
2337                                 xmlGenericError(xmlGenericErrorContext,
2338                                                 "%s is an empty Node Set\n",
2339                                                 arg);
2340                             break;
2341                         case XPATH_BOOLEAN:
2342                             xmlGenericError(xmlGenericErrorContext,
2343                                             "%s is a Boolean\n", arg);
2344                             break;
2345                         case XPATH_NUMBER:
2346                             xmlGenericError(xmlGenericErrorContext,
2347                                             "%s is a number\n", arg);
2348                             break;
2349                         case XPATH_STRING:
2350                             xmlGenericError(xmlGenericErrorContext,
2351                                             "%s is a string\n", arg);
2352                             break;
2353                         case XPATH_POINT:
2354                             xmlGenericError(xmlGenericErrorContext,
2355                                             "%s is a point\n", arg);
2356                             break;
2357                         case XPATH_RANGE:
2358                             xmlGenericError(xmlGenericErrorContext,
2359                                             "%s is a range\n", arg);
2360                             break;
2361                         case XPATH_LOCATIONSET:
2362                             xmlGenericError(xmlGenericErrorContext,
2363                                             "%s is a range\n", arg);
2364                             break;
2365                         case XPATH_USERS:
2366                             xmlGenericError(xmlGenericErrorContext,
2367                                             "%s is user-defined\n", arg);
2368                             break;
2369                         case XPATH_XSLT_TREE:
2370                             xmlGenericError(xmlGenericErrorContext,
2371                                             "%s is an XSLT value tree\n",
2372                                             arg);
2373                             break;
2374                     }
2375 #ifdef LIBXML_XPATH_ENABLED
2376                     xmlXPathFreeObject(list);
2377 #endif
2378                 } else {
2379                     xmlGenericError(xmlGenericErrorContext,
2380                                     "%s: no such node\n", arg);
2381                 }
2382                 ctxt->pctxt->node = NULL;
2383             }
2384         } else if (!strcmp(command, "cat")) {
2385             if (arg[0] == 0) {
2386                 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
2387             } else {
2388                 ctxt->pctxt->node = ctxt->node;
2389 #ifdef LIBXML_XPATH_ENABLED
2390                 ctxt->pctxt->node = ctxt->node;
2391                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2392 #else
2393                 list = NULL;
2394 #endif /* LIBXML_XPATH_ENABLED */
2395                 if (list != NULL) {
2396                     switch (list->type) {
2397                         case XPATH_UNDEFINED:
2398                             xmlGenericError(xmlGenericErrorContext,
2399                                             "%s: no such node\n", arg);
2400                             break;
2401                         case XPATH_NODESET:{
2402                                 int indx;
2403
2404                                 if (list->nodesetval == NULL)
2405                                     break;
2406
2407                                 for (indx = 0;
2408                                      indx < list->nodesetval->nodeNr;
2409                                      indx++) {
2410                                     if (i > 0)
2411                                         fprintf(ctxt->output, " -------\n");
2412                                     xmlShellCat(ctxt, NULL,
2413                                                 list->nodesetval->
2414                                                 nodeTab[indx], NULL);
2415                                 }
2416                                 break;
2417                             }
2418                         case XPATH_BOOLEAN:
2419                             xmlGenericError(xmlGenericErrorContext,
2420                                             "%s is a Boolean\n", arg);
2421                             break;
2422                         case XPATH_NUMBER:
2423                             xmlGenericError(xmlGenericErrorContext,
2424                                             "%s is a number\n", arg);
2425                             break;
2426                         case XPATH_STRING:
2427                             xmlGenericError(xmlGenericErrorContext,
2428                                             "%s is a string\n", arg);
2429                             break;
2430                         case XPATH_POINT:
2431                             xmlGenericError(xmlGenericErrorContext,
2432                                             "%s is a point\n", arg);
2433                             break;
2434                         case XPATH_RANGE:
2435                             xmlGenericError(xmlGenericErrorContext,
2436                                             "%s is a range\n", arg);
2437                             break;
2438                         case XPATH_LOCATIONSET:
2439                             xmlGenericError(xmlGenericErrorContext,
2440                                             "%s is a range\n", arg);
2441                             break;
2442                         case XPATH_USERS:
2443                             xmlGenericError(xmlGenericErrorContext,
2444                                             "%s is user-defined\n", arg);
2445                             break;
2446                         case XPATH_XSLT_TREE:
2447                             xmlGenericError(xmlGenericErrorContext,
2448                                             "%s is an XSLT value tree\n",
2449                                             arg);
2450                             break;
2451                     }
2452 #ifdef LIBXML_XPATH_ENABLED
2453                     xmlXPathFreeObject(list);
2454 #endif
2455                 } else {
2456                     xmlGenericError(xmlGenericErrorContext,
2457                                     "%s: no such node\n", arg);
2458                 }
2459                 ctxt->pctxt->node = NULL;
2460             }
2461         } else {
2462             xmlGenericError(xmlGenericErrorContext,
2463                             "Unknown command %s\n", command);
2464         }
2465         free(cmdline);          /* not xmlFree here ! */
2466     }
2467 #ifdef LIBXML_XPATH_ENABLED
2468     xmlXPathFreeContext(ctxt->pctxt);
2469 #endif /* LIBXML_XPATH_ENABLED */
2470     if (ctxt->loaded) {
2471         xmlFreeDoc(ctxt->doc);
2472     }
2473     if (ctxt->filename != NULL)
2474         xmlFree(ctxt->filename);
2475     xmlFree(ctxt);
2476     if (cmdline != NULL)
2477         free(cmdline);          /* not xmlFree here ! */
2478 }
2479
2480 #endif /* LIBXML_DEBUG_ENABLED */