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 #ifdef LIBXML_SCHEMAS_ENABLED
34 #include <libxml/relaxng.h>
35 #endif
36 
37 #define DUMP_TEXT_TYPE 1
38 
39 typedef struct _xmlDebugCtxt xmlDebugCtxt;
40 typedef xmlDebugCtxt *xmlDebugCtxtPtr;
41 struct _xmlDebugCtxt {
42     FILE *output;               /* the output file */
43     char shift[101];            /* used for indenting */
44     int depth;                  /* current depth */
45     xmlDocPtr doc;              /* current document */
46     xmlNodePtr node;		/* current node */
47     xmlDictPtr dict;		/* the doc dictionnary */
48     int check;                  /* do just checkings */
49     int errors;                 /* number of errors found */
50     int nodict;			/* if the document has no dictionnary */
51     int options;		/* options */
52 };
53 
54 static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
55 
56 static void
xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)57 xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
58 {
59     int i;
60 
61     ctxt->depth = 0;
62     ctxt->check = 0;
63     ctxt->errors = 0;
64     ctxt->output = stdout;
65     ctxt->doc = NULL;
66     ctxt->node = NULL;
67     ctxt->dict = NULL;
68     ctxt->nodict = 0;
69     ctxt->options = 0;
70     for (i = 0; i < 100; i++)
71         ctxt->shift[i] = ' ';
72     ctxt->shift[100] = 0;
73 }
74 
75 static void
xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)76 xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)
77 {
78  /* remove the ATTRIBUTE_UNUSED when this is added */
79 }
80 
81 /**
82  * xmlNsCheckScope:
83  * @node: the node
84  * @ns: the namespace node
85  *
86  * Check that a given namespace is in scope on a node.
87  *
88  * Returns 1 if in scope, -1 in case of argument error,
89  *         -2 if the namespace is not in scope, and -3 if not on
90  *         an ancestor node.
91  */
92 static int
xmlNsCheckScope(xmlNodePtr node,xmlNsPtr ns)93 xmlNsCheckScope(xmlNodePtr node, xmlNsPtr ns)
94 {
95     xmlNsPtr cur;
96 
97     if ((node == NULL) || (ns == NULL))
98         return(-1);
99 
100     if ((node->type != XML_ELEMENT_NODE) &&
101 	(node->type != XML_ATTRIBUTE_NODE) &&
102 	(node->type != XML_DOCUMENT_NODE) &&
103 	(node->type != XML_TEXT_NODE) &&
104 	(node->type != XML_HTML_DOCUMENT_NODE) &&
105 	(node->type != XML_XINCLUDE_START))
106 	return(-2);
107 
108     while ((node != NULL) &&
109            ((node->type == XML_ELEMENT_NODE) ||
110             (node->type == XML_ATTRIBUTE_NODE) ||
111             (node->type == XML_TEXT_NODE) ||
112 	    (node->type == XML_XINCLUDE_START))) {
113 	if ((node->type == XML_ELEMENT_NODE) ||
114 	    (node->type == XML_XINCLUDE_START)) {
115 	    cur = node->nsDef;
116 	    while (cur != NULL) {
117 	        if (cur == ns)
118 		    return(1);
119 		if (xmlStrEqual(cur->prefix, ns->prefix))
120 		    return(-2);
121 		cur = cur->next;
122 	    }
123 	}
124 	node = node->parent;
125     }
126     /* the xml namespace may be declared on the document node */
127     if ((node != NULL) &&
128         ((node->type == XML_DOCUMENT_NODE) ||
129 	 (node->type == XML_HTML_DOCUMENT_NODE))) {
130 	 xmlNsPtr oldNs = ((xmlDocPtr) node)->oldNs;
131 	 if (oldNs == ns)
132 	     return(1);
133     }
134     return(-3);
135 }
136 
137 static void
xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)138 xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
139 {
140     if (ctxt->check)
141         return;
142     if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
143         if (ctxt->depth < 50)
144             fprintf(ctxt->output, "%s", &ctxt->shift[100 - 2 * ctxt->depth]);
145         else
146             fprintf(ctxt->output, "%s", ctxt->shift);
147     }
148 }
149 
150 /**
151  * xmlDebugErr:
152  * @ctxt:  a debug context
153  * @error:  the error code
154  *
155  * Handle a debug error.
156  */
157 static void
xmlDebugErr(xmlDebugCtxtPtr ctxt,int error,const char * msg)158 xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
159 {
160     ctxt->errors++;
161     __xmlRaiseError(NULL, NULL, NULL,
162 		    NULL, ctxt->node, XML_FROM_CHECK,
163 		    error, XML_ERR_ERROR, NULL, 0,
164 		    NULL, NULL, NULL, 0, 0,
165 		    "%s", msg);
166 }
167 static void
xmlDebugErr2(xmlDebugCtxtPtr ctxt,int error,const char * msg,int extra)168 xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra)
169 {
170     ctxt->errors++;
171     __xmlRaiseError(NULL, NULL, NULL,
172 		    NULL, ctxt->node, XML_FROM_CHECK,
173 		    error, XML_ERR_ERROR, NULL, 0,
174 		    NULL, NULL, NULL, 0, 0,
175 		    msg, extra);
176 }
177 static void
xmlDebugErr3(xmlDebugCtxtPtr ctxt,int error,const char * msg,const char * extra)178 xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, const char *extra)
179 {
180     ctxt->errors++;
181     __xmlRaiseError(NULL, NULL, NULL,
182 		    NULL, ctxt->node, XML_FROM_CHECK,
183 		    error, XML_ERR_ERROR, NULL, 0,
184 		    NULL, NULL, NULL, 0, 0,
185 		    msg, extra);
186 }
187 
188 /**
189  * xmlCtxtNsCheckScope:
190  * @ctxt: the debugging context
191  * @node: the node
192  * @ns: the namespace node
193  *
194  * Report if a given namespace is is not in scope.
195  */
196 static void
xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt,xmlNodePtr node,xmlNsPtr ns)197 xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt, xmlNodePtr node, xmlNsPtr ns)
198 {
199     int ret;
200 
201     ret = xmlNsCheckScope(node, ns);
202     if (ret == -2) {
203         if (ns->prefix == NULL)
204 	    xmlDebugErr(ctxt, XML_CHECK_NS_SCOPE,
205 			"Reference to default namespace not in scope\n");
206 	else
207 	    xmlDebugErr3(ctxt, XML_CHECK_NS_SCOPE,
208 			 "Reference to namespace '%s' not in scope\n",
209 			 (char *) ns->prefix);
210     }
211     if (ret == -3) {
212         if (ns->prefix == NULL)
213 	    xmlDebugErr(ctxt, XML_CHECK_NS_ANCESTOR,
214 			"Reference to default namespace not on ancestor\n");
215 	else
216 	    xmlDebugErr3(ctxt, XML_CHECK_NS_ANCESTOR,
217 			 "Reference to namespace '%s' not on ancestor\n",
218 			 (char *) ns->prefix);
219     }
220 }
221 
222 /**
223  * xmlCtxtCheckString:
224  * @ctxt: the debug context
225  * @str: the string
226  *
227  * Do debugging on the string, currently it just checks the UTF-8 content
228  */
229 static void
xmlCtxtCheckString(xmlDebugCtxtPtr ctxt,const xmlChar * str)230 xmlCtxtCheckString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
231 {
232     if (str == NULL) return;
233     if (ctxt->check) {
234         if (!xmlCheckUTF8(str)) {
235 	    xmlDebugErr3(ctxt, XML_CHECK_NOT_UTF8,
236 			 "String is not UTF-8 %s", (const char *) str);
237 	}
238     }
239 }
240 
241 /**
242  * xmlCtxtCheckName:
243  * @ctxt: the debug context
244  * @name: the name
245  *
246  * Do debugging on the name, for example the dictionnary status and
247  * conformance to the Name production.
248  */
249 static void
xmlCtxtCheckName(xmlDebugCtxtPtr ctxt,const xmlChar * name)250 xmlCtxtCheckName(xmlDebugCtxtPtr ctxt, const xmlChar * name)
251 {
252     if (ctxt->check) {
253 	if (name == NULL) {
254 	    xmlDebugErr(ctxt, XML_CHECK_NO_NAME, "Name is NULL");
255 	    return;
256 	}
257 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
258         if (xmlValidateName(name, 0)) {
259 	    xmlDebugErr3(ctxt, XML_CHECK_NOT_NCNAME,
260 			 "Name is not an NCName '%s'", (const char *) name);
261 	}
262 #endif
263 	if ((ctxt->dict != NULL) &&
264 	    (!xmlDictOwns(ctxt->dict, name)) &&
265             ((ctxt->doc == NULL) ||
266              ((ctxt->doc->parseFlags & (XML_PARSE_SAX1 | XML_PARSE_NODICT)) == 0))) {
267 	    xmlDebugErr3(ctxt, XML_CHECK_OUTSIDE_DICT,
268 			 "Name is not from the document dictionnary '%s'",
269 			 (const char *) name);
270 	}
271     }
272 }
273 
274 static void
xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt,xmlNodePtr node)275 xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
276     xmlDocPtr doc;
277     xmlDictPtr dict;
278 
279     doc = node->doc;
280 
281     if (node->parent == NULL)
282         xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
283 	            "Node has no parent\n");
284     if (node->doc == NULL) {
285         xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
286 	            "Node has no doc\n");
287         dict = NULL;
288     } else {
289 	dict = doc->dict;
290 	if ((dict == NULL) && (ctxt->nodict == 0)) {
291 #if 0
292             /* desactivated right now as it raises too many errors */
293 	    if (doc->type == XML_DOCUMENT_NODE)
294 		xmlDebugErr(ctxt, XML_CHECK_NO_DICT,
295 			    "Document has no dictionnary\n");
296 #endif
297 	    ctxt->nodict = 1;
298 	}
299 	if (ctxt->doc == NULL)
300 	    ctxt->doc = doc;
301 
302 	if (ctxt->dict == NULL) {
303 	    ctxt->dict = dict;
304 	}
305     }
306     if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
307         (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
308         xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
309 	            "Node doc differs from parent's one\n");
310     if (node->prev == NULL) {
311         if (node->type == XML_ATTRIBUTE_NODE) {
312 	    if ((node->parent != NULL) &&
313 	        (node != (xmlNodePtr) node->parent->properties))
314 		xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
315                     "Attr has no prev and not first of attr list\n");
316 
317         } else if ((node->parent != NULL) && (node->parent->children != node))
318 	    xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
319                     "Node has no prev and not first of parent list\n");
320     } else {
321         if (node->prev->next != node)
322 	    xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
323                         "Node prev->next : back link wrong\n");
324     }
325     if (node->next == NULL) {
326 	if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
327 	    (node->parent->last != node) &&
328 	    (node->parent->type == XML_ELEMENT_NODE))
329 	    xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
330                     "Node has no next and not last of parent list\n");
331     } else {
332         if (node->next->prev != node)
333 	    xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
334                     "Node next->prev : forward link wrong\n");
335         if (node->next->parent != node->parent)
336 	    xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT,
337                     "Node next->prev : forward link wrong\n");
338     }
339     if (node->type == XML_ELEMENT_NODE) {
340         xmlNsPtr ns;
341 
342 	ns = node->nsDef;
343 	while (ns != NULL) {
344 	    xmlCtxtNsCheckScope(ctxt, node, ns);
345 	    ns = ns->next;
346 	}
347 	if (node->ns != NULL)
348 	    xmlCtxtNsCheckScope(ctxt, node, node->ns);
349     } else if (node->type == XML_ATTRIBUTE_NODE) {
350 	if (node->ns != NULL)
351 	    xmlCtxtNsCheckScope(ctxt, node, node->ns);
352     }
353 
354     if ((node->type != XML_ELEMENT_NODE) &&
355 	(node->type != XML_ATTRIBUTE_NODE) &&
356 	(node->type != XML_ELEMENT_DECL) &&
357 	(node->type != XML_ATTRIBUTE_DECL) &&
358 	(node->type != XML_DTD_NODE) &&
359 	(node->type != XML_HTML_DOCUMENT_NODE) &&
360 	(node->type != XML_DOCUMENT_NODE)) {
361 	if (node->content != NULL)
362 	    xmlCtxtCheckString(ctxt, (const xmlChar *) node->content);
363     }
364     switch (node->type) {
365         case XML_ELEMENT_NODE:
366         case XML_ATTRIBUTE_NODE:
367 	    xmlCtxtCheckName(ctxt, node->name);
368 	    break;
369         case XML_TEXT_NODE:
370 	    if ((node->name == xmlStringText) ||
371 	        (node->name == xmlStringTextNoenc))
372 		break;
373 	    /* some case of entity substitution can lead to this */
374 	    if ((ctxt->dict != NULL) &&
375 	        (node->name == xmlDictLookup(ctxt->dict, BAD_CAST "nbktext",
376 		                             7)))
377 		break;
378 
379 	    xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
380 			 "Text node has wrong name '%s'",
381 			 (const char *) node->name);
382 	    break;
383         case XML_COMMENT_NODE:
384 	    if (node->name == xmlStringComment)
385 		break;
386 	    xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
387 			 "Comment node has wrong name '%s'",
388 			 (const char *) node->name);
389 	    break;
390         case XML_PI_NODE:
391 	    xmlCtxtCheckName(ctxt, node->name);
392 	    break;
393         case XML_CDATA_SECTION_NODE:
394 	    if (node->name == NULL)
395 		break;
396 	    xmlDebugErr3(ctxt, XML_CHECK_NAME_NOT_NULL,
397 			 "CData section has non NULL name '%s'",
398 			 (const char *) node->name);
399 	    break;
400         case XML_ENTITY_REF_NODE:
401         case XML_ENTITY_NODE:
402         case XML_DOCUMENT_TYPE_NODE:
403         case XML_DOCUMENT_FRAG_NODE:
404         case XML_NOTATION_NODE:
405         case XML_DTD_NODE:
406         case XML_ELEMENT_DECL:
407         case XML_ATTRIBUTE_DECL:
408         case XML_ENTITY_DECL:
409         case XML_NAMESPACE_DECL:
410         case XML_XINCLUDE_START:
411         case XML_XINCLUDE_END:
412 #ifdef LIBXML_DOCB_ENABLED
413         case XML_DOCB_DOCUMENT_NODE:
414 #endif
415         case XML_DOCUMENT_NODE:
416         case XML_HTML_DOCUMENT_NODE:
417 	    break;
418     }
419 }
420 
421 static void
xmlCtxtDumpString(xmlDebugCtxtPtr ctxt,const xmlChar * str)422 xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
423 {
424     int i;
425 
426     if (ctxt->check) {
427         return;
428     }
429     /* TODO: check UTF8 content of the string */
430     if (str == NULL) {
431         fprintf(ctxt->output, "(NULL)");
432         return;
433     }
434     for (i = 0; i < 40; i++)
435         if (str[i] == 0)
436             return;
437         else if (IS_BLANK_CH(str[i]))
438             fputc(' ', ctxt->output);
439         else if (str[i] >= 0x80)
440             fprintf(ctxt->output, "#%X", str[i]);
441         else
442             fputc(str[i], ctxt->output);
443     fprintf(ctxt->output, "...");
444 }
445 
446 static void
xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)447 xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
448 {
449     xmlCtxtDumpSpaces(ctxt);
450 
451     if (dtd == NULL) {
452         if (!ctxt->check)
453             fprintf(ctxt->output, "DTD node is NULL\n");
454         return;
455     }
456 
457     if (dtd->type != XML_DTD_NODE) {
458 	xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
459 	            "Node is not a DTD");
460         return;
461     }
462     if (!ctxt->check) {
463         if (dtd->name != NULL)
464             fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
465         else
466             fprintf(ctxt->output, "DTD");
467         if (dtd->ExternalID != NULL)
468             fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
469         if (dtd->SystemID != NULL)
470             fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
471         fprintf(ctxt->output, "\n");
472     }
473     /*
474      * Do a bit of checking
475      */
476     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
477 }
478 
479 static void
xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt,xmlAttributePtr attr)480 xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
481 {
482     xmlCtxtDumpSpaces(ctxt);
483 
484     if (attr == NULL) {
485         if (!ctxt->check)
486             fprintf(ctxt->output, "Attribute declaration is NULL\n");
487         return;
488     }
489     if (attr->type != XML_ATTRIBUTE_DECL) {
490 	xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
491 	            "Node is not an attribute declaration");
492         return;
493     }
494     if (attr->name != NULL) {
495         if (!ctxt->check)
496             fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
497     } else
498 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
499 	            "Node attribute declaration has no name");
500     if (attr->elem != NULL) {
501         if (!ctxt->check)
502             fprintf(ctxt->output, " for %s", (char *) attr->elem);
503     } else
504 	xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
505 	            "Node attribute declaration has no element name");
506     if (!ctxt->check) {
507         switch (attr->atype) {
508             case XML_ATTRIBUTE_CDATA:
509                 fprintf(ctxt->output, " CDATA");
510                 break;
511             case XML_ATTRIBUTE_ID:
512                 fprintf(ctxt->output, " ID");
513                 break;
514             case XML_ATTRIBUTE_IDREF:
515                 fprintf(ctxt->output, " IDREF");
516                 break;
517             case XML_ATTRIBUTE_IDREFS:
518                 fprintf(ctxt->output, " IDREFS");
519                 break;
520             case XML_ATTRIBUTE_ENTITY:
521                 fprintf(ctxt->output, " ENTITY");
522                 break;
523             case XML_ATTRIBUTE_ENTITIES:
524                 fprintf(ctxt->output, " ENTITIES");
525                 break;
526             case XML_ATTRIBUTE_NMTOKEN:
527                 fprintf(ctxt->output, " NMTOKEN");
528                 break;
529             case XML_ATTRIBUTE_NMTOKENS:
530                 fprintf(ctxt->output, " NMTOKENS");
531                 break;
532             case XML_ATTRIBUTE_ENUMERATION:
533                 fprintf(ctxt->output, " ENUMERATION");
534                 break;
535             case XML_ATTRIBUTE_NOTATION:
536                 fprintf(ctxt->output, " NOTATION ");
537                 break;
538         }
539         if (attr->tree != NULL) {
540             int indx;
541             xmlEnumerationPtr cur = attr->tree;
542 
543             for (indx = 0; indx < 5; indx++) {
544                 if (indx != 0)
545                     fprintf(ctxt->output, "|%s", (char *) cur->name);
546                 else
547                     fprintf(ctxt->output, " (%s", (char *) cur->name);
548                 cur = cur->next;
549                 if (cur == NULL)
550                     break;
551             }
552             if (cur == NULL)
553                 fprintf(ctxt->output, ")");
554             else
555                 fprintf(ctxt->output, "...)");
556         }
557         switch (attr->def) {
558             case XML_ATTRIBUTE_NONE:
559                 break;
560             case XML_ATTRIBUTE_REQUIRED:
561                 fprintf(ctxt->output, " REQUIRED");
562                 break;
563             case XML_ATTRIBUTE_IMPLIED:
564                 fprintf(ctxt->output, " IMPLIED");
565                 break;
566             case XML_ATTRIBUTE_FIXED:
567                 fprintf(ctxt->output, " FIXED");
568                 break;
569         }
570         if (attr->defaultValue != NULL) {
571             fprintf(ctxt->output, "\"");
572             xmlCtxtDumpString(ctxt, attr->defaultValue);
573             fprintf(ctxt->output, "\"");
574         }
575         fprintf(ctxt->output, "\n");
576     }
577 
578     /*
579      * Do a bit of checking
580      */
581     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
582 }
583 
584 static void
xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt,xmlElementPtr elem)585 xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
586 {
587     xmlCtxtDumpSpaces(ctxt);
588 
589     if (elem == NULL) {
590         if (!ctxt->check)
591             fprintf(ctxt->output, "Element declaration is NULL\n");
592         return;
593     }
594     if (elem->type != XML_ELEMENT_DECL) {
595 	xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
596 	            "Node is not an element declaration");
597         return;
598     }
599     if (elem->name != NULL) {
600         if (!ctxt->check) {
601             fprintf(ctxt->output, "ELEMDECL(");
602             xmlCtxtDumpString(ctxt, elem->name);
603             fprintf(ctxt->output, ")");
604         }
605     } else
606 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
607 	            "Element declaration has no name");
608     if (!ctxt->check) {
609         switch (elem->etype) {
610             case XML_ELEMENT_TYPE_UNDEFINED:
611                 fprintf(ctxt->output, ", UNDEFINED");
612                 break;
613             case XML_ELEMENT_TYPE_EMPTY:
614                 fprintf(ctxt->output, ", EMPTY");
615                 break;
616             case XML_ELEMENT_TYPE_ANY:
617                 fprintf(ctxt->output, ", ANY");
618                 break;
619             case XML_ELEMENT_TYPE_MIXED:
620                 fprintf(ctxt->output, ", MIXED ");
621                 break;
622             case XML_ELEMENT_TYPE_ELEMENT:
623                 fprintf(ctxt->output, ", MIXED ");
624                 break;
625         }
626         if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
627             char buf[5001];
628 
629             buf[0] = 0;
630             xmlSnprintfElementContent(buf, 5000, elem->content, 1);
631             buf[5000] = 0;
632             fprintf(ctxt->output, "%s", buf);
633         }
634         fprintf(ctxt->output, "\n");
635     }
636 
637     /*
638      * Do a bit of checking
639      */
640     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
641 }
642 
643 static void
xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)644 xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
645 {
646     xmlCtxtDumpSpaces(ctxt);
647 
648     if (ent == NULL) {
649         if (!ctxt->check)
650             fprintf(ctxt->output, "Entity declaration is NULL\n");
651         return;
652     }
653     if (ent->type != XML_ENTITY_DECL) {
654 	xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
655 	            "Node is not an entity declaration");
656         return;
657     }
658     if (ent->name != NULL) {
659         if (!ctxt->check) {
660             fprintf(ctxt->output, "ENTITYDECL(");
661             xmlCtxtDumpString(ctxt, ent->name);
662             fprintf(ctxt->output, ")");
663         }
664     } else
665 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
666 	            "Entity declaration has no name");
667     if (!ctxt->check) {
668         switch (ent->etype) {
669             case XML_INTERNAL_GENERAL_ENTITY:
670                 fprintf(ctxt->output, ", internal\n");
671                 break;
672             case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
673                 fprintf(ctxt->output, ", external parsed\n");
674                 break;
675             case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
676                 fprintf(ctxt->output, ", unparsed\n");
677                 break;
678             case XML_INTERNAL_PARAMETER_ENTITY:
679                 fprintf(ctxt->output, ", parameter\n");
680                 break;
681             case XML_EXTERNAL_PARAMETER_ENTITY:
682                 fprintf(ctxt->output, ", external parameter\n");
683                 break;
684             case XML_INTERNAL_PREDEFINED_ENTITY:
685                 fprintf(ctxt->output, ", predefined\n");
686                 break;
687         }
688         if (ent->ExternalID) {
689             xmlCtxtDumpSpaces(ctxt);
690             fprintf(ctxt->output, " ExternalID=%s\n",
691                     (char *) ent->ExternalID);
692         }
693         if (ent->SystemID) {
694             xmlCtxtDumpSpaces(ctxt);
695             fprintf(ctxt->output, " SystemID=%s\n",
696                     (char *) ent->SystemID);
697         }
698         if (ent->URI != NULL) {
699             xmlCtxtDumpSpaces(ctxt);
700             fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
701         }
702         if (ent->content) {
703             xmlCtxtDumpSpaces(ctxt);
704             fprintf(ctxt->output, " content=");
705             xmlCtxtDumpString(ctxt, ent->content);
706             fprintf(ctxt->output, "\n");
707         }
708     }
709 
710     /*
711      * Do a bit of checking
712      */
713     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
714 }
715 
716 static void
xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)717 xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
718 {
719     xmlCtxtDumpSpaces(ctxt);
720 
721     if (ns == NULL) {
722         if (!ctxt->check)
723             fprintf(ctxt->output, "namespace node is NULL\n");
724         return;
725     }
726     if (ns->type != XML_NAMESPACE_DECL) {
727 	xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
728 	            "Node is not a namespace declaration");
729         return;
730     }
731     if (ns->href == NULL) {
732         if (ns->prefix != NULL)
733 	    xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
734                     "Incomplete namespace %s href=NULL\n",
735                     (char *) ns->prefix);
736         else
737 	    xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
738                     "Incomplete default namespace href=NULL\n");
739     } else {
740         if (!ctxt->check) {
741             if (ns->prefix != NULL)
742                 fprintf(ctxt->output, "namespace %s href=",
743                         (char *) ns->prefix);
744             else
745                 fprintf(ctxt->output, "default namespace href=");
746 
747             xmlCtxtDumpString(ctxt, ns->href);
748             fprintf(ctxt->output, "\n");
749         }
750     }
751 }
752 
753 static void
xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)754 xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
755 {
756     while (ns != NULL) {
757         xmlCtxtDumpNamespace(ctxt, ns);
758         ns = ns->next;
759     }
760 }
761 
762 static void
xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)763 xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
764 {
765     xmlCtxtDumpSpaces(ctxt);
766 
767     if (ent == NULL) {
768         if (!ctxt->check)
769             fprintf(ctxt->output, "Entity is NULL\n");
770         return;
771     }
772     if (!ctxt->check) {
773         switch (ent->etype) {
774             case XML_INTERNAL_GENERAL_ENTITY:
775                 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
776                 break;
777             case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
778                 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
779                 break;
780             case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
781                 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
782                 break;
783             case XML_INTERNAL_PARAMETER_ENTITY:
784                 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
785                 break;
786             case XML_EXTERNAL_PARAMETER_ENTITY:
787                 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
788                 break;
789             default:
790                 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
791         }
792         fprintf(ctxt->output, "%s\n", ent->name);
793         if (ent->ExternalID) {
794             xmlCtxtDumpSpaces(ctxt);
795             fprintf(ctxt->output, "ExternalID=%s\n",
796                     (char *) ent->ExternalID);
797         }
798         if (ent->SystemID) {
799             xmlCtxtDumpSpaces(ctxt);
800             fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
801         }
802         if (ent->URI) {
803             xmlCtxtDumpSpaces(ctxt);
804             fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
805         }
806         if (ent->content) {
807             xmlCtxtDumpSpaces(ctxt);
808             fprintf(ctxt->output, "content=");
809             xmlCtxtDumpString(ctxt, ent->content);
810             fprintf(ctxt->output, "\n");
811         }
812     }
813 }
814 
815 /**
816  * xmlCtxtDumpAttr:
817  * @output:  the FILE * for the output
818  * @attr:  the attribute
819  * @depth:  the indentation level.
820  *
821  * Dumps debug information for the attribute
822  */
823 static void
xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)824 xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
825 {
826     xmlCtxtDumpSpaces(ctxt);
827 
828     if (attr == NULL) {
829         if (!ctxt->check)
830             fprintf(ctxt->output, "Attr is NULL");
831         return;
832     }
833     if (!ctxt->check) {
834         fprintf(ctxt->output, "ATTRIBUTE ");
835 	xmlCtxtDumpString(ctxt, attr->name);
836         fprintf(ctxt->output, "\n");
837         if (attr->children != NULL) {
838             ctxt->depth++;
839             xmlCtxtDumpNodeList(ctxt, attr->children);
840             ctxt->depth--;
841         }
842     }
843     if (attr->name == NULL)
844 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
845 	            "Attribute has no name");
846 
847     /*
848      * Do a bit of checking
849      */
850     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
851 }
852 
853 /**
854  * xmlCtxtDumpAttrList:
855  * @output:  the FILE * for the output
856  * @attr:  the attribute list
857  * @depth:  the indentation level.
858  *
859  * Dumps debug information for the attribute list
860  */
861 static void
xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)862 xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
863 {
864     while (attr != NULL) {
865         xmlCtxtDumpAttr(ctxt, attr);
866         attr = attr->next;
867     }
868 }
869 
870 /**
871  * xmlCtxtDumpOneNode:
872  * @output:  the FILE * for the output
873  * @node:  the node
874  * @depth:  the indentation level.
875  *
876  * Dumps debug information for the element node, it is not recursive
877  */
878 static void
xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)879 xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
880 {
881     if (node == NULL) {
882         if (!ctxt->check) {
883             xmlCtxtDumpSpaces(ctxt);
884             fprintf(ctxt->output, "node is NULL\n");
885         }
886         return;
887     }
888     ctxt->node = node;
889 
890     switch (node->type) {
891         case XML_ELEMENT_NODE:
892             if (!ctxt->check) {
893                 xmlCtxtDumpSpaces(ctxt);
894                 fprintf(ctxt->output, "ELEMENT ");
895                 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
896                     xmlCtxtDumpString(ctxt, node->ns->prefix);
897                     fprintf(ctxt->output, ":");
898                 }
899                 xmlCtxtDumpString(ctxt, node->name);
900                 fprintf(ctxt->output, "\n");
901             }
902             break;
903         case XML_ATTRIBUTE_NODE:
904             if (!ctxt->check)
905                 xmlCtxtDumpSpaces(ctxt);
906             fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
907             xmlCtxtGenericNodeCheck(ctxt, node);
908             return;
909         case XML_TEXT_NODE:
910             if (!ctxt->check) {
911                 xmlCtxtDumpSpaces(ctxt);
912                 if (node->name == (const xmlChar *) xmlStringTextNoenc)
913                     fprintf(ctxt->output, "TEXT no enc");
914                 else
915                     fprintf(ctxt->output, "TEXT");
916 		if (ctxt->options & DUMP_TEXT_TYPE) {
917 		    if (node->content == (xmlChar *) &(node->properties))
918 			fprintf(ctxt->output, " compact\n");
919 		    else if (xmlDictOwns(ctxt->dict, node->content) == 1)
920 			fprintf(ctxt->output, " interned\n");
921 		    else
922 			fprintf(ctxt->output, "\n");
923 		} else
924 		    fprintf(ctxt->output, "\n");
925             }
926             break;
927         case XML_CDATA_SECTION_NODE:
928             if (!ctxt->check) {
929                 xmlCtxtDumpSpaces(ctxt);
930                 fprintf(ctxt->output, "CDATA_SECTION\n");
931             }
932             break;
933         case XML_ENTITY_REF_NODE:
934             if (!ctxt->check) {
935                 xmlCtxtDumpSpaces(ctxt);
936                 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
937                         (char *) node->name);
938             }
939             break;
940         case XML_ENTITY_NODE:
941             if (!ctxt->check) {
942                 xmlCtxtDumpSpaces(ctxt);
943                 fprintf(ctxt->output, "ENTITY\n");
944             }
945             break;
946         case XML_PI_NODE:
947             if (!ctxt->check) {
948                 xmlCtxtDumpSpaces(ctxt);
949                 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
950             }
951             break;
952         case XML_COMMENT_NODE:
953             if (!ctxt->check) {
954                 xmlCtxtDumpSpaces(ctxt);
955                 fprintf(ctxt->output, "COMMENT\n");
956             }
957             break;
958         case XML_DOCUMENT_NODE:
959         case XML_HTML_DOCUMENT_NODE:
960             if (!ctxt->check) {
961                 xmlCtxtDumpSpaces(ctxt);
962             }
963             fprintf(ctxt->output, "Error, DOCUMENT found here\n");
964             xmlCtxtGenericNodeCheck(ctxt, node);
965             return;
966         case XML_DOCUMENT_TYPE_NODE:
967             if (!ctxt->check) {
968                 xmlCtxtDumpSpaces(ctxt);
969                 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
970             }
971             break;
972         case XML_DOCUMENT_FRAG_NODE:
973             if (!ctxt->check) {
974                 xmlCtxtDumpSpaces(ctxt);
975                 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
976             }
977             break;
978         case XML_NOTATION_NODE:
979             if (!ctxt->check) {
980                 xmlCtxtDumpSpaces(ctxt);
981                 fprintf(ctxt->output, "NOTATION\n");
982             }
983             break;
984         case XML_DTD_NODE:
985             xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
986             return;
987         case XML_ELEMENT_DECL:
988             xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
989             return;
990         case XML_ATTRIBUTE_DECL:
991             xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
992             return;
993         case XML_ENTITY_DECL:
994             xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
995             return;
996         case XML_NAMESPACE_DECL:
997             xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
998             return;
999         case XML_XINCLUDE_START:
1000             if (!ctxt->check) {
1001                 xmlCtxtDumpSpaces(ctxt);
1002                 fprintf(ctxt->output, "INCLUDE START\n");
1003             }
1004             return;
1005         case XML_XINCLUDE_END:
1006             if (!ctxt->check) {
1007                 xmlCtxtDumpSpaces(ctxt);
1008                 fprintf(ctxt->output, "INCLUDE END\n");
1009             }
1010             return;
1011         default:
1012             if (!ctxt->check)
1013                 xmlCtxtDumpSpaces(ctxt);
1014 	    xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
1015 	                "Unknown node type %d\n", node->type);
1016             return;
1017     }
1018     if (node->doc == NULL) {
1019         if (!ctxt->check) {
1020             xmlCtxtDumpSpaces(ctxt);
1021         }
1022         fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
1023     }
1024     ctxt->depth++;
1025     if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
1026         xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
1027     if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
1028         xmlCtxtDumpAttrList(ctxt, node->properties);
1029     if (node->type != XML_ENTITY_REF_NODE) {
1030         if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
1031             if (!ctxt->check) {
1032                 xmlCtxtDumpSpaces(ctxt);
1033                 fprintf(ctxt->output, "content=");
1034                 xmlCtxtDumpString(ctxt, node->content);
1035                 fprintf(ctxt->output, "\n");
1036             }
1037         }
1038     } else {
1039         xmlEntityPtr ent;
1040 
1041         ent = xmlGetDocEntity(node->doc, node->name);
1042         if (ent != NULL)
1043             xmlCtxtDumpEntity(ctxt, ent);
1044     }
1045     ctxt->depth--;
1046 
1047     /*
1048      * Do a bit of checking
1049      */
1050     xmlCtxtGenericNodeCheck(ctxt, node);
1051 }
1052 
1053 /**
1054  * xmlCtxtDumpNode:
1055  * @output:  the FILE * for the output
1056  * @node:  the node
1057  * @depth:  the indentation level.
1058  *
1059  * Dumps debug information for the element node, it is recursive
1060  */
1061 static void
xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1062 xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1063 {
1064     if (node == NULL) {
1065         if (!ctxt->check) {
1066             xmlCtxtDumpSpaces(ctxt);
1067             fprintf(ctxt->output, "node is NULL\n");
1068         }
1069         return;
1070     }
1071     xmlCtxtDumpOneNode(ctxt, node);
1072     if ((node->type != XML_NAMESPACE_DECL) &&
1073         (node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1074         ctxt->depth++;
1075         xmlCtxtDumpNodeList(ctxt, node->children);
1076         ctxt->depth--;
1077     }
1078 }
1079 
1080 /**
1081  * xmlCtxtDumpNodeList:
1082  * @output:  the FILE * for the output
1083  * @node:  the node list
1084  * @depth:  the indentation level.
1085  *
1086  * Dumps debug information for the list of element node, it is recursive
1087  */
1088 static void
xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1089 xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1090 {
1091     while (node != NULL) {
1092         xmlCtxtDumpNode(ctxt, node);
1093         node = node->next;
1094     }
1095 }
1096 
1097 static void
xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1098 xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1099 {
1100     if (doc == NULL) {
1101         if (!ctxt->check)
1102             fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1103         return;
1104     }
1105     ctxt->node = (xmlNodePtr) doc;
1106 
1107     switch (doc->type) {
1108         case XML_ELEMENT_NODE:
1109 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
1110 	                "Misplaced ELEMENT node\n");
1111             break;
1112         case XML_ATTRIBUTE_NODE:
1113 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
1114 	                "Misplaced ATTRIBUTE node\n");
1115             break;
1116         case XML_TEXT_NODE:
1117 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
1118 	                "Misplaced TEXT node\n");
1119             break;
1120         case XML_CDATA_SECTION_NODE:
1121 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
1122 	                "Misplaced CDATA node\n");
1123             break;
1124         case XML_ENTITY_REF_NODE:
1125 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
1126 	                "Misplaced ENTITYREF node\n");
1127             break;
1128         case XML_ENTITY_NODE:
1129 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
1130 	                "Misplaced ENTITY node\n");
1131             break;
1132         case XML_PI_NODE:
1133 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
1134 	                "Misplaced PI node\n");
1135             break;
1136         case XML_COMMENT_NODE:
1137 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
1138 	                "Misplaced COMMENT node\n");
1139             break;
1140         case XML_DOCUMENT_NODE:
1141 	    if (!ctxt->check)
1142 		fprintf(ctxt->output, "DOCUMENT\n");
1143             break;
1144         case XML_HTML_DOCUMENT_NODE:
1145 	    if (!ctxt->check)
1146 		fprintf(ctxt->output, "HTML DOCUMENT\n");
1147             break;
1148         case XML_DOCUMENT_TYPE_NODE:
1149 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
1150 	                "Misplaced DOCTYPE node\n");
1151             break;
1152         case XML_DOCUMENT_FRAG_NODE:
1153 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
1154 	                "Misplaced FRAGMENT node\n");
1155             break;
1156         case XML_NOTATION_NODE:
1157 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
1158 	                "Misplaced NOTATION node\n");
1159             break;
1160         default:
1161 	    xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
1162 	                "Unknown node type %d\n", doc->type);
1163     }
1164 }
1165 
1166 /**
1167  * xmlCtxtDumpDocumentHead:
1168  * @output:  the FILE * for the output
1169  * @doc:  the document
1170  *
1171  * Dumps debug information cncerning the document, not recursive
1172  */
1173 static void
xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1174 xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1175 {
1176     if (doc == NULL) return;
1177     xmlCtxtDumpDocHead(ctxt, doc);
1178     if (!ctxt->check) {
1179         if (doc->name != NULL) {
1180             fprintf(ctxt->output, "name=");
1181             xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
1182             fprintf(ctxt->output, "\n");
1183         }
1184         if (doc->version != NULL) {
1185             fprintf(ctxt->output, "version=");
1186             xmlCtxtDumpString(ctxt, doc->version);
1187             fprintf(ctxt->output, "\n");
1188         }
1189         if (doc->encoding != NULL) {
1190             fprintf(ctxt->output, "encoding=");
1191             xmlCtxtDumpString(ctxt, doc->encoding);
1192             fprintf(ctxt->output, "\n");
1193         }
1194         if (doc->URL != NULL) {
1195             fprintf(ctxt->output, "URL=");
1196             xmlCtxtDumpString(ctxt, doc->URL);
1197             fprintf(ctxt->output, "\n");
1198         }
1199         if (doc->standalone)
1200             fprintf(ctxt->output, "standalone=true\n");
1201     }
1202     if (doc->oldNs != NULL)
1203         xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
1204 }
1205 
1206 /**
1207  * xmlCtxtDumpDocument:
1208  * @output:  the FILE * for the output
1209  * @doc:  the document
1210  *
1211  * Dumps debug information for the document, it's recursive
1212  */
1213 static void
xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1214 xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1215 {
1216     if (doc == NULL) {
1217         if (!ctxt->check)
1218             fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1219         return;
1220     }
1221     xmlCtxtDumpDocumentHead(ctxt, doc);
1222     if (((doc->type == XML_DOCUMENT_NODE) ||
1223          (doc->type == XML_HTML_DOCUMENT_NODE))
1224         && (doc->children != NULL)) {
1225         ctxt->depth++;
1226         xmlCtxtDumpNodeList(ctxt, doc->children);
1227         ctxt->depth--;
1228     }
1229 }
1230 
1231 static void
xmlCtxtDumpEntityCallback(xmlEntityPtr cur,xmlDebugCtxtPtr ctxt)1232 xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt)
1233 {
1234     if (cur == NULL) {
1235         if (!ctxt->check)
1236             fprintf(ctxt->output, "Entity is NULL");
1237         return;
1238     }
1239     if (!ctxt->check) {
1240         fprintf(ctxt->output, "%s : ", (char *) cur->name);
1241         switch (cur->etype) {
1242             case XML_INTERNAL_GENERAL_ENTITY:
1243                 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1244                 break;
1245             case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1246                 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1247                 break;
1248             case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1249                 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1250                 break;
1251             case XML_INTERNAL_PARAMETER_ENTITY:
1252                 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1253                 break;
1254             case XML_EXTERNAL_PARAMETER_ENTITY:
1255                 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1256                 break;
1257             default:
1258 		xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1259 			     "Unknown entity type %d\n", cur->etype);
1260         }
1261         if (cur->ExternalID != NULL)
1262             fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1263         if (cur->SystemID != NULL)
1264             fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1265         if (cur->orig != NULL)
1266             fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1267         if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1268             fprintf(ctxt->output, "\n content \"%s\"",
1269                     (char *) cur->content);
1270         fprintf(ctxt->output, "\n");
1271     }
1272 }
1273 
1274 /**
1275  * xmlCtxtDumpEntities:
1276  * @output:  the FILE * for the output
1277  * @doc:  the document
1278  *
1279  * Dumps debug information for all the entities in use by the document
1280  */
1281 static void
xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1282 xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1283 {
1284     if (doc == NULL) return;
1285     xmlCtxtDumpDocHead(ctxt, doc);
1286     if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1287         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1288             doc->intSubset->entities;
1289 
1290         if (!ctxt->check)
1291             fprintf(ctxt->output, "Entities in internal subset\n");
1292         xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1293                     ctxt);
1294     } else
1295         fprintf(ctxt->output, "No entities in internal subset\n");
1296     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1297         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1298             doc->extSubset->entities;
1299 
1300         if (!ctxt->check)
1301             fprintf(ctxt->output, "Entities in external subset\n");
1302         xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1303                     ctxt);
1304     } else if (!ctxt->check)
1305         fprintf(ctxt->output, "No entities in external subset\n");
1306 }
1307 
1308 /**
1309  * xmlCtxtDumpDTD:
1310  * @output:  the FILE * for the output
1311  * @dtd:  the DTD
1312  *
1313  * Dumps debug information for the DTD
1314  */
1315 static void
xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)1316 xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1317 {
1318     if (dtd == NULL) {
1319         if (!ctxt->check)
1320             fprintf(ctxt->output, "DTD is NULL\n");
1321         return;
1322     }
1323     xmlCtxtDumpDtdNode(ctxt, dtd);
1324     if (dtd->children == NULL)
1325         fprintf(ctxt->output, "    DTD is empty\n");
1326     else {
1327         ctxt->depth++;
1328         xmlCtxtDumpNodeList(ctxt, dtd->children);
1329         ctxt->depth--;
1330     }
1331 }
1332 
1333 /************************************************************************
1334  *									*
1335  *			Public entry points for dump			*
1336  *									*
1337  ************************************************************************/
1338 
1339 /**
1340  * xmlDebugDumpString:
1341  * @output:  the FILE * for the output
1342  * @str:  the string
1343  *
1344  * Dumps informations about the string, shorten it if necessary
1345  */
1346 void
xmlDebugDumpString(FILE * output,const xmlChar * str)1347 xmlDebugDumpString(FILE * output, const xmlChar * str)
1348 {
1349     int i;
1350 
1351     if (output == NULL)
1352 	output = stdout;
1353     if (str == NULL) {
1354         fprintf(output, "(NULL)");
1355         return;
1356     }
1357     for (i = 0; i < 40; i++)
1358         if (str[i] == 0)
1359             return;
1360         else if (IS_BLANK_CH(str[i]))
1361             fputc(' ', output);
1362         else if (str[i] >= 0x80)
1363             fprintf(output, "#%X", str[i]);
1364         else
1365             fputc(str[i], output);
1366     fprintf(output, "...");
1367 }
1368 
1369 /**
1370  * xmlDebugDumpAttr:
1371  * @output:  the FILE * for the output
1372  * @attr:  the attribute
1373  * @depth:  the indentation level.
1374  *
1375  * Dumps debug information for the attribute
1376  */
1377 void
xmlDebugDumpAttr(FILE * output,xmlAttrPtr attr,int depth)1378 xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
1379     xmlDebugCtxt ctxt;
1380 
1381     if (output == NULL) return;
1382     xmlCtxtDumpInitCtxt(&ctxt);
1383     ctxt.output = output;
1384     ctxt.depth = depth;
1385     xmlCtxtDumpAttr(&ctxt, attr);
1386     xmlCtxtDumpCleanCtxt(&ctxt);
1387 }
1388 
1389 
1390 /**
1391  * xmlDebugDumpEntities:
1392  * @output:  the FILE * for the output
1393  * @doc:  the document
1394  *
1395  * Dumps debug information for all the entities in use by the document
1396  */
1397 void
xmlDebugDumpEntities(FILE * output,xmlDocPtr doc)1398 xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1399 {
1400     xmlDebugCtxt ctxt;
1401 
1402     if (output == NULL) return;
1403     xmlCtxtDumpInitCtxt(&ctxt);
1404     ctxt.output = output;
1405     xmlCtxtDumpEntities(&ctxt, doc);
1406     xmlCtxtDumpCleanCtxt(&ctxt);
1407 }
1408 
1409 /**
1410  * xmlDebugDumpAttrList:
1411  * @output:  the FILE * for the output
1412  * @attr:  the attribute list
1413  * @depth:  the indentation level.
1414  *
1415  * Dumps debug information for the attribute list
1416  */
1417 void
xmlDebugDumpAttrList(FILE * output,xmlAttrPtr attr,int depth)1418 xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1419 {
1420     xmlDebugCtxt ctxt;
1421 
1422     if (output == NULL) return;
1423     xmlCtxtDumpInitCtxt(&ctxt);
1424     ctxt.output = output;
1425     ctxt.depth = depth;
1426     xmlCtxtDumpAttrList(&ctxt, attr);
1427     xmlCtxtDumpCleanCtxt(&ctxt);
1428 }
1429 
1430 /**
1431  * xmlDebugDumpOneNode:
1432  * @output:  the FILE * for the output
1433  * @node:  the node
1434  * @depth:  the indentation level.
1435  *
1436  * Dumps debug information for the element node, it is not recursive
1437  */
1438 void
xmlDebugDumpOneNode(FILE * output,xmlNodePtr node,int depth)1439 xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1440 {
1441     xmlDebugCtxt ctxt;
1442 
1443     if (output == NULL) return;
1444     xmlCtxtDumpInitCtxt(&ctxt);
1445     ctxt.output = output;
1446     ctxt.depth = depth;
1447     xmlCtxtDumpOneNode(&ctxt, node);
1448     xmlCtxtDumpCleanCtxt(&ctxt);
1449 }
1450 
1451 /**
1452  * xmlDebugDumpNode:
1453  * @output:  the FILE * for the output
1454  * @node:  the node
1455  * @depth:  the indentation level.
1456  *
1457  * Dumps debug information for the element node, it is recursive
1458  */
1459 void
xmlDebugDumpNode(FILE * output,xmlNodePtr node,int depth)1460 xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1461 {
1462     xmlDebugCtxt ctxt;
1463 
1464     if (output == NULL)
1465 	output = stdout;
1466     xmlCtxtDumpInitCtxt(&ctxt);
1467     ctxt.output = output;
1468     ctxt.depth = depth;
1469     xmlCtxtDumpNode(&ctxt, node);
1470     xmlCtxtDumpCleanCtxt(&ctxt);
1471 }
1472 
1473 /**
1474  * xmlDebugDumpNodeList:
1475  * @output:  the FILE * for the output
1476  * @node:  the node list
1477  * @depth:  the indentation level.
1478  *
1479  * Dumps debug information for the list of element node, it is recursive
1480  */
1481 void
xmlDebugDumpNodeList(FILE * output,xmlNodePtr node,int depth)1482 xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1483 {
1484     xmlDebugCtxt ctxt;
1485 
1486     if (output == NULL)
1487 	output = stdout;
1488     xmlCtxtDumpInitCtxt(&ctxt);
1489     ctxt.output = output;
1490     ctxt.depth = depth;
1491     xmlCtxtDumpNodeList(&ctxt, node);
1492     xmlCtxtDumpCleanCtxt(&ctxt);
1493 }
1494 
1495 /**
1496  * xmlDebugDumpDocumentHead:
1497  * @output:  the FILE * for the output
1498  * @doc:  the document
1499  *
1500  * Dumps debug information cncerning the document, not recursive
1501  */
1502 void
xmlDebugDumpDocumentHead(FILE * output,xmlDocPtr doc)1503 xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1504 {
1505     xmlDebugCtxt ctxt;
1506 
1507     if (output == NULL)
1508 	output = stdout;
1509     xmlCtxtDumpInitCtxt(&ctxt);
1510     ctxt.options |= DUMP_TEXT_TYPE;
1511     ctxt.output = output;
1512     xmlCtxtDumpDocumentHead(&ctxt, doc);
1513     xmlCtxtDumpCleanCtxt(&ctxt);
1514 }
1515 
1516 /**
1517  * xmlDebugDumpDocument:
1518  * @output:  the FILE * for the output
1519  * @doc:  the document
1520  *
1521  * Dumps debug information for the document, it's recursive
1522  */
1523 void
xmlDebugDumpDocument(FILE * output,xmlDocPtr doc)1524 xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1525 {
1526     xmlDebugCtxt ctxt;
1527 
1528     if (output == NULL)
1529 	output = stdout;
1530     xmlCtxtDumpInitCtxt(&ctxt);
1531     ctxt.options |= DUMP_TEXT_TYPE;
1532     ctxt.output = output;
1533     xmlCtxtDumpDocument(&ctxt, doc);
1534     xmlCtxtDumpCleanCtxt(&ctxt);
1535 }
1536 
1537 /**
1538  * xmlDebugDumpDTD:
1539  * @output:  the FILE * for the output
1540  * @dtd:  the DTD
1541  *
1542  * Dumps debug information for the DTD
1543  */
1544 void
xmlDebugDumpDTD(FILE * output,xmlDtdPtr dtd)1545 xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1546 {
1547     xmlDebugCtxt ctxt;
1548 
1549     if (output == NULL)
1550 	output = stdout;
1551     xmlCtxtDumpInitCtxt(&ctxt);
1552     ctxt.options |= DUMP_TEXT_TYPE;
1553     ctxt.output = output;
1554     xmlCtxtDumpDTD(&ctxt, dtd);
1555     xmlCtxtDumpCleanCtxt(&ctxt);
1556 }
1557 
1558 /************************************************************************
1559  *									*
1560  *			Public entry points for checkings		*
1561  *									*
1562  ************************************************************************/
1563 
1564 /**
1565  * xmlDebugCheckDocument:
1566  * @output:  the FILE * for the output
1567  * @doc:  the document
1568  *
1569  * Check the document for potential content problems, and output
1570  * the errors to @output
1571  *
1572  * Returns the number of errors found
1573  */
1574 int
xmlDebugCheckDocument(FILE * output,xmlDocPtr doc)1575 xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1576 {
1577     xmlDebugCtxt ctxt;
1578 
1579     if (output == NULL)
1580 	output = stdout;
1581     xmlCtxtDumpInitCtxt(&ctxt);
1582     ctxt.output = output;
1583     ctxt.check = 1;
1584     xmlCtxtDumpDocument(&ctxt, doc);
1585     xmlCtxtDumpCleanCtxt(&ctxt);
1586     return(ctxt.errors);
1587 }
1588 
1589 /************************************************************************
1590  *									*
1591  *			Helpers for Shell				*
1592  *									*
1593  ************************************************************************/
1594 
1595 /**
1596  * xmlLsCountNode:
1597  * @node:  the node to count
1598  *
1599  * Count the children of @node.
1600  *
1601  * Returns the number of children of @node.
1602  */
1603 int
xmlLsCountNode(xmlNodePtr node)1604 xmlLsCountNode(xmlNodePtr node) {
1605     int ret = 0;
1606     xmlNodePtr list = NULL;
1607 
1608     if (node == NULL)
1609 	return(0);
1610 
1611     switch (node->type) {
1612 	case XML_ELEMENT_NODE:
1613 	    list = node->children;
1614 	    break;
1615 	case XML_DOCUMENT_NODE:
1616 	case XML_HTML_DOCUMENT_NODE:
1617 #ifdef LIBXML_DOCB_ENABLED
1618 	case XML_DOCB_DOCUMENT_NODE:
1619 #endif
1620 	    list = ((xmlDocPtr) node)->children;
1621 	    break;
1622 	case XML_ATTRIBUTE_NODE:
1623 	    list = ((xmlAttrPtr) node)->children;
1624 	    break;
1625 	case XML_TEXT_NODE:
1626 	case XML_CDATA_SECTION_NODE:
1627 	case XML_PI_NODE:
1628 	case XML_COMMENT_NODE:
1629 	    if (node->content != NULL) {
1630 		ret = xmlStrlen(node->content);
1631             }
1632 	    break;
1633 	case XML_ENTITY_REF_NODE:
1634 	case XML_DOCUMENT_TYPE_NODE:
1635 	case XML_ENTITY_NODE:
1636 	case XML_DOCUMENT_FRAG_NODE:
1637 	case XML_NOTATION_NODE:
1638 	case XML_DTD_NODE:
1639         case XML_ELEMENT_DECL:
1640         case XML_ATTRIBUTE_DECL:
1641         case XML_ENTITY_DECL:
1642 	case XML_NAMESPACE_DECL:
1643 	case XML_XINCLUDE_START:
1644 	case XML_XINCLUDE_END:
1645 	    ret = 1;
1646 	    break;
1647     }
1648     for (;list != NULL;ret++)
1649         list = list->next;
1650     return(ret);
1651 }
1652 
1653 /**
1654  * xmlLsOneNode:
1655  * @output:  the FILE * for the output
1656  * @node:  the node to dump
1657  *
1658  * Dump to @output the type and name of @node.
1659  */
1660 void
xmlLsOneNode(FILE * output,xmlNodePtr node)1661 xmlLsOneNode(FILE *output, xmlNodePtr node) {
1662     if (output == NULL) return;
1663     if (node == NULL) {
1664 	fprintf(output, "NULL\n");
1665 	return;
1666     }
1667     switch (node->type) {
1668 	case XML_ELEMENT_NODE:
1669 	    fprintf(output, "-");
1670 	    break;
1671 	case XML_ATTRIBUTE_NODE:
1672 	    fprintf(output, "a");
1673 	    break;
1674 	case XML_TEXT_NODE:
1675 	    fprintf(output, "t");
1676 	    break;
1677 	case XML_CDATA_SECTION_NODE:
1678 	    fprintf(output, "C");
1679 	    break;
1680 	case XML_ENTITY_REF_NODE:
1681 	    fprintf(output, "e");
1682 	    break;
1683 	case XML_ENTITY_NODE:
1684 	    fprintf(output, "E");
1685 	    break;
1686 	case XML_PI_NODE:
1687 	    fprintf(output, "p");
1688 	    break;
1689 	case XML_COMMENT_NODE:
1690 	    fprintf(output, "c");
1691 	    break;
1692 	case XML_DOCUMENT_NODE:
1693 	    fprintf(output, "d");
1694 	    break;
1695 	case XML_HTML_DOCUMENT_NODE:
1696 	    fprintf(output, "h");
1697 	    break;
1698 	case XML_DOCUMENT_TYPE_NODE:
1699 	    fprintf(output, "T");
1700 	    break;
1701 	case XML_DOCUMENT_FRAG_NODE:
1702 	    fprintf(output, "F");
1703 	    break;
1704 	case XML_NOTATION_NODE:
1705 	    fprintf(output, "N");
1706 	    break;
1707 	case XML_NAMESPACE_DECL:
1708 	    fprintf(output, "n");
1709 	    break;
1710 	default:
1711 	    fprintf(output, "?");
1712     }
1713     if (node->type != XML_NAMESPACE_DECL) {
1714 	if (node->properties != NULL)
1715 	    fprintf(output, "a");
1716 	else
1717 	    fprintf(output, "-");
1718 	if (node->nsDef != NULL)
1719 	    fprintf(output, "n");
1720 	else
1721 	    fprintf(output, "-");
1722     }
1723 
1724     fprintf(output, " %8d ", xmlLsCountNode(node));
1725 
1726     switch (node->type) {
1727 	case XML_ELEMENT_NODE:
1728 	    if (node->name != NULL) {
1729                 if ((node->ns != NULL) && (node->ns->prefix != NULL))
1730                     fprintf(output, "%s:", node->ns->prefix);
1731 		fprintf(output, "%s", (const char *) node->name);
1732             }
1733 	    break;
1734 	case XML_ATTRIBUTE_NODE:
1735 	    if (node->name != NULL)
1736 		fprintf(output, "%s", (const char *) node->name);
1737 	    break;
1738 	case XML_TEXT_NODE:
1739 	    if (node->content != NULL) {
1740 		xmlDebugDumpString(output, node->content);
1741             }
1742 	    break;
1743 	case XML_CDATA_SECTION_NODE:
1744 	    break;
1745 	case XML_ENTITY_REF_NODE:
1746 	    if (node->name != NULL)
1747 		fprintf(output, "%s", (const char *) node->name);
1748 	    break;
1749 	case XML_ENTITY_NODE:
1750 	    if (node->name != NULL)
1751 		fprintf(output, "%s", (const char *) node->name);
1752 	    break;
1753 	case XML_PI_NODE:
1754 	    if (node->name != NULL)
1755 		fprintf(output, "%s", (const char *) node->name);
1756 	    break;
1757 	case XML_COMMENT_NODE:
1758 	    break;
1759 	case XML_DOCUMENT_NODE:
1760 	    break;
1761 	case XML_HTML_DOCUMENT_NODE:
1762 	    break;
1763 	case XML_DOCUMENT_TYPE_NODE:
1764 	    break;
1765 	case XML_DOCUMENT_FRAG_NODE:
1766 	    break;
1767 	case XML_NOTATION_NODE:
1768 	    break;
1769 	case XML_NAMESPACE_DECL: {
1770 	    xmlNsPtr ns = (xmlNsPtr) node;
1771 
1772 	    if (ns->prefix == NULL)
1773 		fprintf(output, "default -> %s", (char *)ns->href);
1774 	    else
1775 		fprintf(output, "%s -> %s", (char *)ns->prefix,
1776 			(char *)ns->href);
1777 	    break;
1778 	}
1779 	default:
1780 	    if (node->name != NULL)
1781 		fprintf(output, "%s", (const char *) node->name);
1782     }
1783     fprintf(output, "\n");
1784 }
1785 
1786 /**
1787  * xmlBoolToText:
1788  * @boolval: a bool to turn into text
1789  *
1790  * Convenient way to turn bool into text
1791  *
1792  * Returns a pointer to either "True" or "False"
1793  */
1794 const char *
xmlBoolToText(int boolval)1795 xmlBoolToText(int boolval)
1796 {
1797     if (boolval)
1798         return("True");
1799     else
1800         return("False");
1801 }
1802 
1803 #ifdef LIBXML_XPATH_ENABLED
1804 /****************************************************************
1805  *								*
1806  *		The XML shell related functions			*
1807  *								*
1808  ****************************************************************/
1809 
1810 
1811 
1812 /*
1813  * TODO: Improvement/cleanups for the XML shell
1814  *     - allow to shell out an editor on a subpart
1815  *     - cleanup function registrations (with help) and calling
1816  *     - provide registration routines
1817  */
1818 
1819 /**
1820  * xmlShellPrintXPathError:
1821  * @errorType: valid xpath error id
1822  * @arg: the argument that cause xpath to fail
1823  *
1824  * Print the xpath error to libxml default error channel
1825  */
1826 void
xmlShellPrintXPathError(int errorType,const char * arg)1827 xmlShellPrintXPathError(int errorType, const char *arg)
1828 {
1829     const char *default_arg = "Result";
1830 
1831     if (!arg)
1832         arg = default_arg;
1833 
1834     switch (errorType) {
1835         case XPATH_UNDEFINED:
1836             xmlGenericError(xmlGenericErrorContext,
1837                             "%s: no such node\n", arg);
1838             break;
1839 
1840         case XPATH_BOOLEAN:
1841             xmlGenericError(xmlGenericErrorContext,
1842                             "%s is a Boolean\n", arg);
1843             break;
1844         case XPATH_NUMBER:
1845             xmlGenericError(xmlGenericErrorContext,
1846                             "%s is a number\n", arg);
1847             break;
1848         case XPATH_STRING:
1849             xmlGenericError(xmlGenericErrorContext,
1850                             "%s is a string\n", arg);
1851             break;
1852         case XPATH_POINT:
1853             xmlGenericError(xmlGenericErrorContext,
1854                             "%s is a point\n", arg);
1855             break;
1856         case XPATH_RANGE:
1857             xmlGenericError(xmlGenericErrorContext,
1858                             "%s is a range\n", arg);
1859             break;
1860         case XPATH_LOCATIONSET:
1861             xmlGenericError(xmlGenericErrorContext,
1862                             "%s is a range\n", arg);
1863             break;
1864         case XPATH_USERS:
1865             xmlGenericError(xmlGenericErrorContext,
1866                             "%s is user-defined\n", arg);
1867             break;
1868         case XPATH_XSLT_TREE:
1869             xmlGenericError(xmlGenericErrorContext,
1870                             "%s is an XSLT value tree\n", arg);
1871             break;
1872     }
1873 #if 0
1874     xmlGenericError(xmlGenericErrorContext,
1875                     "Try casting the result string function (xpath builtin)\n",
1876                     arg);
1877 #endif
1878 }
1879 
1880 
1881 #ifdef LIBXML_OUTPUT_ENABLED
1882 /**
1883  * xmlShellPrintNodeCtxt:
1884  * @ctxt : a non-null shell context
1885  * @node : a non-null node to print to the output FILE
1886  *
1887  * Print node to the output FILE
1888  */
1889 static void
xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)1890 xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1891 {
1892     FILE *fp;
1893 
1894     if (!node)
1895         return;
1896     if (ctxt == NULL)
1897 	fp = stdout;
1898     else
1899 	fp = ctxt->output;
1900 
1901     if (node->type == XML_DOCUMENT_NODE)
1902         xmlDocDump(fp, (xmlDocPtr) node);
1903     else if (node->type == XML_ATTRIBUTE_NODE)
1904         xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
1905     else
1906         xmlElemDump(fp, node->doc, node);
1907 
1908     fprintf(fp, "\n");
1909 }
1910 
1911 /**
1912  * xmlShellPrintNode:
1913  * @node : a non-null node to print to the output FILE
1914  *
1915  * Print node to the output FILE
1916  */
1917 void
xmlShellPrintNode(xmlNodePtr node)1918 xmlShellPrintNode(xmlNodePtr node)
1919 {
1920     xmlShellPrintNodeCtxt(NULL, node);
1921 }
1922 #endif /* LIBXML_OUTPUT_ENABLED */
1923 
1924 /**
1925  * xmlShellPrintXPathResultCtxt:
1926  * @ctxt: a valid shell context
1927  * @list: a valid result generated by an xpath evaluation
1928  *
1929  * Prints result to the output FILE
1930  */
1931 static void
xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)1932 xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
1933 {
1934     if (!ctxt)
1935        return;
1936 
1937     if (list != NULL) {
1938         switch (list->type) {
1939             case XPATH_NODESET:{
1940 #ifdef LIBXML_OUTPUT_ENABLED
1941                     int indx;
1942 
1943                     if (list->nodesetval) {
1944                         for (indx = 0; indx < list->nodesetval->nodeNr;
1945                              indx++) {
1946                             xmlShellPrintNodeCtxt(ctxt,
1947 				    list->nodesetval->nodeTab[indx]);
1948                         }
1949                     } else {
1950                         xmlGenericError(xmlGenericErrorContext,
1951                                         "Empty node set\n");
1952                     }
1953                     break;
1954 #else
1955 		    xmlGenericError(xmlGenericErrorContext,
1956 				    "Node set\n");
1957 #endif /* LIBXML_OUTPUT_ENABLED */
1958                 }
1959             case XPATH_BOOLEAN:
1960                 xmlGenericError(xmlGenericErrorContext,
1961                                 "Is a Boolean:%s\n",
1962                                 xmlBoolToText(list->boolval));
1963                 break;
1964             case XPATH_NUMBER:
1965                 xmlGenericError(xmlGenericErrorContext,
1966                                 "Is a number:%0g\n", list->floatval);
1967                 break;
1968             case XPATH_STRING:
1969                 xmlGenericError(xmlGenericErrorContext,
1970                                 "Is a string:%s\n", list->stringval);
1971                 break;
1972 
1973             default:
1974                 xmlShellPrintXPathError(list->type, NULL);
1975         }
1976     }
1977 }
1978 
1979 /**
1980  * xmlShellPrintXPathResult:
1981  * @list: a valid result generated by an xpath evaluation
1982  *
1983  * Prints result to the output FILE
1984  */
1985 void
xmlShellPrintXPathResult(xmlXPathObjectPtr list)1986 xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1987 {
1988     xmlShellPrintXPathResultCtxt(NULL, list);
1989 }
1990 
1991 /**
1992  * xmlShellList:
1993  * @ctxt:  the shell context
1994  * @arg:  unused
1995  * @node:  a node
1996  * @node2:  unused
1997  *
1998  * Implements the XML shell function "ls"
1999  * Does an Unix like listing of the given node (like a directory)
2000  *
2001  * Returns 0
2002  */
2003 int
xmlShellList(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2004 xmlShellList(xmlShellCtxtPtr ctxt,
2005              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2006              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2007 {
2008     xmlNodePtr cur;
2009     if (!ctxt)
2010         return (0);
2011     if (node == NULL) {
2012 	fprintf(ctxt->output, "NULL\n");
2013 	return (0);
2014     }
2015     if ((node->type == XML_DOCUMENT_NODE) ||
2016         (node->type == XML_HTML_DOCUMENT_NODE)) {
2017         cur = ((xmlDocPtr) node)->children;
2018     } else if (node->type == XML_NAMESPACE_DECL) {
2019         xmlLsOneNode(ctxt->output, node);
2020         return (0);
2021     } else if (node->children != NULL) {
2022         cur = node->children;
2023     } else {
2024         xmlLsOneNode(ctxt->output, node);
2025         return (0);
2026     }
2027     while (cur != NULL) {
2028         xmlLsOneNode(ctxt->output, cur);
2029         cur = cur->next;
2030     }
2031     return (0);
2032 }
2033 
2034 /**
2035  * xmlShellBase:
2036  * @ctxt:  the shell context
2037  * @arg:  unused
2038  * @node:  a node
2039  * @node2:  unused
2040  *
2041  * Implements the XML shell function "base"
2042  * dumps the current XML base of the node
2043  *
2044  * Returns 0
2045  */
2046 int
xmlShellBase(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2047 xmlShellBase(xmlShellCtxtPtr ctxt,
2048              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2049              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2050 {
2051     xmlChar *base;
2052     if (!ctxt)
2053         return 0;
2054     if (node == NULL) {
2055 	fprintf(ctxt->output, "NULL\n");
2056 	return (0);
2057     }
2058 
2059     base = xmlNodeGetBase(node->doc, node);
2060 
2061     if (base == NULL) {
2062         fprintf(ctxt->output, " No base found !!!\n");
2063     } else {
2064         fprintf(ctxt->output, "%s\n", base);
2065         xmlFree(base);
2066     }
2067     return (0);
2068 }
2069 
2070 #ifdef LIBXML_TREE_ENABLED
2071 /**
2072  * xmlShellSetBase:
2073  * @ctxt:  the shell context
2074  * @arg:  the new base
2075  * @node:  a node
2076  * @node2:  unused
2077  *
2078  * Implements the XML shell function "setbase"
2079  * change the current XML base of the node
2080  *
2081  * Returns 0
2082  */
2083 static int
xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2084 xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2085              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2086              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2087 {
2088     xmlNodeSetBase(node, (xmlChar*) arg);
2089     return (0);
2090 }
2091 #endif
2092 
2093 #ifdef LIBXML_XPATH_ENABLED
2094 /**
2095  * xmlShellRegisterNamespace:
2096  * @ctxt:  the shell context
2097  * @arg:  a string in prefix=nsuri format
2098  * @node:  unused
2099  * @node2:  unused
2100  *
2101  * Implements the XML shell function "setns"
2102  * register/unregister a prefix=namespace pair
2103  * on the XPath context
2104  *
2105  * Returns 0 on success and a negative value otherwise.
2106  */
2107 static int
xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt,char * arg,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2108 xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
2109       xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2110 {
2111     xmlChar* nsListDup;
2112     xmlChar* prefix;
2113     xmlChar* href;
2114     xmlChar* next;
2115 
2116     nsListDup = xmlStrdup((xmlChar *) arg);
2117     next = nsListDup;
2118     while(next != NULL) {
2119 	/* skip spaces */
2120 	/*while((*next) == ' ') next++;*/
2121 	if((*next) == '\0') break;
2122 
2123 	/* find prefix */
2124 	prefix = next;
2125 	next = (xmlChar*)xmlStrchr(next, '=');
2126 	if(next == NULL) {
2127 	    fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
2128 	    xmlFree(nsListDup);
2129 	    return(-1);
2130 	}
2131 	*(next++) = '\0';
2132 
2133 	/* find href */
2134 	href = next;
2135 	next = (xmlChar*)xmlStrchr(next, ' ');
2136 	if(next != NULL) {
2137 	    *(next++) = '\0';
2138 	}
2139 
2140 	/* do register namespace */
2141 	if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
2142 	    fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
2143 	    xmlFree(nsListDup);
2144 	    return(-1);
2145 	}
2146     }
2147 
2148     xmlFree(nsListDup);
2149     return(0);
2150 }
2151 /**
2152  * xmlShellRegisterRootNamespaces:
2153  * @ctxt:  the shell context
2154  * @arg:  unused
2155  * @node:  the root element
2156  * @node2:  unused
2157  *
2158  * Implements the XML shell function "setrootns"
2159  * which registers all namespaces declarations found on the root element.
2160  *
2161  * Returns 0 on success and a negative value otherwise.
2162  */
2163 static int
xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr root,xmlNodePtr node2 ATTRIBUTE_UNUSED)2164 xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2165       xmlNodePtr root, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2166 {
2167     xmlNsPtr ns;
2168 
2169     if ((root == NULL) || (root->type != XML_ELEMENT_NODE) ||
2170         (root->nsDef == NULL) || (ctxt == NULL) || (ctxt->pctxt == NULL))
2171 	return(-1);
2172     ns = root->nsDef;
2173     while (ns != NULL) {
2174         if (ns->prefix == NULL)
2175 	    xmlXPathRegisterNs(ctxt->pctxt, BAD_CAST "defaultns", ns->href);
2176 	else
2177 	    xmlXPathRegisterNs(ctxt->pctxt, ns->prefix, ns->href);
2178         ns = ns->next;
2179     }
2180     return(0);
2181 }
2182 #endif
2183 
2184 /**
2185  * xmlShellGrep:
2186  * @ctxt:  the shell context
2187  * @arg:  the string or regular expression to find
2188  * @node:  a node
2189  * @node2:  unused
2190  *
2191  * Implements the XML shell function "grep"
2192  * dumps informations about the node (namespace, attributes, content).
2193  *
2194  * Returns 0
2195  */
2196 static int
xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2197 xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2198             char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2199 {
2200     if (!ctxt)
2201         return (0);
2202     if (node == NULL)
2203 	return (0);
2204     if (arg == NULL)
2205 	return (0);
2206 #ifdef LIBXML_REGEXP_ENABLED
2207     if ((xmlStrchr((xmlChar *) arg, '?')) ||
2208 	(xmlStrchr((xmlChar *) arg, '*')) ||
2209 	(xmlStrchr((xmlChar *) arg, '.')) ||
2210 	(xmlStrchr((xmlChar *) arg, '['))) {
2211     }
2212 #endif
2213     while (node != NULL) {
2214         if (node->type == XML_COMMENT_NODE) {
2215 	    if (xmlStrstr(node->content, (xmlChar *) arg)) {
2216 
2217 		fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
2218                 xmlShellList(ctxt, NULL, node, NULL);
2219 	    }
2220         } else if (node->type == XML_TEXT_NODE) {
2221 	    if (xmlStrstr(node->content, (xmlChar *) arg)) {
2222 
2223 		fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
2224                 xmlShellList(ctxt, NULL, node->parent, NULL);
2225 	    }
2226         }
2227 
2228         /*
2229          * Browse the full subtree, deep first
2230          */
2231 
2232         if ((node->type == XML_DOCUMENT_NODE) ||
2233             (node->type == XML_HTML_DOCUMENT_NODE)) {
2234             node = ((xmlDocPtr) node)->children;
2235         } else if ((node->children != NULL)
2236                    && (node->type != XML_ENTITY_REF_NODE)) {
2237             /* deep first */
2238             node = node->children;
2239         } else if (node->next != NULL) {
2240             /* then siblings */
2241             node = node->next;
2242         } else {
2243             /* go up to parents->next if needed */
2244             while (node != NULL) {
2245                 if (node->parent != NULL) {
2246                     node = node->parent;
2247                 }
2248                 if (node->next != NULL) {
2249                     node = node->next;
2250                     break;
2251                 }
2252                 if (node->parent == NULL) {
2253                     node = NULL;
2254                     break;
2255                 }
2256             }
2257 	}
2258     }
2259     return (0);
2260 }
2261 
2262 /**
2263  * xmlShellDir:
2264  * @ctxt:  the shell context
2265  * @arg:  unused
2266  * @node:  a node
2267  * @node2:  unused
2268  *
2269  * Implements the XML shell function "dir"
2270  * dumps informations about the node (namespace, attributes, content).
2271  *
2272  * Returns 0
2273  */
2274 int
xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2275 xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2276             char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2277             xmlNodePtr node2 ATTRIBUTE_UNUSED)
2278 {
2279     if (!ctxt)
2280         return (0);
2281     if (node == NULL) {
2282 	fprintf(ctxt->output, "NULL\n");
2283 	return (0);
2284     }
2285     if ((node->type == XML_DOCUMENT_NODE) ||
2286         (node->type == XML_HTML_DOCUMENT_NODE)) {
2287         xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
2288     } else if (node->type == XML_ATTRIBUTE_NODE) {
2289         xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
2290     } else {
2291         xmlDebugDumpOneNode(ctxt->output, node, 0);
2292     }
2293     return (0);
2294 }
2295 
2296 /**
2297  * xmlShellSetContent:
2298  * @ctxt:  the shell context
2299  * @value:  the content as a string
2300  * @node:  a node
2301  * @node2:  unused
2302  *
2303  * Implements the XML shell function "dir"
2304  * dumps informations about the node (namespace, attributes, content).
2305  *
2306  * Returns 0
2307  */
2308 static int
xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * value,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2309 xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2310             char *value, xmlNodePtr node,
2311             xmlNodePtr node2 ATTRIBUTE_UNUSED)
2312 {
2313     xmlNodePtr results;
2314     xmlParserErrors ret;
2315 
2316     if (!ctxt)
2317         return (0);
2318     if (node == NULL) {
2319 	fprintf(ctxt->output, "NULL\n");
2320 	return (0);
2321     }
2322     if (value == NULL) {
2323         fprintf(ctxt->output, "NULL\n");
2324 	return (0);
2325     }
2326 
2327     ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
2328     if (ret == XML_ERR_OK) {
2329 	if (node->children != NULL) {
2330 	    xmlFreeNodeList(node->children);
2331 	    node->children = NULL;
2332 	    node->last = NULL;
2333 	}
2334 	xmlAddChildList(node, results);
2335     } else {
2336         fprintf(ctxt->output, "failed to parse content\n");
2337     }
2338     return (0);
2339 }
2340 
2341 #ifdef LIBXML_SCHEMAS_ENABLED
2342 /**
2343  * xmlShellRNGValidate:
2344  * @ctxt:  the shell context
2345  * @schemas:  the path to the Relax-NG schemas
2346  * @node:  a node
2347  * @node2:  unused
2348  *
2349  * Implements the XML shell function "relaxng"
2350  * validating the instance against a Relax-NG schemas
2351  *
2352  * Returns 0
2353  */
2354 static int
xmlShellRNGValidate(xmlShellCtxtPtr sctxt,char * schemas,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2355 xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2356             xmlNodePtr node ATTRIBUTE_UNUSED,
2357 	    xmlNodePtr node2 ATTRIBUTE_UNUSED)
2358 {
2359     xmlRelaxNGPtr relaxngschemas;
2360     xmlRelaxNGParserCtxtPtr ctxt;
2361     xmlRelaxNGValidCtxtPtr vctxt;
2362     int ret;
2363 
2364     ctxt = xmlRelaxNGNewParserCtxt(schemas);
2365     xmlRelaxNGSetParserErrors(ctxt,
2366 	    (xmlRelaxNGValidityErrorFunc) fprintf,
2367 	    (xmlRelaxNGValidityWarningFunc) fprintf,
2368 	    stderr);
2369     relaxngschemas = xmlRelaxNGParse(ctxt);
2370     xmlRelaxNGFreeParserCtxt(ctxt);
2371     if (relaxngschemas == NULL) {
2372 	xmlGenericError(xmlGenericErrorContext,
2373 		"Relax-NG schema %s failed to compile\n", schemas);
2374 	return(-1);
2375     }
2376     vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2377     xmlRelaxNGSetValidErrors(vctxt,
2378 	    (xmlRelaxNGValidityErrorFunc) fprintf,
2379 	    (xmlRelaxNGValidityWarningFunc) fprintf,
2380 	    stderr);
2381     ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2382     if (ret == 0) {
2383 	fprintf(stderr, "%s validates\n", sctxt->filename);
2384     } else if (ret > 0) {
2385 	fprintf(stderr, "%s fails to validate\n", sctxt->filename);
2386     } else {
2387 	fprintf(stderr, "%s validation generated an internal error\n",
2388 	       sctxt->filename);
2389     }
2390     xmlRelaxNGFreeValidCtxt(vctxt);
2391     if (relaxngschemas != NULL)
2392 	xmlRelaxNGFree(relaxngschemas);
2393     return(0);
2394 }
2395 #endif
2396 
2397 #ifdef LIBXML_OUTPUT_ENABLED
2398 /**
2399  * xmlShellCat:
2400  * @ctxt:  the shell context
2401  * @arg:  unused
2402  * @node:  a node
2403  * @node2:  unused
2404  *
2405  * Implements the XML shell function "cat"
2406  * dumps the serialization node content (XML or HTML).
2407  *
2408  * Returns 0
2409  */
2410 int
xmlShellCat(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2411 xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2412             xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2413 {
2414     if (!ctxt)
2415         return (0);
2416     if (node == NULL) {
2417 	fprintf(ctxt->output, "NULL\n");
2418 	return (0);
2419     }
2420     if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2421 #ifdef LIBXML_HTML_ENABLED
2422         if (node->type == XML_HTML_DOCUMENT_NODE)
2423             htmlDocDump(ctxt->output, (htmlDocPtr) node);
2424         else
2425             htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
2426 #else
2427         if (node->type == XML_DOCUMENT_NODE)
2428             xmlDocDump(ctxt->output, (xmlDocPtr) node);
2429         else
2430             xmlElemDump(ctxt->output, ctxt->doc, node);
2431 #endif /* LIBXML_HTML_ENABLED */
2432     } else {
2433         if (node->type == XML_DOCUMENT_NODE)
2434             xmlDocDump(ctxt->output, (xmlDocPtr) node);
2435         else
2436             xmlElemDump(ctxt->output, ctxt->doc, node);
2437     }
2438     fprintf(ctxt->output, "\n");
2439     return (0);
2440 }
2441 #endif /* LIBXML_OUTPUT_ENABLED */
2442 
2443 /**
2444  * xmlShellLoad:
2445  * @ctxt:  the shell context
2446  * @filename:  the file name
2447  * @node:  unused
2448  * @node2:  unused
2449  *
2450  * Implements the XML shell function "load"
2451  * loads a new document specified by the filename
2452  *
2453  * Returns 0 or -1 if loading failed
2454  */
2455 int
xmlShellLoad(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2456 xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2457              xmlNodePtr node ATTRIBUTE_UNUSED,
2458              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2459 {
2460     xmlDocPtr doc;
2461     int html = 0;
2462 
2463     if ((ctxt == NULL) || (filename == NULL)) return(-1);
2464     if (ctxt->doc != NULL)
2465         html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
2466 
2467     if (html) {
2468 #ifdef LIBXML_HTML_ENABLED
2469         doc = htmlParseFile(filename, NULL);
2470 #else
2471         fprintf(ctxt->output, "HTML support not compiled in\n");
2472         doc = NULL;
2473 #endif /* LIBXML_HTML_ENABLED */
2474     } else {
2475         doc = xmlReadFile(filename,NULL,0);
2476     }
2477     if (doc != NULL) {
2478         if (ctxt->loaded == 1) {
2479             xmlFreeDoc(ctxt->doc);
2480         }
2481         ctxt->loaded = 1;
2482 #ifdef LIBXML_XPATH_ENABLED
2483         xmlXPathFreeContext(ctxt->pctxt);
2484 #endif /* LIBXML_XPATH_ENABLED */
2485         xmlFree(ctxt->filename);
2486         ctxt->doc = doc;
2487         ctxt->node = (xmlNodePtr) doc;
2488 #ifdef LIBXML_XPATH_ENABLED
2489         ctxt->pctxt = xmlXPathNewContext(doc);
2490 #endif /* LIBXML_XPATH_ENABLED */
2491         ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
2492     } else
2493         return (-1);
2494     return (0);
2495 }
2496 
2497 #ifdef LIBXML_OUTPUT_ENABLED
2498 /**
2499  * xmlShellWrite:
2500  * @ctxt:  the shell context
2501  * @filename:  the file name
2502  * @node:  a node in the tree
2503  * @node2:  unused
2504  *
2505  * Implements the XML shell function "write"
2506  * Write the current node to the filename, it saves the serialization
2507  * of the subtree under the @node specified
2508  *
2509  * Returns 0 or -1 in case of error
2510  */
2511 int
xmlShellWrite(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2512 xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
2513               xmlNodePtr node2 ATTRIBUTE_UNUSED)
2514 {
2515     if (node == NULL)
2516         return (-1);
2517     if ((filename == NULL) || (filename[0] == 0)) {
2518         return (-1);
2519     }
2520 #ifdef W_OK
2521     if (access((char *) filename, W_OK)) {
2522         xmlGenericError(xmlGenericErrorContext,
2523                         "Cannot write to %s\n", filename);
2524         return (-1);
2525     }
2526 #endif
2527     switch (node->type) {
2528         case XML_DOCUMENT_NODE:
2529             if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2530                 xmlGenericError(xmlGenericErrorContext,
2531                                 "Failed to write to %s\n", filename);
2532                 return (-1);
2533             }
2534             break;
2535         case XML_HTML_DOCUMENT_NODE:
2536 #ifdef LIBXML_HTML_ENABLED
2537             if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2538                 xmlGenericError(xmlGenericErrorContext,
2539                                 "Failed to write to %s\n", filename);
2540                 return (-1);
2541             }
2542 #else
2543             if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2544                 xmlGenericError(xmlGenericErrorContext,
2545                                 "Failed to write to %s\n", filename);
2546                 return (-1);
2547             }
2548 #endif /* LIBXML_HTML_ENABLED */
2549             break;
2550         default:{
2551                 FILE *f;
2552 
2553                 f = fopen((char *) filename, "w");
2554                 if (f == NULL) {
2555                     xmlGenericError(xmlGenericErrorContext,
2556                                     "Failed to write to %s\n", filename);
2557                     return (-1);
2558                 }
2559                 xmlElemDump(f, ctxt->doc, node);
2560                 fclose(f);
2561             }
2562     }
2563     return (0);
2564 }
2565 
2566 /**
2567  * xmlShellSave:
2568  * @ctxt:  the shell context
2569  * @filename:  the file name (optional)
2570  * @node:  unused
2571  * @node2:  unused
2572  *
2573  * Implements the XML shell function "save"
2574  * Write the current document to the filename, or it's original name
2575  *
2576  * Returns 0 or -1 in case of error
2577  */
2578 int
xmlShellSave(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2579 xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2580              xmlNodePtr node ATTRIBUTE_UNUSED,
2581              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2582 {
2583     if ((ctxt == NULL) || (ctxt->doc == NULL))
2584         return (-1);
2585     if ((filename == NULL) || (filename[0] == 0))
2586         filename = ctxt->filename;
2587     if (filename == NULL)
2588         return (-1);
2589 #ifdef W_OK
2590     if (access((char *) filename, W_OK)) {
2591         xmlGenericError(xmlGenericErrorContext,
2592                         "Cannot save to %s\n", filename);
2593         return (-1);
2594     }
2595 #endif
2596     switch (ctxt->doc->type) {
2597         case XML_DOCUMENT_NODE:
2598             if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2599                 xmlGenericError(xmlGenericErrorContext,
2600                                 "Failed to save to %s\n", filename);
2601             }
2602             break;
2603         case XML_HTML_DOCUMENT_NODE:
2604 #ifdef LIBXML_HTML_ENABLED
2605             if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2606                 xmlGenericError(xmlGenericErrorContext,
2607                                 "Failed to save to %s\n", filename);
2608             }
2609 #else
2610             if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2611                 xmlGenericError(xmlGenericErrorContext,
2612                                 "Failed to save to %s\n", filename);
2613             }
2614 #endif /* LIBXML_HTML_ENABLED */
2615             break;
2616         default:
2617             xmlGenericError(xmlGenericErrorContext,
2618 	    "To save to subparts of a document use the 'write' command\n");
2619             return (-1);
2620 
2621     }
2622     return (0);
2623 }
2624 #endif /* LIBXML_OUTPUT_ENABLED */
2625 
2626 #ifdef LIBXML_VALID_ENABLED
2627 /**
2628  * xmlShellValidate:
2629  * @ctxt:  the shell context
2630  * @dtd:  the DTD URI (optional)
2631  * @node:  unused
2632  * @node2:  unused
2633  *
2634  * Implements the XML shell function "validate"
2635  * Validate the document, if a DTD path is provided, then the validation
2636  * is done against the given DTD.
2637  *
2638  * Returns 0 or -1 in case of error
2639  */
2640 int
xmlShellValidate(xmlShellCtxtPtr ctxt,char * dtd,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2641 xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2642                  xmlNodePtr node ATTRIBUTE_UNUSED,
2643                  xmlNodePtr node2 ATTRIBUTE_UNUSED)
2644 {
2645     xmlValidCtxt vctxt;
2646     int res = -1;
2647 
2648     if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1);
2649     vctxt.userData = stderr;
2650     vctxt.error = (xmlValidityErrorFunc) fprintf;
2651     vctxt.warning = (xmlValidityWarningFunc) fprintf;
2652 
2653     if ((dtd == NULL) || (dtd[0] == 0)) {
2654         res = xmlValidateDocument(&vctxt, ctxt->doc);
2655     } else {
2656         xmlDtdPtr subset;
2657 
2658         subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2659         if (subset != NULL) {
2660             res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2661 
2662             xmlFreeDtd(subset);
2663         }
2664     }
2665     return (res);
2666 }
2667 #endif /* LIBXML_VALID_ENABLED */
2668 
2669 /**
2670  * xmlShellDu:
2671  * @ctxt:  the shell context
2672  * @arg:  unused
2673  * @tree:  a node defining a subtree
2674  * @node2:  unused
2675  *
2676  * Implements the XML shell function "du"
2677  * show the structure of the subtree under node @tree
2678  * If @tree is null, the command works on the current node.
2679  *
2680  * Returns 0 or -1 in case of error
2681  */
2682 int
xmlShellDu(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr tree,xmlNodePtr node2 ATTRIBUTE_UNUSED)2683 xmlShellDu(xmlShellCtxtPtr ctxt,
2684            char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2685            xmlNodePtr node2 ATTRIBUTE_UNUSED)
2686 {
2687     xmlNodePtr node;
2688     int indent = 0, i;
2689 
2690     if (!ctxt)
2691 	return (-1);
2692 
2693     if (tree == NULL)
2694         return (-1);
2695     node = tree;
2696     while (node != NULL) {
2697         if ((node->type == XML_DOCUMENT_NODE) ||
2698             (node->type == XML_HTML_DOCUMENT_NODE)) {
2699             fprintf(ctxt->output, "/\n");
2700         } else if (node->type == XML_ELEMENT_NODE) {
2701             for (i = 0; i < indent; i++)
2702                 fprintf(ctxt->output, "  ");
2703             if ((node->ns) && (node->ns->prefix))
2704                 fprintf(ctxt->output, "%s:", node->ns->prefix);
2705             fprintf(ctxt->output, "%s\n", node->name);
2706         } else {
2707         }
2708 
2709         /*
2710          * Browse the full subtree, deep first
2711          */
2712 
2713         if ((node->type == XML_DOCUMENT_NODE) ||
2714             (node->type == XML_HTML_DOCUMENT_NODE)) {
2715             node = ((xmlDocPtr) node)->children;
2716         } else if ((node->children != NULL)
2717                    && (node->type != XML_ENTITY_REF_NODE)) {
2718             /* deep first */
2719             node = node->children;
2720             indent++;
2721         } else if ((node != tree) && (node->next != NULL)) {
2722             /* then siblings */
2723             node = node->next;
2724         } else if (node != tree) {
2725             /* go up to parents->next if needed */
2726             while (node != tree) {
2727                 if (node->parent != NULL) {
2728                     node = node->parent;
2729                     indent--;
2730                 }
2731                 if ((node != tree) && (node->next != NULL)) {
2732                     node = node->next;
2733                     break;
2734                 }
2735                 if (node->parent == NULL) {
2736                     node = NULL;
2737                     break;
2738                 }
2739                 if (node == tree) {
2740                     node = NULL;
2741                     break;
2742                 }
2743             }
2744             /* exit condition */
2745             if (node == tree)
2746                 node = NULL;
2747         } else
2748             node = NULL;
2749     }
2750     return (0);
2751 }
2752 
2753 /**
2754  * xmlShellPwd:
2755  * @ctxt:  the shell context
2756  * @buffer:  the output buffer
2757  * @node:  a node
2758  * @node2:  unused
2759  *
2760  * Implements the XML shell function "pwd"
2761  * Show the full path from the root to the node, if needed building
2762  * thumblers when similar elements exists at a given ancestor level.
2763  * The output is compatible with XPath commands.
2764  *
2765  * Returns 0 or -1 in case of error
2766  */
2767 int
xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * buffer,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2768 xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2769             xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2770 {
2771     xmlChar *path;
2772 
2773     if ((node == NULL) || (buffer == NULL))
2774         return (-1);
2775 
2776     path = xmlGetNodePath(node);
2777     if (path == NULL)
2778 	return (-1);
2779 
2780     /*
2781      * This test prevents buffer overflow, because this routine
2782      * is only called by xmlShell, in which the second argument is
2783      * 500 chars long.
2784      * It is a dirty hack before a cleaner solution is found.
2785      * Documentation should mention that the second argument must
2786      * be at least 500 chars long, and could be stripped if too long.
2787      */
2788     snprintf(buffer, 499, "%s", path);
2789     buffer[499] = '0';
2790     xmlFree(path);
2791 
2792     return (0);
2793 }
2794 
2795 /**
2796  * xmlShell:
2797  * @doc:  the initial document
2798  * @filename:  the output buffer
2799  * @input:  the line reading function
2800  * @output:  the output FILE*, defaults to stdout if NULL
2801  *
2802  * Implements the XML shell
2803  * This allow to load, validate, view, modify and save a document
2804  * using a environment similar to a UNIX commandline.
2805  */
2806 void
xmlShell(xmlDocPtr doc,char * filename,xmlShellReadlineFunc input,FILE * output)2807 xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
2808          FILE * output)
2809 {
2810     char prompt[500] = "/ > ";
2811     char *cmdline = NULL, *cur;
2812     char command[100];
2813     char arg[400];
2814     int i;
2815     xmlShellCtxtPtr ctxt;
2816     xmlXPathObjectPtr list;
2817 
2818     if (doc == NULL)
2819         return;
2820     if (filename == NULL)
2821         return;
2822     if (input == NULL)
2823         return;
2824     if (output == NULL)
2825         output = stdout;
2826     ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
2827     if (ctxt == NULL)
2828         return;
2829     ctxt->loaded = 0;
2830     ctxt->doc = doc;
2831     ctxt->input = input;
2832     ctxt->output = output;
2833     ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
2834     ctxt->node = (xmlNodePtr) ctxt->doc;
2835 
2836 #ifdef LIBXML_XPATH_ENABLED
2837     ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2838     if (ctxt->pctxt == NULL) {
2839         xmlFree(ctxt);
2840         return;
2841     }
2842 #endif /* LIBXML_XPATH_ENABLED */
2843     while (1) {
2844         if (ctxt->node == (xmlNodePtr) ctxt->doc)
2845             snprintf(prompt, sizeof(prompt), "%s > ", "/");
2846         else if ((ctxt->node != NULL) && (ctxt->node->name) &&
2847                  (ctxt->node->ns) && (ctxt->node->ns->prefix))
2848             snprintf(prompt, sizeof(prompt), "%s:%s > ",
2849                      (ctxt->node->ns->prefix), ctxt->node->name);
2850         else if ((ctxt->node != NULL) && (ctxt->node->name))
2851             snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
2852         else
2853             snprintf(prompt, sizeof(prompt), "? > ");
2854         prompt[sizeof(prompt) - 1] = 0;
2855 
2856         /*
2857          * Get a new command line
2858          */
2859         cmdline = ctxt->input(prompt);
2860         if (cmdline == NULL)
2861             break;
2862 
2863         /*
2864          * Parse the command itself
2865          */
2866         cur = cmdline;
2867         while ((*cur == ' ') || (*cur == '\t'))
2868             cur++;
2869         i = 0;
2870         while ((*cur != ' ') && (*cur != '\t') &&
2871                (*cur != '\n') && (*cur != '\r')) {
2872             if (*cur == 0)
2873                 break;
2874             command[i++] = *cur++;
2875         }
2876         command[i] = 0;
2877         if (i == 0)
2878             continue;
2879 
2880         /*
2881          * Parse the argument
2882          */
2883         while ((*cur == ' ') || (*cur == '\t'))
2884             cur++;
2885         i = 0;
2886         while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2887             if (*cur == 0)
2888                 break;
2889             arg[i++] = *cur++;
2890         }
2891         arg[i] = 0;
2892 
2893         /*
2894          * start interpreting the command
2895          */
2896         if (!strcmp(command, "exit"))
2897             break;
2898         if (!strcmp(command, "quit"))
2899             break;
2900         if (!strcmp(command, "bye"))
2901             break;
2902 		if (!strcmp(command, "help")) {
2903 		  fprintf(ctxt->output, "\tbase         display XML base of the node\n");
2904 		  fprintf(ctxt->output, "\tsetbase URI  change the XML base of the node\n");
2905 		  fprintf(ctxt->output, "\tbye          leave shell\n");
2906 		  fprintf(ctxt->output, "\tcat [node]   display node or current node\n");
2907 		  fprintf(ctxt->output, "\tcd [path]    change directory to path or to root\n");
2908 		  fprintf(ctxt->output, "\tdir [path]   dumps informations about the node (namespace, attributes, content)\n");
2909 		  fprintf(ctxt->output, "\tdu [path]    show the structure of the subtree under path or the current node\n");
2910 		  fprintf(ctxt->output, "\texit         leave shell\n");
2911 		  fprintf(ctxt->output, "\thelp         display this help\n");
2912 		  fprintf(ctxt->output, "\tfree         display memory usage\n");
2913 		  fprintf(ctxt->output, "\tload [name]  load a new document with name\n");
2914 		  fprintf(ctxt->output, "\tls [path]    list contents of path or the current directory\n");
2915 		  fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n");
2916 #ifdef LIBXML_XPATH_ENABLED
2917 		  fprintf(ctxt->output, "\txpath expr   evaluate the XPath expression in that context and print the result\n");
2918 		  fprintf(ctxt->output, "\tsetns nsreg  register a namespace to a prefix in the XPath evaluation context\n");
2919 		  fprintf(ctxt->output, "\t             format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
2920 		  fprintf(ctxt->output, "\tsetrootns    register all namespace found on the root element\n");
2921 		  fprintf(ctxt->output, "\t             the default namespace if any uses 'defaultns' prefix\n");
2922 #endif /* LIBXML_XPATH_ENABLED */
2923 		  fprintf(ctxt->output, "\tpwd          display current working directory\n");
2924 		  fprintf(ctxt->output, "\twhereis      display absolute path of [path] or current working directory\n");
2925 		  fprintf(ctxt->output, "\tquit         leave shell\n");
2926 #ifdef LIBXML_OUTPUT_ENABLED
2927 		  fprintf(ctxt->output, "\tsave [name]  save this document to name or the original name\n");
2928 		  fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
2929 #endif /* LIBXML_OUTPUT_ENABLED */
2930 #ifdef LIBXML_VALID_ENABLED
2931 		  fprintf(ctxt->output, "\tvalidate     check the document for errors\n");
2932 #endif /* LIBXML_VALID_ENABLED */
2933 #ifdef LIBXML_SCHEMAS_ENABLED
2934 		  fprintf(ctxt->output, "\trelaxng rng  validate the document agaisnt the Relax-NG schemas\n");
2935 #endif
2936 		  fprintf(ctxt->output, "\tgrep string  search for a string in the subtree\n");
2937 #ifdef LIBXML_VALID_ENABLED
2938         } else if (!strcmp(command, "validate")) {
2939             xmlShellValidate(ctxt, arg, NULL, NULL);
2940 #endif /* LIBXML_VALID_ENABLED */
2941         } else if (!strcmp(command, "load")) {
2942             xmlShellLoad(ctxt, arg, NULL, NULL);
2943 #ifdef LIBXML_SCHEMAS_ENABLED
2944         } else if (!strcmp(command, "relaxng")) {
2945             xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2946 #endif
2947 #ifdef LIBXML_OUTPUT_ENABLED
2948         } else if (!strcmp(command, "save")) {
2949             xmlShellSave(ctxt, arg, NULL, NULL);
2950         } else if (!strcmp(command, "write")) {
2951 	    if (arg[0] == 0)
2952 		xmlGenericError(xmlGenericErrorContext,
2953                         "Write command requires a filename argument\n");
2954 	    else
2955 		xmlShellWrite(ctxt, arg, ctxt->node, NULL);
2956 #endif /* LIBXML_OUTPUT_ENABLED */
2957         } else if (!strcmp(command, "grep")) {
2958             xmlShellGrep(ctxt, arg, ctxt->node, NULL);
2959         } else if (!strcmp(command, "free")) {
2960             if (arg[0] == 0) {
2961                 xmlMemShow(ctxt->output, 0);
2962             } else {
2963                 int len = 0;
2964 
2965                 sscanf(arg, "%d", &len);
2966                 xmlMemShow(ctxt->output, len);
2967             }
2968         } else if (!strcmp(command, "pwd")) {
2969             char dir[500];
2970 
2971             if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
2972                 fprintf(ctxt->output, "%s\n", dir);
2973         } else if (!strcmp(command, "du")) {
2974             if (arg[0] == 0) {
2975                 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2976             } else {
2977                 ctxt->pctxt->node = ctxt->node;
2978 #ifdef LIBXML_XPATH_ENABLED
2979                 ctxt->pctxt->node = ctxt->node;
2980                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2981 #else
2982                 list = NULL;
2983 #endif /* LIBXML_XPATH_ENABLED */
2984                 if (list != NULL) {
2985                     switch (list->type) {
2986                         case XPATH_UNDEFINED:
2987                             xmlGenericError(xmlGenericErrorContext,
2988                                             "%s: no such node\n", arg);
2989                             break;
2990                         case XPATH_NODESET:{
2991                             int indx;
2992 
2993                             if (list->nodesetval == NULL)
2994                                 break;
2995 
2996                             for (indx = 0;
2997                                  indx < list->nodesetval->nodeNr;
2998                                  indx++)
2999                                 xmlShellDu(ctxt, NULL,
3000                                            list->nodesetval->
3001                                            nodeTab[indx], NULL);
3002                             break;
3003                         }
3004                         case XPATH_BOOLEAN:
3005                             xmlGenericError(xmlGenericErrorContext,
3006                                             "%s is a Boolean\n", arg);
3007                             break;
3008                         case XPATH_NUMBER:
3009                             xmlGenericError(xmlGenericErrorContext,
3010                                             "%s is a number\n", arg);
3011                             break;
3012                         case XPATH_STRING:
3013                             xmlGenericError(xmlGenericErrorContext,
3014                                             "%s is a string\n", arg);
3015                             break;
3016                         case XPATH_POINT:
3017                             xmlGenericError(xmlGenericErrorContext,
3018                                             "%s is a point\n", arg);
3019                             break;
3020                         case XPATH_RANGE:
3021                             xmlGenericError(xmlGenericErrorContext,
3022                                             "%s is a range\n", arg);
3023                             break;
3024                         case XPATH_LOCATIONSET:
3025                             xmlGenericError(xmlGenericErrorContext,
3026                                             "%s is a range\n", arg);
3027                             break;
3028                         case XPATH_USERS:
3029                             xmlGenericError(xmlGenericErrorContext,
3030                                             "%s is user-defined\n", arg);
3031                             break;
3032                         case XPATH_XSLT_TREE:
3033                             xmlGenericError(xmlGenericErrorContext,
3034                                             "%s is an XSLT value tree\n",
3035                                             arg);
3036                             break;
3037                     }
3038 #ifdef LIBXML_XPATH_ENABLED
3039                     xmlXPathFreeObject(list);
3040 #endif
3041                 } else {
3042                     xmlGenericError(xmlGenericErrorContext,
3043                                     "%s: no such node\n", arg);
3044                 }
3045                 ctxt->pctxt->node = NULL;
3046             }
3047         } else if (!strcmp(command, "base")) {
3048             xmlShellBase(ctxt, NULL, ctxt->node, NULL);
3049         } else if (!strcmp(command, "set")) {
3050 	    xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
3051 #ifdef LIBXML_XPATH_ENABLED
3052         } else if (!strcmp(command, "setns")) {
3053             if (arg[0] == 0) {
3054 		xmlGenericError(xmlGenericErrorContext,
3055 				"setns: prefix=[nsuri] required\n");
3056             } else {
3057                 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
3058             }
3059         } else if (!strcmp(command, "setrootns")) {
3060 	    xmlNodePtr root;
3061 
3062 	    root = xmlDocGetRootElement(ctxt->doc);
3063 	    xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL);
3064         } else if (!strcmp(command, "xpath")) {
3065             if (arg[0] == 0) {
3066 		xmlGenericError(xmlGenericErrorContext,
3067 				"xpath: expression required\n");
3068 	    } else {
3069                 ctxt->pctxt->node = ctxt->node;
3070                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3071 		xmlXPathDebugDumpObject(ctxt->output, list, 0);
3072 		xmlXPathFreeObject(list);
3073 	    }
3074 #endif /* LIBXML_XPATH_ENABLED */
3075 #ifdef LIBXML_TREE_ENABLED
3076         } else if (!strcmp(command, "setbase")) {
3077             xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
3078 #endif
3079         } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
3080             int dir = (!strcmp(command, "dir"));
3081 
3082             if (arg[0] == 0) {
3083                 if (dir)
3084                     xmlShellDir(ctxt, NULL, ctxt->node, NULL);
3085                 else
3086                     xmlShellList(ctxt, NULL, ctxt->node, NULL);
3087             } else {
3088                 ctxt->pctxt->node = ctxt->node;
3089 #ifdef LIBXML_XPATH_ENABLED
3090                 ctxt->pctxt->node = ctxt->node;
3091                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3092 #else
3093                 list = NULL;
3094 #endif /* LIBXML_XPATH_ENABLED */
3095                 if (list != NULL) {
3096                     switch (list->type) {
3097                         case XPATH_UNDEFINED:
3098                             xmlGenericError(xmlGenericErrorContext,
3099                                             "%s: no such node\n", arg);
3100                             break;
3101                         case XPATH_NODESET:{
3102                                 int indx;
3103 
3104 				if (list->nodesetval == NULL)
3105 				    break;
3106 
3107                                 for (indx = 0;
3108                                      indx < list->nodesetval->nodeNr;
3109                                      indx++) {
3110                                     if (dir)
3111                                         xmlShellDir(ctxt, NULL,
3112                                                     list->nodesetval->
3113                                                     nodeTab[indx], NULL);
3114                                     else
3115                                         xmlShellList(ctxt, NULL,
3116                                                      list->nodesetval->
3117                                                      nodeTab[indx], NULL);
3118                                 }
3119                                 break;
3120                             }
3121                         case XPATH_BOOLEAN:
3122                             xmlGenericError(xmlGenericErrorContext,
3123                                             "%s is a Boolean\n", arg);
3124                             break;
3125                         case XPATH_NUMBER:
3126                             xmlGenericError(xmlGenericErrorContext,
3127                                             "%s is a number\n", arg);
3128                             break;
3129                         case XPATH_STRING:
3130                             xmlGenericError(xmlGenericErrorContext,
3131                                             "%s is a string\n", arg);
3132                             break;
3133                         case XPATH_POINT:
3134                             xmlGenericError(xmlGenericErrorContext,
3135                                             "%s is a point\n", arg);
3136                             break;
3137                         case XPATH_RANGE:
3138                             xmlGenericError(xmlGenericErrorContext,
3139                                             "%s is a range\n", arg);
3140                             break;
3141                         case XPATH_LOCATIONSET:
3142                             xmlGenericError(xmlGenericErrorContext,
3143                                             "%s is a range\n", arg);
3144                             break;
3145                         case XPATH_USERS:
3146                             xmlGenericError(xmlGenericErrorContext,
3147                                             "%s is user-defined\n", arg);
3148                             break;
3149                         case XPATH_XSLT_TREE:
3150                             xmlGenericError(xmlGenericErrorContext,
3151                                             "%s is an XSLT value tree\n",
3152                                             arg);
3153                             break;
3154                     }
3155 #ifdef LIBXML_XPATH_ENABLED
3156                     xmlXPathFreeObject(list);
3157 #endif
3158                 } else {
3159                     xmlGenericError(xmlGenericErrorContext,
3160                                     "%s: no such node\n", arg);
3161                 }
3162                 ctxt->pctxt->node = NULL;
3163             }
3164         } else if (!strcmp(command, "whereis")) {
3165             char dir[500];
3166 
3167             if (arg[0] == 0) {
3168                 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
3169                     fprintf(ctxt->output, "%s\n", dir);
3170             } else {
3171                 ctxt->pctxt->node = ctxt->node;
3172 #ifdef LIBXML_XPATH_ENABLED
3173                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3174 #else
3175                 list = NULL;
3176 #endif /* LIBXML_XPATH_ENABLED */
3177                 if (list != NULL) {
3178                     switch (list->type) {
3179                         case XPATH_UNDEFINED:
3180                             xmlGenericError(xmlGenericErrorContext,
3181                                             "%s: no such node\n", arg);
3182                             break;
3183                         case XPATH_NODESET:{
3184                                 int indx;
3185 
3186 				if (list->nodesetval == NULL)
3187 				    break;
3188 
3189                                 for (indx = 0;
3190                                      indx < list->nodesetval->nodeNr;
3191                                      indx++) {
3192                                     if (!xmlShellPwd(ctxt, dir, list->nodesetval->
3193                                                      nodeTab[indx], NULL))
3194                                         fprintf(ctxt->output, "%s\n", dir);
3195                                 }
3196                                 break;
3197                             }
3198                         case XPATH_BOOLEAN:
3199                             xmlGenericError(xmlGenericErrorContext,
3200                                             "%s is a Boolean\n", arg);
3201                             break;
3202                         case XPATH_NUMBER:
3203                             xmlGenericError(xmlGenericErrorContext,
3204                                             "%s is a number\n", arg);
3205                             break;
3206                         case XPATH_STRING:
3207                             xmlGenericError(xmlGenericErrorContext,
3208                                             "%s is a string\n", arg);
3209                             break;
3210                         case XPATH_POINT:
3211                             xmlGenericError(xmlGenericErrorContext,
3212                                             "%s is a point\n", arg);
3213                             break;
3214                         case XPATH_RANGE:
3215                             xmlGenericError(xmlGenericErrorContext,
3216                                             "%s is a range\n", arg);
3217                             break;
3218                         case XPATH_LOCATIONSET:
3219                             xmlGenericError(xmlGenericErrorContext,
3220                                             "%s is a range\n", arg);
3221                             break;
3222                         case XPATH_USERS:
3223                             xmlGenericError(xmlGenericErrorContext,
3224                                             "%s is user-defined\n", arg);
3225                             break;
3226                         case XPATH_XSLT_TREE:
3227                             xmlGenericError(xmlGenericErrorContext,
3228                                             "%s is an XSLT value tree\n",
3229                                             arg);
3230                             break;
3231                     }
3232 #ifdef LIBXML_XPATH_ENABLED
3233                     xmlXPathFreeObject(list);
3234 #endif
3235                 } else {
3236                     xmlGenericError(xmlGenericErrorContext,
3237                                     "%s: no such node\n", arg);
3238                 }
3239                 ctxt->pctxt->node = NULL;
3240             }
3241         } else if (!strcmp(command, "cd")) {
3242             if (arg[0] == 0) {
3243                 ctxt->node = (xmlNodePtr) ctxt->doc;
3244             } else {
3245 #ifdef LIBXML_XPATH_ENABLED
3246                 int l;
3247 
3248                 ctxt->pctxt->node = ctxt->node;
3249 		l = strlen(arg);
3250 		if ((l >= 2) && (arg[l - 1] == '/'))
3251 		    arg[l - 1] = 0;
3252                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3253 #else
3254                 list = NULL;
3255 #endif /* LIBXML_XPATH_ENABLED */
3256                 if (list != NULL) {
3257                     switch (list->type) {
3258                         case XPATH_UNDEFINED:
3259                             xmlGenericError(xmlGenericErrorContext,
3260                                             "%s: no such node\n", arg);
3261                             break;
3262                         case XPATH_NODESET:
3263                             if (list->nodesetval != NULL) {
3264 				if (list->nodesetval->nodeNr == 1) {
3265 				    ctxt->node = list->nodesetval->nodeTab[0];
3266 				    if ((ctxt->node != NULL) &&
3267 				        (ctxt->node->type ==
3268 					 XML_NAMESPACE_DECL)) {
3269 					xmlGenericError(xmlGenericErrorContext,
3270 						    "cannot cd to namespace\n");
3271 					ctxt->node = NULL;
3272 				    }
3273 				} else
3274 				    xmlGenericError(xmlGenericErrorContext,
3275 						    "%s is a %d Node Set\n",
3276 						    arg,
3277 						    list->nodesetval->nodeNr);
3278                             } else
3279                                 xmlGenericError(xmlGenericErrorContext,
3280                                                 "%s is an empty Node Set\n",
3281                                                 arg);
3282                             break;
3283                         case XPATH_BOOLEAN:
3284                             xmlGenericError(xmlGenericErrorContext,
3285                                             "%s is a Boolean\n", arg);
3286                             break;
3287                         case XPATH_NUMBER:
3288                             xmlGenericError(xmlGenericErrorContext,
3289                                             "%s is a number\n", arg);
3290                             break;
3291                         case XPATH_STRING:
3292                             xmlGenericError(xmlGenericErrorContext,
3293                                             "%s is a string\n", arg);
3294                             break;
3295                         case XPATH_POINT:
3296                             xmlGenericError(xmlGenericErrorContext,
3297                                             "%s is a point\n", arg);
3298                             break;
3299                         case XPATH_RANGE:
3300                             xmlGenericError(xmlGenericErrorContext,
3301                                             "%s is a range\n", arg);
3302                             break;
3303                         case XPATH_LOCATIONSET:
3304                             xmlGenericError(xmlGenericErrorContext,
3305                                             "%s is a range\n", arg);
3306                             break;
3307                         case XPATH_USERS:
3308                             xmlGenericError(xmlGenericErrorContext,
3309                                             "%s is user-defined\n", arg);
3310                             break;
3311                         case XPATH_XSLT_TREE:
3312                             xmlGenericError(xmlGenericErrorContext,
3313                                             "%s is an XSLT value tree\n",
3314                                             arg);
3315                             break;
3316                     }
3317 #ifdef LIBXML_XPATH_ENABLED
3318                     xmlXPathFreeObject(list);
3319 #endif
3320                 } else {
3321                     xmlGenericError(xmlGenericErrorContext,
3322                                     "%s: no such node\n", arg);
3323                 }
3324                 ctxt->pctxt->node = NULL;
3325             }
3326 #ifdef LIBXML_OUTPUT_ENABLED
3327         } else if (!strcmp(command, "cat")) {
3328             if (arg[0] == 0) {
3329                 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
3330             } else {
3331                 ctxt->pctxt->node = ctxt->node;
3332 #ifdef LIBXML_XPATH_ENABLED
3333                 ctxt->pctxt->node = ctxt->node;
3334                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3335 #else
3336                 list = NULL;
3337 #endif /* LIBXML_XPATH_ENABLED */
3338                 if (list != NULL) {
3339                     switch (list->type) {
3340                         case XPATH_UNDEFINED:
3341                             xmlGenericError(xmlGenericErrorContext,
3342                                             "%s: no such node\n", arg);
3343                             break;
3344                         case XPATH_NODESET:{
3345                                 int indx;
3346 
3347 				if (list->nodesetval == NULL)
3348 				    break;
3349 
3350                                 for (indx = 0;
3351                                      indx < list->nodesetval->nodeNr;
3352                                      indx++) {
3353                                     if (i > 0)
3354                                         fprintf(ctxt->output, " -------\n");
3355                                     xmlShellCat(ctxt, NULL,
3356                                                 list->nodesetval->
3357                                                 nodeTab[indx], NULL);
3358                                 }
3359                                 break;
3360                             }
3361                         case XPATH_BOOLEAN:
3362                             xmlGenericError(xmlGenericErrorContext,
3363                                             "%s is a Boolean\n", arg);
3364                             break;
3365                         case XPATH_NUMBER:
3366                             xmlGenericError(xmlGenericErrorContext,
3367                                             "%s is a number\n", arg);
3368                             break;
3369                         case XPATH_STRING:
3370                             xmlGenericError(xmlGenericErrorContext,
3371                                             "%s is a string\n", arg);
3372                             break;
3373                         case XPATH_POINT:
3374                             xmlGenericError(xmlGenericErrorContext,
3375                                             "%s is a point\n", arg);
3376                             break;
3377                         case XPATH_RANGE:
3378                             xmlGenericError(xmlGenericErrorContext,
3379                                             "%s is a range\n", arg);
3380                             break;
3381                         case XPATH_LOCATIONSET:
3382                             xmlGenericError(xmlGenericErrorContext,
3383                                             "%s is a range\n", arg);
3384                             break;
3385                         case XPATH_USERS:
3386                             xmlGenericError(xmlGenericErrorContext,
3387                                             "%s is user-defined\n", arg);
3388                             break;
3389                         case XPATH_XSLT_TREE:
3390                             xmlGenericError(xmlGenericErrorContext,
3391                                             "%s is an XSLT value tree\n",
3392                                             arg);
3393                             break;
3394                     }
3395 #ifdef LIBXML_XPATH_ENABLED
3396                     xmlXPathFreeObject(list);
3397 #endif
3398                 } else {
3399                     xmlGenericError(xmlGenericErrorContext,
3400                                     "%s: no such node\n", arg);
3401                 }
3402                 ctxt->pctxt->node = NULL;
3403             }
3404 #endif /* LIBXML_OUTPUT_ENABLED */
3405         } else {
3406             xmlGenericError(xmlGenericErrorContext,
3407                             "Unknown command %s\n", command);
3408         }
3409         free(cmdline);          /* not xmlFree here ! */
3410 	cmdline = NULL;
3411     }
3412 #ifdef LIBXML_XPATH_ENABLED
3413     xmlXPathFreeContext(ctxt->pctxt);
3414 #endif /* LIBXML_XPATH_ENABLED */
3415     if (ctxt->loaded) {
3416         xmlFreeDoc(ctxt->doc);
3417     }
3418     if (ctxt->filename != NULL)
3419         xmlFree(ctxt->filename);
3420     xmlFree(ctxt);
3421     if (cmdline != NULL)
3422         free(cmdline);          /* not xmlFree here ! */
3423 }
3424 
3425 #endif /* LIBXML_XPATH_ENABLED */
3426 #define bottom_debugXML
3427 #include "elfgcchack.h"
3428 #endif /* LIBXML_DEBUG_ENABLED */
3429