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