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 dictionary */
48     int check;                  /* do just checkings */
49     int errors;                 /* number of errors found */
50     int nodict;			/* if the document has no dictionary */
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 LIBXML_ATTR_FORMAT(3,0)
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 LIBXML_ATTR_FORMAT(3,0)
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 dictionary 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 dictionary '%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             /* deactivated 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 dictionary\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 concerning 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(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)1232 xmlCtxtDumpEntityCallback(void *payload, void *data,
1233                           const xmlChar *name ATTRIBUTE_UNUSED)
1234 {
1235     xmlEntityPtr cur = (xmlEntityPtr) payload;
1236     xmlDebugCtxtPtr ctxt = (xmlDebugCtxtPtr) data;
1237     if (cur == NULL) {
1238         if (!ctxt->check)
1239             fprintf(ctxt->output, "Entity is NULL");
1240         return;
1241     }
1242     if (!ctxt->check) {
1243         fprintf(ctxt->output, "%s : ", (char *) cur->name);
1244         switch (cur->etype) {
1245             case XML_INTERNAL_GENERAL_ENTITY:
1246                 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1247                 break;
1248             case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1249                 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1250                 break;
1251             case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1252                 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1253                 break;
1254             case XML_INTERNAL_PARAMETER_ENTITY:
1255                 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1256                 break;
1257             case XML_EXTERNAL_PARAMETER_ENTITY:
1258                 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1259                 break;
1260             default:
1261 		xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1262 			     "Unknown entity type %d\n", cur->etype);
1263         }
1264         if (cur->ExternalID != NULL)
1265             fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1266         if (cur->SystemID != NULL)
1267             fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1268         if (cur->orig != NULL)
1269             fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1270         if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1271             fprintf(ctxt->output, "\n content \"%s\"",
1272                     (char *) cur->content);
1273         fprintf(ctxt->output, "\n");
1274     }
1275 }
1276 
1277 /**
1278  * xmlCtxtDumpEntities:
1279  * @output:  the FILE * for the output
1280  * @doc:  the document
1281  *
1282  * Dumps debug information for all the entities in use by the document
1283  */
1284 static void
xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1285 xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1286 {
1287     if (doc == NULL) return;
1288     xmlCtxtDumpDocHead(ctxt, doc);
1289     if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1290         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1291             doc->intSubset->entities;
1292 
1293         if (!ctxt->check)
1294             fprintf(ctxt->output, "Entities in internal subset\n");
1295         xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1296     } else
1297         fprintf(ctxt->output, "No entities in internal subset\n");
1298     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1299         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1300             doc->extSubset->entities;
1301 
1302         if (!ctxt->check)
1303             fprintf(ctxt->output, "Entities in external subset\n");
1304         xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1305     } else if (!ctxt->check)
1306         fprintf(ctxt->output, "No entities in external subset\n");
1307 }
1308 
1309 /**
1310  * xmlCtxtDumpDTD:
1311  * @output:  the FILE * for the output
1312  * @dtd:  the DTD
1313  *
1314  * Dumps debug information for the DTD
1315  */
1316 static void
xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)1317 xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1318 {
1319     if (dtd == NULL) {
1320         if (!ctxt->check)
1321             fprintf(ctxt->output, "DTD is NULL\n");
1322         return;
1323     }
1324     xmlCtxtDumpDtdNode(ctxt, dtd);
1325     if (dtd->children == NULL)
1326         fprintf(ctxt->output, "    DTD is empty\n");
1327     else {
1328         ctxt->depth++;
1329         xmlCtxtDumpNodeList(ctxt, dtd->children);
1330         ctxt->depth--;
1331     }
1332 }
1333 
1334 /************************************************************************
1335  *									*
1336  *			Public entry points for dump			*
1337  *									*
1338  ************************************************************************/
1339 
1340 /**
1341  * xmlDebugDumpString:
1342  * @output:  the FILE * for the output
1343  * @str:  the string
1344  *
1345  * Dumps information about the string, shorten it if necessary
1346  */
1347 void
xmlDebugDumpString(FILE * output,const xmlChar * str)1348 xmlDebugDumpString(FILE * output, const xmlChar * str)
1349 {
1350     int i;
1351 
1352     if (output == NULL)
1353 	output = stdout;
1354     if (str == NULL) {
1355         fprintf(output, "(NULL)");
1356         return;
1357     }
1358     for (i = 0; i < 40; i++)
1359         if (str[i] == 0)
1360             return;
1361         else if (IS_BLANK_CH(str[i]))
1362             fputc(' ', output);
1363         else if (str[i] >= 0x80)
1364             fprintf(output, "#%X", str[i]);
1365         else
1366             fputc(str[i], output);
1367     fprintf(output, "...");
1368 }
1369 
1370 /**
1371  * xmlDebugDumpAttr:
1372  * @output:  the FILE * for the output
1373  * @attr:  the attribute
1374  * @depth:  the indentation level.
1375  *
1376  * Dumps debug information for the attribute
1377  */
1378 void
xmlDebugDumpAttr(FILE * output,xmlAttrPtr attr,int depth)1379 xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
1380     xmlDebugCtxt ctxt;
1381 
1382     if (output == NULL) return;
1383     xmlCtxtDumpInitCtxt(&ctxt);
1384     ctxt.output = output;
1385     ctxt.depth = depth;
1386     xmlCtxtDumpAttr(&ctxt, attr);
1387     xmlCtxtDumpCleanCtxt(&ctxt);
1388 }
1389 
1390 
1391 /**
1392  * xmlDebugDumpEntities:
1393  * @output:  the FILE * for the output
1394  * @doc:  the document
1395  *
1396  * Dumps debug information for all the entities in use by the document
1397  */
1398 void
xmlDebugDumpEntities(FILE * output,xmlDocPtr doc)1399 xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1400 {
1401     xmlDebugCtxt ctxt;
1402 
1403     if (output == NULL) return;
1404     xmlCtxtDumpInitCtxt(&ctxt);
1405     ctxt.output = output;
1406     xmlCtxtDumpEntities(&ctxt, doc);
1407     xmlCtxtDumpCleanCtxt(&ctxt);
1408 }
1409 
1410 /**
1411  * xmlDebugDumpAttrList:
1412  * @output:  the FILE * for the output
1413  * @attr:  the attribute list
1414  * @depth:  the indentation level.
1415  *
1416  * Dumps debug information for the attribute list
1417  */
1418 void
xmlDebugDumpAttrList(FILE * output,xmlAttrPtr attr,int depth)1419 xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1420 {
1421     xmlDebugCtxt ctxt;
1422 
1423     if (output == NULL) return;
1424     xmlCtxtDumpInitCtxt(&ctxt);
1425     ctxt.output = output;
1426     ctxt.depth = depth;
1427     xmlCtxtDumpAttrList(&ctxt, attr);
1428     xmlCtxtDumpCleanCtxt(&ctxt);
1429 }
1430 
1431 /**
1432  * xmlDebugDumpOneNode:
1433  * @output:  the FILE * for the output
1434  * @node:  the node
1435  * @depth:  the indentation level.
1436  *
1437  * Dumps debug information for the element node, it is not recursive
1438  */
1439 void
xmlDebugDumpOneNode(FILE * output,xmlNodePtr node,int depth)1440 xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1441 {
1442     xmlDebugCtxt ctxt;
1443 
1444     if (output == NULL) return;
1445     xmlCtxtDumpInitCtxt(&ctxt);
1446     ctxt.output = output;
1447     ctxt.depth = depth;
1448     xmlCtxtDumpOneNode(&ctxt, node);
1449     xmlCtxtDumpCleanCtxt(&ctxt);
1450 }
1451 
1452 /**
1453  * xmlDebugDumpNode:
1454  * @output:  the FILE * for the output
1455  * @node:  the node
1456  * @depth:  the indentation level.
1457  *
1458  * Dumps debug information for the element node, it is recursive
1459  */
1460 void
xmlDebugDumpNode(FILE * output,xmlNodePtr node,int depth)1461 xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1462 {
1463     xmlDebugCtxt ctxt;
1464 
1465     if (output == NULL)
1466 	output = stdout;
1467     xmlCtxtDumpInitCtxt(&ctxt);
1468     ctxt.output = output;
1469     ctxt.depth = depth;
1470     xmlCtxtDumpNode(&ctxt, node);
1471     xmlCtxtDumpCleanCtxt(&ctxt);
1472 }
1473 
1474 /**
1475  * xmlDebugDumpNodeList:
1476  * @output:  the FILE * for the output
1477  * @node:  the node list
1478  * @depth:  the indentation level.
1479  *
1480  * Dumps debug information for the list of element node, it is recursive
1481  */
1482 void
xmlDebugDumpNodeList(FILE * output,xmlNodePtr node,int depth)1483 xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1484 {
1485     xmlDebugCtxt ctxt;
1486 
1487     if (output == NULL)
1488 	output = stdout;
1489     xmlCtxtDumpInitCtxt(&ctxt);
1490     ctxt.output = output;
1491     ctxt.depth = depth;
1492     xmlCtxtDumpNodeList(&ctxt, node);
1493     xmlCtxtDumpCleanCtxt(&ctxt);
1494 }
1495 
1496 /**
1497  * xmlDebugDumpDocumentHead:
1498  * @output:  the FILE * for the output
1499  * @doc:  the document
1500  *
1501  * Dumps debug information concerning the document, not recursive
1502  */
1503 void
xmlDebugDumpDocumentHead(FILE * output,xmlDocPtr doc)1504 xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1505 {
1506     xmlDebugCtxt ctxt;
1507 
1508     if (output == NULL)
1509 	output = stdout;
1510     xmlCtxtDumpInitCtxt(&ctxt);
1511     ctxt.options |= DUMP_TEXT_TYPE;
1512     ctxt.output = output;
1513     xmlCtxtDumpDocumentHead(&ctxt, doc);
1514     xmlCtxtDumpCleanCtxt(&ctxt);
1515 }
1516 
1517 /**
1518  * xmlDebugDumpDocument:
1519  * @output:  the FILE * for the output
1520  * @doc:  the document
1521  *
1522  * Dumps debug information for the document, it's recursive
1523  */
1524 void
xmlDebugDumpDocument(FILE * output,xmlDocPtr doc)1525 xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1526 {
1527     xmlDebugCtxt ctxt;
1528 
1529     if (output == NULL)
1530 	output = stdout;
1531     xmlCtxtDumpInitCtxt(&ctxt);
1532     ctxt.options |= DUMP_TEXT_TYPE;
1533     ctxt.output = output;
1534     xmlCtxtDumpDocument(&ctxt, doc);
1535     xmlCtxtDumpCleanCtxt(&ctxt);
1536 }
1537 
1538 /**
1539  * xmlDebugDumpDTD:
1540  * @output:  the FILE * for the output
1541  * @dtd:  the DTD
1542  *
1543  * Dumps debug information for the DTD
1544  */
1545 void
xmlDebugDumpDTD(FILE * output,xmlDtdPtr dtd)1546 xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1547 {
1548     xmlDebugCtxt ctxt;
1549 
1550     if (output == NULL)
1551 	output = stdout;
1552     xmlCtxtDumpInitCtxt(&ctxt);
1553     ctxt.options |= DUMP_TEXT_TYPE;
1554     ctxt.output = output;
1555     xmlCtxtDumpDTD(&ctxt, dtd);
1556     xmlCtxtDumpCleanCtxt(&ctxt);
1557 }
1558 
1559 /************************************************************************
1560  *									*
1561  *			Public entry points for checkings		*
1562  *									*
1563  ************************************************************************/
1564 
1565 /**
1566  * xmlDebugCheckDocument:
1567  * @output:  the FILE * for the output
1568  * @doc:  the document
1569  *
1570  * Check the document for potential content problems, and output
1571  * the errors to @output
1572  *
1573  * Returns the number of errors found
1574  */
1575 int
xmlDebugCheckDocument(FILE * output,xmlDocPtr doc)1576 xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1577 {
1578     xmlDebugCtxt ctxt;
1579 
1580     if (output == NULL)
1581 	output = stdout;
1582     xmlCtxtDumpInitCtxt(&ctxt);
1583     ctxt.output = output;
1584     ctxt.check = 1;
1585     xmlCtxtDumpDocument(&ctxt, doc);
1586     xmlCtxtDumpCleanCtxt(&ctxt);
1587     return(ctxt.errors);
1588 }
1589 
1590 /************************************************************************
1591  *									*
1592  *			Helpers for Shell				*
1593  *									*
1594  ************************************************************************/
1595 
1596 /**
1597  * xmlLsCountNode:
1598  * @node:  the node to count
1599  *
1600  * Count the children of @node.
1601  *
1602  * Returns the number of children of @node.
1603  */
1604 int
xmlLsCountNode(xmlNodePtr node)1605 xmlLsCountNode(xmlNodePtr node) {
1606     int ret = 0;
1607     xmlNodePtr list = NULL;
1608 
1609     if (node == NULL)
1610 	return(0);
1611 
1612     switch (node->type) {
1613 	case XML_ELEMENT_NODE:
1614 	    list = node->children;
1615 	    break;
1616 	case XML_DOCUMENT_NODE:
1617 	case XML_HTML_DOCUMENT_NODE:
1618 #ifdef LIBXML_DOCB_ENABLED
1619 	case XML_DOCB_DOCUMENT_NODE:
1620 #endif
1621 	    list = ((xmlDocPtr) node)->children;
1622 	    break;
1623 	case XML_ATTRIBUTE_NODE:
1624 	    list = ((xmlAttrPtr) node)->children;
1625 	    break;
1626 	case XML_TEXT_NODE:
1627 	case XML_CDATA_SECTION_NODE:
1628 	case XML_PI_NODE:
1629 	case XML_COMMENT_NODE:
1630 	    if (node->content != NULL) {
1631 		ret = xmlStrlen(node->content);
1632             }
1633 	    break;
1634 	case XML_ENTITY_REF_NODE:
1635 	case XML_DOCUMENT_TYPE_NODE:
1636 	case XML_ENTITY_NODE:
1637 	case XML_DOCUMENT_FRAG_NODE:
1638 	case XML_NOTATION_NODE:
1639 	case XML_DTD_NODE:
1640         case XML_ELEMENT_DECL:
1641         case XML_ATTRIBUTE_DECL:
1642         case XML_ENTITY_DECL:
1643 	case XML_NAMESPACE_DECL:
1644 	case XML_XINCLUDE_START:
1645 	case XML_XINCLUDE_END:
1646 	    ret = 1;
1647 	    break;
1648     }
1649     for (;list != NULL;ret++)
1650         list = list->next;
1651     return(ret);
1652 }
1653 
1654 /**
1655  * xmlLsOneNode:
1656  * @output:  the FILE * for the output
1657  * @node:  the node to dump
1658  *
1659  * Dump to @output the type and name of @node.
1660  */
1661 void
xmlLsOneNode(FILE * output,xmlNodePtr node)1662 xmlLsOneNode(FILE *output, xmlNodePtr node) {
1663     if (output == NULL) return;
1664     if (node == NULL) {
1665 	fprintf(output, "NULL\n");
1666 	return;
1667     }
1668     switch (node->type) {
1669 	case XML_ELEMENT_NODE:
1670 	    fprintf(output, "-");
1671 	    break;
1672 	case XML_ATTRIBUTE_NODE:
1673 	    fprintf(output, "a");
1674 	    break;
1675 	case XML_TEXT_NODE:
1676 	    fprintf(output, "t");
1677 	    break;
1678 	case XML_CDATA_SECTION_NODE:
1679 	    fprintf(output, "C");
1680 	    break;
1681 	case XML_ENTITY_REF_NODE:
1682 	    fprintf(output, "e");
1683 	    break;
1684 	case XML_ENTITY_NODE:
1685 	    fprintf(output, "E");
1686 	    break;
1687 	case XML_PI_NODE:
1688 	    fprintf(output, "p");
1689 	    break;
1690 	case XML_COMMENT_NODE:
1691 	    fprintf(output, "c");
1692 	    break;
1693 	case XML_DOCUMENT_NODE:
1694 	    fprintf(output, "d");
1695 	    break;
1696 	case XML_HTML_DOCUMENT_NODE:
1697 	    fprintf(output, "h");
1698 	    break;
1699 	case XML_DOCUMENT_TYPE_NODE:
1700 	    fprintf(output, "T");
1701 	    break;
1702 	case XML_DOCUMENT_FRAG_NODE:
1703 	    fprintf(output, "F");
1704 	    break;
1705 	case XML_NOTATION_NODE:
1706 	    fprintf(output, "N");
1707 	    break;
1708 	case XML_NAMESPACE_DECL:
1709 	    fprintf(output, "n");
1710 	    break;
1711 	default:
1712 	    fprintf(output, "?");
1713     }
1714     if (node->type != XML_NAMESPACE_DECL) {
1715 	if (node->properties != NULL)
1716 	    fprintf(output, "a");
1717 	else
1718 	    fprintf(output, "-");
1719 	if (node->nsDef != NULL)
1720 	    fprintf(output, "n");
1721 	else
1722 	    fprintf(output, "-");
1723     }
1724 
1725     fprintf(output, " %8d ", xmlLsCountNode(node));
1726 
1727     switch (node->type) {
1728 	case XML_ELEMENT_NODE:
1729 	    if (node->name != NULL) {
1730                 if ((node->ns != NULL) && (node->ns->prefix != NULL))
1731                     fprintf(output, "%s:", node->ns->prefix);
1732 		fprintf(output, "%s", (const char *) node->name);
1733             }
1734 	    break;
1735 	case XML_ATTRIBUTE_NODE:
1736 	    if (node->name != NULL)
1737 		fprintf(output, "%s", (const char *) node->name);
1738 	    break;
1739 	case XML_TEXT_NODE:
1740 	    if (node->content != NULL) {
1741 		xmlDebugDumpString(output, node->content);
1742             }
1743 	    break;
1744 	case XML_CDATA_SECTION_NODE:
1745 	    break;
1746 	case XML_ENTITY_REF_NODE:
1747 	    if (node->name != NULL)
1748 		fprintf(output, "%s", (const char *) node->name);
1749 	    break;
1750 	case XML_ENTITY_NODE:
1751 	    if (node->name != NULL)
1752 		fprintf(output, "%s", (const char *) node->name);
1753 	    break;
1754 	case XML_PI_NODE:
1755 	    if (node->name != NULL)
1756 		fprintf(output, "%s", (const char *) node->name);
1757 	    break;
1758 	case XML_COMMENT_NODE:
1759 	    break;
1760 	case XML_DOCUMENT_NODE:
1761 	    break;
1762 	case XML_HTML_DOCUMENT_NODE:
1763 	    break;
1764 	case XML_DOCUMENT_TYPE_NODE:
1765 	    break;
1766 	case XML_DOCUMENT_FRAG_NODE:
1767 	    break;
1768 	case XML_NOTATION_NODE:
1769 	    break;
1770 	case XML_NAMESPACE_DECL: {
1771 	    xmlNsPtr ns = (xmlNsPtr) node;
1772 
1773 	    if (ns->prefix == NULL)
1774 		fprintf(output, "default -> %s", (char *)ns->href);
1775 	    else
1776 		fprintf(output, "%s -> %s", (char *)ns->prefix,
1777 			(char *)ns->href);
1778 	    break;
1779 	}
1780 	default:
1781 	    if (node->name != NULL)
1782 		fprintf(output, "%s", (const char *) node->name);
1783     }
1784     fprintf(output, "\n");
1785 }
1786 
1787 /**
1788  * xmlBoolToText:
1789  * @boolval: a bool to turn into text
1790  *
1791  * Convenient way to turn bool into text
1792  *
1793  * Returns a pointer to either "True" or "False"
1794  */
1795 const char *
xmlBoolToText(int boolval)1796 xmlBoolToText(int boolval)
1797 {
1798     if (boolval)
1799         return("True");
1800     else
1801         return("False");
1802 }
1803 
1804 #ifdef LIBXML_XPATH_ENABLED
1805 /****************************************************************
1806  *								*
1807  *		The XML shell related functions			*
1808  *								*
1809  ****************************************************************/
1810 
1811 
1812 
1813 /*
1814  * TODO: Improvement/cleanups for the XML shell
1815  *     - allow to shell out an editor on a subpart
1816  *     - cleanup function registrations (with help) and calling
1817  *     - provide registration routines
1818  */
1819 
1820 /**
1821  * xmlShellPrintXPathError:
1822  * @errorType: valid xpath error id
1823  * @arg: the argument that cause xpath to fail
1824  *
1825  * Print the xpath error to libxml default error channel
1826  */
1827 void
xmlShellPrintXPathError(int errorType,const char * arg)1828 xmlShellPrintXPathError(int errorType, const char *arg)
1829 {
1830     const char *default_arg = "Result";
1831 
1832     if (!arg)
1833         arg = default_arg;
1834 
1835     switch (errorType) {
1836         case XPATH_UNDEFINED:
1837             xmlGenericError(xmlGenericErrorContext,
1838                             "%s: no such node\n", arg);
1839             break;
1840 
1841         case XPATH_BOOLEAN:
1842             xmlGenericError(xmlGenericErrorContext,
1843                             "%s is a Boolean\n", arg);
1844             break;
1845         case XPATH_NUMBER:
1846             xmlGenericError(xmlGenericErrorContext,
1847                             "%s is a number\n", arg);
1848             break;
1849         case XPATH_STRING:
1850             xmlGenericError(xmlGenericErrorContext,
1851                             "%s is a string\n", arg);
1852             break;
1853         case XPATH_POINT:
1854             xmlGenericError(xmlGenericErrorContext,
1855                             "%s is a point\n", arg);
1856             break;
1857         case XPATH_RANGE:
1858             xmlGenericError(xmlGenericErrorContext,
1859                             "%s is a range\n", arg);
1860             break;
1861         case XPATH_LOCATIONSET:
1862             xmlGenericError(xmlGenericErrorContext,
1863                             "%s is a range\n", arg);
1864             break;
1865         case XPATH_USERS:
1866             xmlGenericError(xmlGenericErrorContext,
1867                             "%s is user-defined\n", arg);
1868             break;
1869         case XPATH_XSLT_TREE:
1870             xmlGenericError(xmlGenericErrorContext,
1871                             "%s is an XSLT value tree\n", arg);
1872             break;
1873     }
1874 #if 0
1875     xmlGenericError(xmlGenericErrorContext,
1876                     "Try casting the result string function (xpath builtin)\n",
1877                     arg);
1878 #endif
1879 }
1880 
1881 
1882 #ifdef LIBXML_OUTPUT_ENABLED
1883 /**
1884  * xmlShellPrintNodeCtxt:
1885  * @ctxt : a non-null shell context
1886  * @node : a non-null node to print to the output FILE
1887  *
1888  * Print node to the output FILE
1889  */
1890 static void
xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)1891 xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1892 {
1893     FILE *fp;
1894 
1895     if (!node)
1896         return;
1897     if (ctxt == NULL)
1898 	fp = stdout;
1899     else
1900 	fp = ctxt->output;
1901 
1902     if (node->type == XML_DOCUMENT_NODE)
1903         xmlDocDump(fp, (xmlDocPtr) node);
1904     else if (node->type == XML_ATTRIBUTE_NODE)
1905         xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
1906     else
1907         xmlElemDump(fp, node->doc, node);
1908 
1909     fprintf(fp, "\n");
1910 }
1911 
1912 /**
1913  * xmlShellPrintNode:
1914  * @node : a non-null node to print to the output FILE
1915  *
1916  * Print node to the output FILE
1917  */
1918 void
xmlShellPrintNode(xmlNodePtr node)1919 xmlShellPrintNode(xmlNodePtr node)
1920 {
1921     xmlShellPrintNodeCtxt(NULL, node);
1922 }
1923 #endif /* LIBXML_OUTPUT_ENABLED */
1924 
1925 /**
1926  * xmlShellPrintXPathResultCtxt:
1927  * @ctxt: a valid shell context
1928  * @list: a valid result generated by an xpath evaluation
1929  *
1930  * Prints result to the output FILE
1931  */
1932 static void
xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)1933 xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
1934 {
1935     if (!ctxt)
1936        return;
1937 
1938     if (list != NULL) {
1939         switch (list->type) {
1940             case XPATH_NODESET:{
1941 #ifdef LIBXML_OUTPUT_ENABLED
1942                     int indx;
1943 
1944                     if (list->nodesetval) {
1945                         for (indx = 0; indx < list->nodesetval->nodeNr;
1946                              indx++) {
1947                             xmlShellPrintNodeCtxt(ctxt,
1948 				    list->nodesetval->nodeTab[indx]);
1949                         }
1950                     } else {
1951                         xmlGenericError(xmlGenericErrorContext,
1952                                         "Empty node set\n");
1953                     }
1954                     break;
1955 #else
1956 		    xmlGenericError(xmlGenericErrorContext,
1957 				    "Node set\n");
1958 #endif /* LIBXML_OUTPUT_ENABLED */
1959                 }
1960             case XPATH_BOOLEAN:
1961                 xmlGenericError(xmlGenericErrorContext,
1962                                 "Is a Boolean:%s\n",
1963                                 xmlBoolToText(list->boolval));
1964                 break;
1965             case XPATH_NUMBER:
1966                 xmlGenericError(xmlGenericErrorContext,
1967                                 "Is a number:%0g\n", list->floatval);
1968                 break;
1969             case XPATH_STRING:
1970                 xmlGenericError(xmlGenericErrorContext,
1971                                 "Is a string:%s\n", list->stringval);
1972                 break;
1973 
1974             default:
1975                 xmlShellPrintXPathError(list->type, NULL);
1976         }
1977     }
1978 }
1979 
1980 /**
1981  * xmlShellPrintXPathResult:
1982  * @list: a valid result generated by an xpath evaluation
1983  *
1984  * Prints result to the output FILE
1985  */
1986 void
xmlShellPrintXPathResult(xmlXPathObjectPtr list)1987 xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1988 {
1989     xmlShellPrintXPathResultCtxt(NULL, list);
1990 }
1991 
1992 /**
1993  * xmlShellList:
1994  * @ctxt:  the shell context
1995  * @arg:  unused
1996  * @node:  a node
1997  * @node2:  unused
1998  *
1999  * Implements the XML shell function "ls"
2000  * Does an Unix like listing of the given node (like a directory)
2001  *
2002  * Returns 0
2003  */
2004 int
xmlShellList(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2005 xmlShellList(xmlShellCtxtPtr ctxt,
2006              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2007              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2008 {
2009     xmlNodePtr cur;
2010     if (!ctxt)
2011         return (0);
2012     if (node == NULL) {
2013 	fprintf(ctxt->output, "NULL\n");
2014 	return (0);
2015     }
2016     if ((node->type == XML_DOCUMENT_NODE) ||
2017         (node->type == XML_HTML_DOCUMENT_NODE)) {
2018         cur = ((xmlDocPtr) node)->children;
2019     } else if (node->type == XML_NAMESPACE_DECL) {
2020         xmlLsOneNode(ctxt->output, node);
2021         return (0);
2022     } else if (node->children != NULL) {
2023         cur = node->children;
2024     } else {
2025         xmlLsOneNode(ctxt->output, node);
2026         return (0);
2027     }
2028     while (cur != NULL) {
2029         xmlLsOneNode(ctxt->output, cur);
2030         cur = cur->next;
2031     }
2032     return (0);
2033 }
2034 
2035 /**
2036  * xmlShellBase:
2037  * @ctxt:  the shell context
2038  * @arg:  unused
2039  * @node:  a node
2040  * @node2:  unused
2041  *
2042  * Implements the XML shell function "base"
2043  * dumps the current XML base of the node
2044  *
2045  * Returns 0
2046  */
2047 int
xmlShellBase(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2048 xmlShellBase(xmlShellCtxtPtr ctxt,
2049              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2050              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2051 {
2052     xmlChar *base;
2053     if (!ctxt)
2054         return 0;
2055     if (node == NULL) {
2056 	fprintf(ctxt->output, "NULL\n");
2057 	return (0);
2058     }
2059 
2060     base = xmlNodeGetBase(node->doc, node);
2061 
2062     if (base == NULL) {
2063         fprintf(ctxt->output, " No base found !!!\n");
2064     } else {
2065         fprintf(ctxt->output, "%s\n", base);
2066         xmlFree(base);
2067     }
2068     return (0);
2069 }
2070 
2071 #ifdef LIBXML_TREE_ENABLED
2072 /**
2073  * xmlShellSetBase:
2074  * @ctxt:  the shell context
2075  * @arg:  the new base
2076  * @node:  a node
2077  * @node2:  unused
2078  *
2079  * Implements the XML shell function "setbase"
2080  * change the current XML base of the node
2081  *
2082  * Returns 0
2083  */
2084 static int
xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2085 xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2086              char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2087              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2088 {
2089     xmlNodeSetBase(node, (xmlChar*) arg);
2090     return (0);
2091 }
2092 #endif
2093 
2094 #ifdef LIBXML_XPATH_ENABLED
2095 /**
2096  * xmlShellRegisterNamespace:
2097  * @ctxt:  the shell context
2098  * @arg:  a string in prefix=nsuri format
2099  * @node:  unused
2100  * @node2:  unused
2101  *
2102  * Implements the XML shell function "setns"
2103  * register/unregister a prefix=namespace pair
2104  * on the XPath context
2105  *
2106  * Returns 0 on success and a negative value otherwise.
2107  */
2108 static int
xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt,char * arg,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2109 xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
2110       xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2111 {
2112     xmlChar* nsListDup;
2113     xmlChar* prefix;
2114     xmlChar* href;
2115     xmlChar* next;
2116 
2117     nsListDup = xmlStrdup((xmlChar *) arg);
2118     next = nsListDup;
2119     while(next != NULL) {
2120 	/* skip spaces */
2121 	/*while((*next) == ' ') next++;*/
2122 	if((*next) == '\0') break;
2123 
2124 	/* find prefix */
2125 	prefix = next;
2126 	next = (xmlChar*)xmlStrchr(next, '=');
2127 	if(next == NULL) {
2128 	    fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
2129 	    xmlFree(nsListDup);
2130 	    return(-1);
2131 	}
2132 	*(next++) = '\0';
2133 
2134 	/* find href */
2135 	href = next;
2136 	next = (xmlChar*)xmlStrchr(next, ' ');
2137 	if(next != NULL) {
2138 	    *(next++) = '\0';
2139 	}
2140 
2141 	/* do register namespace */
2142 	if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
2143 	    fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
2144 	    xmlFree(nsListDup);
2145 	    return(-1);
2146 	}
2147     }
2148 
2149     xmlFree(nsListDup);
2150     return(0);
2151 }
2152 /**
2153  * xmlShellRegisterRootNamespaces:
2154  * @ctxt:  the shell context
2155  * @arg:  unused
2156  * @node:  the root element
2157  * @node2:  unused
2158  *
2159  * Implements the XML shell function "setrootns"
2160  * which registers all namespaces declarations found on the root element.
2161  *
2162  * Returns 0 on success and a negative value otherwise.
2163  */
2164 static int
xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr root,xmlNodePtr node2 ATTRIBUTE_UNUSED)2165 xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2166       xmlNodePtr root, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2167 {
2168     xmlNsPtr ns;
2169 
2170     if ((root == NULL) || (root->type != XML_ELEMENT_NODE) ||
2171         (root->nsDef == NULL) || (ctxt == NULL) || (ctxt->pctxt == NULL))
2172 	return(-1);
2173     ns = root->nsDef;
2174     while (ns != NULL) {
2175         if (ns->prefix == NULL)
2176 	    xmlXPathRegisterNs(ctxt->pctxt, BAD_CAST "defaultns", ns->href);
2177 	else
2178 	    xmlXPathRegisterNs(ctxt->pctxt, ns->prefix, ns->href);
2179         ns = ns->next;
2180     }
2181     return(0);
2182 }
2183 #endif
2184 
2185 /**
2186  * xmlShellGrep:
2187  * @ctxt:  the shell context
2188  * @arg:  the string or regular expression to find
2189  * @node:  a node
2190  * @node2:  unused
2191  *
2192  * Implements the XML shell function "grep"
2193  * dumps information about the node (namespace, attributes, content).
2194  *
2195  * Returns 0
2196  */
2197 static int
xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2198 xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2199             char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2200 {
2201     if (!ctxt)
2202         return (0);
2203     if (node == NULL)
2204 	return (0);
2205     if (arg == NULL)
2206 	return (0);
2207 #ifdef LIBXML_REGEXP_ENABLED
2208     if ((xmlStrchr((xmlChar *) arg, '?')) ||
2209 	(xmlStrchr((xmlChar *) arg, '*')) ||
2210 	(xmlStrchr((xmlChar *) arg, '.')) ||
2211 	(xmlStrchr((xmlChar *) arg, '['))) {
2212     }
2213 #endif
2214     while (node != NULL) {
2215         if (node->type == XML_COMMENT_NODE) {
2216 	    if (xmlStrstr(node->content, (xmlChar *) arg)) {
2217 
2218 		fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
2219                 xmlShellList(ctxt, NULL, node, NULL);
2220 	    }
2221         } else if (node->type == XML_TEXT_NODE) {
2222 	    if (xmlStrstr(node->content, (xmlChar *) arg)) {
2223 
2224 		fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
2225                 xmlShellList(ctxt, NULL, node->parent, NULL);
2226 	    }
2227         }
2228 
2229         /*
2230          * Browse the full subtree, deep first
2231          */
2232 
2233         if ((node->type == XML_DOCUMENT_NODE) ||
2234             (node->type == XML_HTML_DOCUMENT_NODE)) {
2235             node = ((xmlDocPtr) node)->children;
2236         } else if ((node->children != NULL)
2237                    && (node->type != XML_ENTITY_REF_NODE)) {
2238             /* deep first */
2239             node = node->children;
2240         } else if (node->next != NULL) {
2241             /* then siblings */
2242             node = node->next;
2243         } else {
2244             /* go up to parents->next if needed */
2245             while (node != NULL) {
2246                 if (node->parent != NULL) {
2247                     node = node->parent;
2248                 }
2249                 if (node->next != NULL) {
2250                     node = node->next;
2251                     break;
2252                 }
2253                 if (node->parent == NULL) {
2254                     node = NULL;
2255                     break;
2256                 }
2257             }
2258 	}
2259     }
2260     return (0);
2261 }
2262 
2263 /**
2264  * xmlShellDir:
2265  * @ctxt:  the shell context
2266  * @arg:  unused
2267  * @node:  a node
2268  * @node2:  unused
2269  *
2270  * Implements the XML shell function "dir"
2271  * dumps information about the node (namespace, attributes, content).
2272  *
2273  * Returns 0
2274  */
2275 int
xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2276 xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2277             char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2278             xmlNodePtr node2 ATTRIBUTE_UNUSED)
2279 {
2280     if (!ctxt)
2281         return (0);
2282     if (node == NULL) {
2283 	fprintf(ctxt->output, "NULL\n");
2284 	return (0);
2285     }
2286     if ((node->type == XML_DOCUMENT_NODE) ||
2287         (node->type == XML_HTML_DOCUMENT_NODE)) {
2288         xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
2289     } else if (node->type == XML_ATTRIBUTE_NODE) {
2290         xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
2291     } else {
2292         xmlDebugDumpOneNode(ctxt->output, node, 0);
2293     }
2294     return (0);
2295 }
2296 
2297 /**
2298  * xmlShellSetContent:
2299  * @ctxt:  the shell context
2300  * @value:  the content as a string
2301  * @node:  a node
2302  * @node2:  unused
2303  *
2304  * Implements the XML shell function "dir"
2305  * dumps information about the node (namespace, attributes, content).
2306  *
2307  * Returns 0
2308  */
2309 static int
xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * value,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2310 xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2311             char *value, xmlNodePtr node,
2312             xmlNodePtr node2 ATTRIBUTE_UNUSED)
2313 {
2314     xmlNodePtr results;
2315     xmlParserErrors ret;
2316 
2317     if (!ctxt)
2318         return (0);
2319     if (node == NULL) {
2320 	fprintf(ctxt->output, "NULL\n");
2321 	return (0);
2322     }
2323     if (value == NULL) {
2324         fprintf(ctxt->output, "NULL\n");
2325 	return (0);
2326     }
2327 
2328     ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
2329     if (ret == XML_ERR_OK) {
2330 	if (node->children != NULL) {
2331 	    xmlFreeNodeList(node->children);
2332 	    node->children = NULL;
2333 	    node->last = NULL;
2334 	}
2335 	xmlAddChildList(node, results);
2336     } else {
2337         fprintf(ctxt->output, "failed to parse content\n");
2338     }
2339     return (0);
2340 }
2341 
2342 #ifdef LIBXML_SCHEMAS_ENABLED
2343 /**
2344  * xmlShellRNGValidate:
2345  * @ctxt:  the shell context
2346  * @schemas:  the path to the Relax-NG schemas
2347  * @node:  a node
2348  * @node2:  unused
2349  *
2350  * Implements the XML shell function "relaxng"
2351  * validating the instance against a Relax-NG schemas
2352  *
2353  * Returns 0
2354  */
2355 static int
xmlShellRNGValidate(xmlShellCtxtPtr sctxt,char * schemas,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2356 xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2357             xmlNodePtr node ATTRIBUTE_UNUSED,
2358 	    xmlNodePtr node2 ATTRIBUTE_UNUSED)
2359 {
2360     xmlRelaxNGPtr relaxngschemas;
2361     xmlRelaxNGParserCtxtPtr ctxt;
2362     xmlRelaxNGValidCtxtPtr vctxt;
2363     int ret;
2364 
2365     ctxt = xmlRelaxNGNewParserCtxt(schemas);
2366     xmlRelaxNGSetParserErrors(ctxt, xmlGenericError, xmlGenericError, NULL);
2367     relaxngschemas = xmlRelaxNGParse(ctxt);
2368     xmlRelaxNGFreeParserCtxt(ctxt);
2369     if (relaxngschemas == NULL) {
2370 	xmlGenericError(xmlGenericErrorContext,
2371 		"Relax-NG schema %s failed to compile\n", schemas);
2372 	return(-1);
2373     }
2374     vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2375     xmlRelaxNGSetValidErrors(vctxt, xmlGenericError, xmlGenericError, NULL);
2376     ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2377     if (ret == 0) {
2378 	fprintf(stderr, "%s validates\n", sctxt->filename);
2379     } else if (ret > 0) {
2380 	fprintf(stderr, "%s fails to validate\n", sctxt->filename);
2381     } else {
2382 	fprintf(stderr, "%s validation generated an internal error\n",
2383 	       sctxt->filename);
2384     }
2385     xmlRelaxNGFreeValidCtxt(vctxt);
2386     if (relaxngschemas != NULL)
2387 	xmlRelaxNGFree(relaxngschemas);
2388     return(0);
2389 }
2390 #endif
2391 
2392 #ifdef LIBXML_OUTPUT_ENABLED
2393 /**
2394  * xmlShellCat:
2395  * @ctxt:  the shell context
2396  * @arg:  unused
2397  * @node:  a node
2398  * @node2:  unused
2399  *
2400  * Implements the XML shell function "cat"
2401  * dumps the serialization node content (XML or HTML).
2402  *
2403  * Returns 0
2404  */
2405 int
xmlShellCat(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2406 xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2407             xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2408 {
2409     if (!ctxt)
2410         return (0);
2411     if (node == NULL) {
2412 	fprintf(ctxt->output, "NULL\n");
2413 	return (0);
2414     }
2415     if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2416 #ifdef LIBXML_HTML_ENABLED
2417         if (node->type == XML_HTML_DOCUMENT_NODE)
2418             htmlDocDump(ctxt->output, (htmlDocPtr) node);
2419         else
2420             htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
2421 #else
2422         if (node->type == XML_DOCUMENT_NODE)
2423             xmlDocDump(ctxt->output, (xmlDocPtr) node);
2424         else
2425             xmlElemDump(ctxt->output, ctxt->doc, node);
2426 #endif /* LIBXML_HTML_ENABLED */
2427     } else {
2428         if (node->type == XML_DOCUMENT_NODE)
2429             xmlDocDump(ctxt->output, (xmlDocPtr) node);
2430         else
2431             xmlElemDump(ctxt->output, ctxt->doc, node);
2432     }
2433     fprintf(ctxt->output, "\n");
2434     return (0);
2435 }
2436 #endif /* LIBXML_OUTPUT_ENABLED */
2437 
2438 /**
2439  * xmlShellLoad:
2440  * @ctxt:  the shell context
2441  * @filename:  the file name
2442  * @node:  unused
2443  * @node2:  unused
2444  *
2445  * Implements the XML shell function "load"
2446  * loads a new document specified by the filename
2447  *
2448  * Returns 0 or -1 if loading failed
2449  */
2450 int
xmlShellLoad(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2451 xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2452              xmlNodePtr node ATTRIBUTE_UNUSED,
2453              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2454 {
2455     xmlDocPtr doc;
2456     int html = 0;
2457 
2458     if ((ctxt == NULL) || (filename == NULL)) return(-1);
2459     if (ctxt->doc != NULL)
2460         html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
2461 
2462     if (html) {
2463 #ifdef LIBXML_HTML_ENABLED
2464         doc = htmlParseFile(filename, NULL);
2465 #else
2466         fprintf(ctxt->output, "HTML support not compiled in\n");
2467         doc = NULL;
2468 #endif /* LIBXML_HTML_ENABLED */
2469     } else {
2470         doc = xmlReadFile(filename,NULL,0);
2471     }
2472     if (doc != NULL) {
2473         if (ctxt->loaded == 1) {
2474             xmlFreeDoc(ctxt->doc);
2475         }
2476         ctxt->loaded = 1;
2477 #ifdef LIBXML_XPATH_ENABLED
2478         xmlXPathFreeContext(ctxt->pctxt);
2479 #endif /* LIBXML_XPATH_ENABLED */
2480         xmlFree(ctxt->filename);
2481         ctxt->doc = doc;
2482         ctxt->node = (xmlNodePtr) doc;
2483 #ifdef LIBXML_XPATH_ENABLED
2484         ctxt->pctxt = xmlXPathNewContext(doc);
2485 #endif /* LIBXML_XPATH_ENABLED */
2486         ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
2487     } else
2488         return (-1);
2489     return (0);
2490 }
2491 
2492 #ifdef LIBXML_OUTPUT_ENABLED
2493 /**
2494  * xmlShellWrite:
2495  * @ctxt:  the shell context
2496  * @filename:  the file name
2497  * @node:  a node in the tree
2498  * @node2:  unused
2499  *
2500  * Implements the XML shell function "write"
2501  * Write the current node to the filename, it saves the serialization
2502  * of the subtree under the @node specified
2503  *
2504  * Returns 0 or -1 in case of error
2505  */
2506 int
xmlShellWrite(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2507 xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
2508               xmlNodePtr node2 ATTRIBUTE_UNUSED)
2509 {
2510     if (node == NULL)
2511         return (-1);
2512     if ((filename == NULL) || (filename[0] == 0)) {
2513         return (-1);
2514     }
2515 #ifdef W_OK
2516     if (access((char *) filename, W_OK)) {
2517         xmlGenericError(xmlGenericErrorContext,
2518                         "Cannot write to %s\n", filename);
2519         return (-1);
2520     }
2521 #endif
2522     switch (node->type) {
2523         case XML_DOCUMENT_NODE:
2524             if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2525                 xmlGenericError(xmlGenericErrorContext,
2526                                 "Failed to write to %s\n", filename);
2527                 return (-1);
2528             }
2529             break;
2530         case XML_HTML_DOCUMENT_NODE:
2531 #ifdef LIBXML_HTML_ENABLED
2532             if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2533                 xmlGenericError(xmlGenericErrorContext,
2534                                 "Failed to write to %s\n", filename);
2535                 return (-1);
2536             }
2537 #else
2538             if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2539                 xmlGenericError(xmlGenericErrorContext,
2540                                 "Failed to write to %s\n", filename);
2541                 return (-1);
2542             }
2543 #endif /* LIBXML_HTML_ENABLED */
2544             break;
2545         default:{
2546                 FILE *f;
2547 
2548                 f = fopen((char *) filename, "w");
2549                 if (f == NULL) {
2550                     xmlGenericError(xmlGenericErrorContext,
2551                                     "Failed to write to %s\n", filename);
2552                     return (-1);
2553                 }
2554                 xmlElemDump(f, ctxt->doc, node);
2555                 fclose(f);
2556             }
2557     }
2558     return (0);
2559 }
2560 
2561 /**
2562  * xmlShellSave:
2563  * @ctxt:  the shell context
2564  * @filename:  the file name (optional)
2565  * @node:  unused
2566  * @node2:  unused
2567  *
2568  * Implements the XML shell function "save"
2569  * Write the current document to the filename, or it's original name
2570  *
2571  * Returns 0 or -1 in case of error
2572  */
2573 int
xmlShellSave(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2574 xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2575              xmlNodePtr node ATTRIBUTE_UNUSED,
2576              xmlNodePtr node2 ATTRIBUTE_UNUSED)
2577 {
2578     if ((ctxt == NULL) || (ctxt->doc == NULL))
2579         return (-1);
2580     if ((filename == NULL) || (filename[0] == 0))
2581         filename = ctxt->filename;
2582     if (filename == NULL)
2583         return (-1);
2584 #ifdef W_OK
2585     if (access((char *) filename, W_OK)) {
2586         xmlGenericError(xmlGenericErrorContext,
2587                         "Cannot save to %s\n", filename);
2588         return (-1);
2589     }
2590 #endif
2591     switch (ctxt->doc->type) {
2592         case XML_DOCUMENT_NODE:
2593             if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2594                 xmlGenericError(xmlGenericErrorContext,
2595                                 "Failed to save to %s\n", filename);
2596             }
2597             break;
2598         case XML_HTML_DOCUMENT_NODE:
2599 #ifdef LIBXML_HTML_ENABLED
2600             if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2601                 xmlGenericError(xmlGenericErrorContext,
2602                                 "Failed to save to %s\n", filename);
2603             }
2604 #else
2605             if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2606                 xmlGenericError(xmlGenericErrorContext,
2607                                 "Failed to save to %s\n", filename);
2608             }
2609 #endif /* LIBXML_HTML_ENABLED */
2610             break;
2611         default:
2612             xmlGenericError(xmlGenericErrorContext,
2613 	    "To save to subparts of a document use the 'write' command\n");
2614             return (-1);
2615 
2616     }
2617     return (0);
2618 }
2619 #endif /* LIBXML_OUTPUT_ENABLED */
2620 
2621 #ifdef LIBXML_VALID_ENABLED
2622 /**
2623  * xmlShellValidate:
2624  * @ctxt:  the shell context
2625  * @dtd:  the DTD URI (optional)
2626  * @node:  unused
2627  * @node2:  unused
2628  *
2629  * Implements the XML shell function "validate"
2630  * Validate the document, if a DTD path is provided, then the validation
2631  * is done against the given DTD.
2632  *
2633  * Returns 0 or -1 in case of error
2634  */
2635 int
xmlShellValidate(xmlShellCtxtPtr ctxt,char * dtd,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2636 xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2637                  xmlNodePtr node ATTRIBUTE_UNUSED,
2638                  xmlNodePtr node2 ATTRIBUTE_UNUSED)
2639 {
2640     xmlValidCtxt vctxt;
2641     int res = -1;
2642 
2643     if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1);
2644     vctxt.userData = NULL;
2645     vctxt.error = xmlGenericError;
2646     vctxt.warning = xmlGenericError;
2647 
2648     if ((dtd == NULL) || (dtd[0] == 0)) {
2649         res = xmlValidateDocument(&vctxt, ctxt->doc);
2650     } else {
2651         xmlDtdPtr subset;
2652 
2653         subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2654         if (subset != NULL) {
2655             res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2656 
2657             xmlFreeDtd(subset);
2658         }
2659     }
2660     return (res);
2661 }
2662 #endif /* LIBXML_VALID_ENABLED */
2663 
2664 /**
2665  * xmlShellDu:
2666  * @ctxt:  the shell context
2667  * @arg:  unused
2668  * @tree:  a node defining a subtree
2669  * @node2:  unused
2670  *
2671  * Implements the XML shell function "du"
2672  * show the structure of the subtree under node @tree
2673  * If @tree is null, the command works on the current node.
2674  *
2675  * Returns 0 or -1 in case of error
2676  */
2677 int
xmlShellDu(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr tree,xmlNodePtr node2 ATTRIBUTE_UNUSED)2678 xmlShellDu(xmlShellCtxtPtr ctxt,
2679            char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2680            xmlNodePtr node2 ATTRIBUTE_UNUSED)
2681 {
2682     xmlNodePtr node;
2683     int indent = 0, i;
2684 
2685     if (!ctxt)
2686 	return (-1);
2687 
2688     if (tree == NULL)
2689         return (-1);
2690     node = tree;
2691     while (node != NULL) {
2692         if ((node->type == XML_DOCUMENT_NODE) ||
2693             (node->type == XML_HTML_DOCUMENT_NODE)) {
2694             fprintf(ctxt->output, "/\n");
2695         } else if (node->type == XML_ELEMENT_NODE) {
2696             for (i = 0; i < indent; i++)
2697                 fprintf(ctxt->output, "  ");
2698             if ((node->ns) && (node->ns->prefix))
2699                 fprintf(ctxt->output, "%s:", node->ns->prefix);
2700             fprintf(ctxt->output, "%s\n", node->name);
2701         } else {
2702         }
2703 
2704         /*
2705          * Browse the full subtree, deep first
2706          */
2707 
2708         if ((node->type == XML_DOCUMENT_NODE) ||
2709             (node->type == XML_HTML_DOCUMENT_NODE)) {
2710             node = ((xmlDocPtr) node)->children;
2711         } else if ((node->children != NULL)
2712                    && (node->type != XML_ENTITY_REF_NODE)) {
2713             /* deep first */
2714             node = node->children;
2715             indent++;
2716         } else if ((node != tree) && (node->next != NULL)) {
2717             /* then siblings */
2718             node = node->next;
2719         } else if (node != tree) {
2720             /* go up to parents->next if needed */
2721             while (node != tree) {
2722                 if (node->parent != NULL) {
2723                     node = node->parent;
2724                     indent--;
2725                 }
2726                 if ((node != tree) && (node->next != NULL)) {
2727                     node = node->next;
2728                     break;
2729                 }
2730                 if (node->parent == NULL) {
2731                     node = NULL;
2732                     break;
2733                 }
2734                 if (node == tree) {
2735                     node = NULL;
2736                     break;
2737                 }
2738             }
2739             /* exit condition */
2740             if (node == tree)
2741                 node = NULL;
2742         } else
2743             node = NULL;
2744     }
2745     return (0);
2746 }
2747 
2748 /**
2749  * xmlShellPwd:
2750  * @ctxt:  the shell context
2751  * @buffer:  the output buffer
2752  * @node:  a node
2753  * @node2:  unused
2754  *
2755  * Implements the XML shell function "pwd"
2756  * Show the full path from the root to the node, if needed building
2757  * thumblers when similar elements exists at a given ancestor level.
2758  * The output is compatible with XPath commands.
2759  *
2760  * Returns 0 or -1 in case of error
2761  */
2762 int
xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * buffer,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2763 xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2764             xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2765 {
2766     xmlChar *path;
2767 
2768     if ((node == NULL) || (buffer == NULL))
2769         return (-1);
2770 
2771     path = xmlGetNodePath(node);
2772     if (path == NULL)
2773 	return (-1);
2774 
2775     /*
2776      * This test prevents buffer overflow, because this routine
2777      * is only called by xmlShell, in which the second argument is
2778      * 500 chars long.
2779      * It is a dirty hack before a cleaner solution is found.
2780      * Documentation should mention that the second argument must
2781      * be at least 500 chars long, and could be stripped if too long.
2782      */
2783     snprintf(buffer, 499, "%s", path);
2784     buffer[499] = '0';
2785     xmlFree(path);
2786 
2787     return (0);
2788 }
2789 
2790 /**
2791  * xmlShell:
2792  * @doc:  the initial document
2793  * @filename:  the output buffer
2794  * @input:  the line reading function
2795  * @output:  the output FILE*, defaults to stdout if NULL
2796  *
2797  * Implements the XML shell
2798  * This allow to load, validate, view, modify and save a document
2799  * using a environment similar to a UNIX commandline.
2800  */
2801 void
xmlShell(xmlDocPtr doc,char * filename,xmlShellReadlineFunc input,FILE * output)2802 xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
2803          FILE * output)
2804 {
2805     char prompt[500] = "/ > ";
2806     char *cmdline = NULL, *cur;
2807     char command[100];
2808     char arg[400];
2809     int i;
2810     xmlShellCtxtPtr ctxt;
2811     xmlXPathObjectPtr list;
2812 
2813     if (doc == NULL)
2814         return;
2815     if (filename == NULL)
2816         return;
2817     if (input == NULL)
2818         return;
2819     if (output == NULL)
2820         output = stdout;
2821     ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
2822     if (ctxt == NULL)
2823         return;
2824     ctxt->loaded = 0;
2825     ctxt->doc = doc;
2826     ctxt->input = input;
2827     ctxt->output = output;
2828     ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
2829     ctxt->node = (xmlNodePtr) ctxt->doc;
2830 
2831 #ifdef LIBXML_XPATH_ENABLED
2832     ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2833     if (ctxt->pctxt == NULL) {
2834         xmlFree(ctxt);
2835         return;
2836     }
2837 #endif /* LIBXML_XPATH_ENABLED */
2838     while (1) {
2839         if (ctxt->node == (xmlNodePtr) ctxt->doc)
2840             snprintf(prompt, sizeof(prompt), "%s > ", "/");
2841         else if ((ctxt->node != NULL) && (ctxt->node->name) &&
2842                  (ctxt->node->ns) && (ctxt->node->ns->prefix))
2843             snprintf(prompt, sizeof(prompt), "%s:%s > ",
2844                      (ctxt->node->ns->prefix), ctxt->node->name);
2845         else if ((ctxt->node != NULL) && (ctxt->node->name))
2846             snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
2847         else
2848             snprintf(prompt, sizeof(prompt), "? > ");
2849         prompt[sizeof(prompt) - 1] = 0;
2850 
2851         /*
2852          * Get a new command line
2853          */
2854         cmdline = ctxt->input(prompt);
2855         if (cmdline == NULL)
2856             break;
2857 
2858         /*
2859          * Parse the command itself
2860          */
2861         cur = cmdline;
2862         while ((*cur == ' ') || (*cur == '\t'))
2863             cur++;
2864         i = 0;
2865         while ((*cur != ' ') && (*cur != '\t') &&
2866                (*cur != '\n') && (*cur != '\r')) {
2867             if (*cur == 0)
2868                 break;
2869             command[i++] = *cur++;
2870         }
2871         command[i] = 0;
2872         if (i == 0)
2873             continue;
2874 
2875         /*
2876          * Parse the argument
2877          */
2878         while ((*cur == ' ') || (*cur == '\t'))
2879             cur++;
2880         i = 0;
2881         while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2882             if (*cur == 0)
2883                 break;
2884             arg[i++] = *cur++;
2885         }
2886         arg[i] = 0;
2887 
2888         /*
2889          * start interpreting the command
2890          */
2891         if (!strcmp(command, "exit"))
2892             break;
2893         if (!strcmp(command, "quit"))
2894             break;
2895         if (!strcmp(command, "bye"))
2896             break;
2897 		if (!strcmp(command, "help")) {
2898 		  fprintf(ctxt->output, "\tbase         display XML base of the node\n");
2899 		  fprintf(ctxt->output, "\tsetbase URI  change the XML base of the node\n");
2900 		  fprintf(ctxt->output, "\tbye          leave shell\n");
2901 		  fprintf(ctxt->output, "\tcat [node]   display node or current node\n");
2902 		  fprintf(ctxt->output, "\tcd [path]    change directory to path or to root\n");
2903 		  fprintf(ctxt->output, "\tdir [path]   dumps information about the node (namespace, attributes, content)\n");
2904 		  fprintf(ctxt->output, "\tdu [path]    show the structure of the subtree under path or the current node\n");
2905 		  fprintf(ctxt->output, "\texit         leave shell\n");
2906 		  fprintf(ctxt->output, "\thelp         display this help\n");
2907 		  fprintf(ctxt->output, "\tfree         display memory usage\n");
2908 		  fprintf(ctxt->output, "\tload [name]  load a new document with name\n");
2909 		  fprintf(ctxt->output, "\tls [path]    list contents of path or the current directory\n");
2910 		  fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n");
2911 #ifdef LIBXML_XPATH_ENABLED
2912 		  fprintf(ctxt->output, "\txpath expr   evaluate the XPath expression in that context and print the result\n");
2913 		  fprintf(ctxt->output, "\tsetns nsreg  register a namespace to a prefix in the XPath evaluation context\n");
2914 		  fprintf(ctxt->output, "\t             format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
2915 		  fprintf(ctxt->output, "\tsetrootns    register all namespace found on the root element\n");
2916 		  fprintf(ctxt->output, "\t             the default namespace if any uses 'defaultns' prefix\n");
2917 #endif /* LIBXML_XPATH_ENABLED */
2918 		  fprintf(ctxt->output, "\tpwd          display current working directory\n");
2919 		  fprintf(ctxt->output, "\twhereis      display absolute path of [path] or current working directory\n");
2920 		  fprintf(ctxt->output, "\tquit         leave shell\n");
2921 #ifdef LIBXML_OUTPUT_ENABLED
2922 		  fprintf(ctxt->output, "\tsave [name]  save this document to name or the original name\n");
2923 		  fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
2924 #endif /* LIBXML_OUTPUT_ENABLED */
2925 #ifdef LIBXML_VALID_ENABLED
2926 		  fprintf(ctxt->output, "\tvalidate     check the document for errors\n");
2927 #endif /* LIBXML_VALID_ENABLED */
2928 #ifdef LIBXML_SCHEMAS_ENABLED
2929 		  fprintf(ctxt->output, "\trelaxng rng  validate the document against the Relax-NG schemas\n");
2930 #endif
2931 		  fprintf(ctxt->output, "\tgrep string  search for a string in the subtree\n");
2932 #ifdef LIBXML_VALID_ENABLED
2933         } else if (!strcmp(command, "validate")) {
2934             xmlShellValidate(ctxt, arg, NULL, NULL);
2935 #endif /* LIBXML_VALID_ENABLED */
2936         } else if (!strcmp(command, "load")) {
2937             xmlShellLoad(ctxt, arg, NULL, NULL);
2938 #ifdef LIBXML_SCHEMAS_ENABLED
2939         } else if (!strcmp(command, "relaxng")) {
2940             xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2941 #endif
2942 #ifdef LIBXML_OUTPUT_ENABLED
2943         } else if (!strcmp(command, "save")) {
2944             xmlShellSave(ctxt, arg, NULL, NULL);
2945         } else if (!strcmp(command, "write")) {
2946 	    if (arg[0] == 0)
2947 		xmlGenericError(xmlGenericErrorContext,
2948                         "Write command requires a filename argument\n");
2949 	    else
2950 		xmlShellWrite(ctxt, arg, ctxt->node, NULL);
2951 #endif /* LIBXML_OUTPUT_ENABLED */
2952         } else if (!strcmp(command, "grep")) {
2953             xmlShellGrep(ctxt, arg, ctxt->node, NULL);
2954         } else if (!strcmp(command, "free")) {
2955             if (arg[0] == 0) {
2956                 xmlMemShow(ctxt->output, 0);
2957             } else {
2958                 int len = 0;
2959 
2960                 sscanf(arg, "%d", &len);
2961                 xmlMemShow(ctxt->output, len);
2962             }
2963         } else if (!strcmp(command, "pwd")) {
2964             char dir[500];
2965 
2966             if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
2967                 fprintf(ctxt->output, "%s\n", dir);
2968         } else if (!strcmp(command, "du")) {
2969             if (arg[0] == 0) {
2970                 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2971             } else {
2972                 ctxt->pctxt->node = ctxt->node;
2973 #ifdef LIBXML_XPATH_ENABLED
2974                 ctxt->pctxt->node = ctxt->node;
2975                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2976 #else
2977                 list = NULL;
2978 #endif /* LIBXML_XPATH_ENABLED */
2979                 if (list != NULL) {
2980                     switch (list->type) {
2981                         case XPATH_UNDEFINED:
2982                             xmlGenericError(xmlGenericErrorContext,
2983                                             "%s: no such node\n", arg);
2984                             break;
2985                         case XPATH_NODESET:{
2986                             int indx;
2987 
2988                             if (list->nodesetval == NULL)
2989                                 break;
2990 
2991                             for (indx = 0;
2992                                  indx < list->nodesetval->nodeNr;
2993                                  indx++)
2994                                 xmlShellDu(ctxt, NULL,
2995                                            list->nodesetval->
2996                                            nodeTab[indx], NULL);
2997                             break;
2998                         }
2999                         case XPATH_BOOLEAN:
3000                             xmlGenericError(xmlGenericErrorContext,
3001                                             "%s is a Boolean\n", arg);
3002                             break;
3003                         case XPATH_NUMBER:
3004                             xmlGenericError(xmlGenericErrorContext,
3005                                             "%s is a number\n", arg);
3006                             break;
3007                         case XPATH_STRING:
3008                             xmlGenericError(xmlGenericErrorContext,
3009                                             "%s is a string\n", arg);
3010                             break;
3011                         case XPATH_POINT:
3012                             xmlGenericError(xmlGenericErrorContext,
3013                                             "%s is a point\n", arg);
3014                             break;
3015                         case XPATH_RANGE:
3016                             xmlGenericError(xmlGenericErrorContext,
3017                                             "%s is a range\n", arg);
3018                             break;
3019                         case XPATH_LOCATIONSET:
3020                             xmlGenericError(xmlGenericErrorContext,
3021                                             "%s is a range\n", arg);
3022                             break;
3023                         case XPATH_USERS:
3024                             xmlGenericError(xmlGenericErrorContext,
3025                                             "%s is user-defined\n", arg);
3026                             break;
3027                         case XPATH_XSLT_TREE:
3028                             xmlGenericError(xmlGenericErrorContext,
3029                                             "%s is an XSLT value tree\n",
3030                                             arg);
3031                             break;
3032                     }
3033 #ifdef LIBXML_XPATH_ENABLED
3034                     xmlXPathFreeObject(list);
3035 #endif
3036                 } else {
3037                     xmlGenericError(xmlGenericErrorContext,
3038                                     "%s: no such node\n", arg);
3039                 }
3040                 ctxt->pctxt->node = NULL;
3041             }
3042         } else if (!strcmp(command, "base")) {
3043             xmlShellBase(ctxt, NULL, ctxt->node, NULL);
3044         } else if (!strcmp(command, "set")) {
3045 	    xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
3046 #ifdef LIBXML_XPATH_ENABLED
3047         } else if (!strcmp(command, "setns")) {
3048             if (arg[0] == 0) {
3049 		xmlGenericError(xmlGenericErrorContext,
3050 				"setns: prefix=[nsuri] required\n");
3051             } else {
3052                 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
3053             }
3054         } else if (!strcmp(command, "setrootns")) {
3055 	    xmlNodePtr root;
3056 
3057 	    root = xmlDocGetRootElement(ctxt->doc);
3058 	    xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL);
3059         } else if (!strcmp(command, "xpath")) {
3060             if (arg[0] == 0) {
3061 		xmlGenericError(xmlGenericErrorContext,
3062 				"xpath: expression required\n");
3063 	    } else {
3064                 ctxt->pctxt->node = ctxt->node;
3065                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3066 		xmlXPathDebugDumpObject(ctxt->output, list, 0);
3067 		xmlXPathFreeObject(list);
3068 	    }
3069 #endif /* LIBXML_XPATH_ENABLED */
3070 #ifdef LIBXML_TREE_ENABLED
3071         } else if (!strcmp(command, "setbase")) {
3072             xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
3073 #endif
3074         } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
3075             int dir = (!strcmp(command, "dir"));
3076 
3077             if (arg[0] == 0) {
3078                 if (dir)
3079                     xmlShellDir(ctxt, NULL, ctxt->node, NULL);
3080                 else
3081                     xmlShellList(ctxt, NULL, ctxt->node, NULL);
3082             } else {
3083                 ctxt->pctxt->node = ctxt->node;
3084 #ifdef LIBXML_XPATH_ENABLED
3085                 ctxt->pctxt->node = ctxt->node;
3086                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3087 #else
3088                 list = NULL;
3089 #endif /* LIBXML_XPATH_ENABLED */
3090                 if (list != NULL) {
3091                     switch (list->type) {
3092                         case XPATH_UNDEFINED:
3093                             xmlGenericError(xmlGenericErrorContext,
3094                                             "%s: no such node\n", arg);
3095                             break;
3096                         case XPATH_NODESET:{
3097                                 int indx;
3098 
3099 				if (list->nodesetval == NULL)
3100 				    break;
3101 
3102                                 for (indx = 0;
3103                                      indx < list->nodesetval->nodeNr;
3104                                      indx++) {
3105                                     if (dir)
3106                                         xmlShellDir(ctxt, NULL,
3107                                                     list->nodesetval->
3108                                                     nodeTab[indx], NULL);
3109                                     else
3110                                         xmlShellList(ctxt, NULL,
3111                                                      list->nodesetval->
3112                                                      nodeTab[indx], NULL);
3113                                 }
3114                                 break;
3115                             }
3116                         case XPATH_BOOLEAN:
3117                             xmlGenericError(xmlGenericErrorContext,
3118                                             "%s is a Boolean\n", arg);
3119                             break;
3120                         case XPATH_NUMBER:
3121                             xmlGenericError(xmlGenericErrorContext,
3122                                             "%s is a number\n", arg);
3123                             break;
3124                         case XPATH_STRING:
3125                             xmlGenericError(xmlGenericErrorContext,
3126                                             "%s is a string\n", arg);
3127                             break;
3128                         case XPATH_POINT:
3129                             xmlGenericError(xmlGenericErrorContext,
3130                                             "%s is a point\n", arg);
3131                             break;
3132                         case XPATH_RANGE:
3133                             xmlGenericError(xmlGenericErrorContext,
3134                                             "%s is a range\n", arg);
3135                             break;
3136                         case XPATH_LOCATIONSET:
3137                             xmlGenericError(xmlGenericErrorContext,
3138                                             "%s is a range\n", arg);
3139                             break;
3140                         case XPATH_USERS:
3141                             xmlGenericError(xmlGenericErrorContext,
3142                                             "%s is user-defined\n", arg);
3143                             break;
3144                         case XPATH_XSLT_TREE:
3145                             xmlGenericError(xmlGenericErrorContext,
3146                                             "%s is an XSLT value tree\n",
3147                                             arg);
3148                             break;
3149                     }
3150 #ifdef LIBXML_XPATH_ENABLED
3151                     xmlXPathFreeObject(list);
3152 #endif
3153                 } else {
3154                     xmlGenericError(xmlGenericErrorContext,
3155                                     "%s: no such node\n", arg);
3156                 }
3157                 ctxt->pctxt->node = NULL;
3158             }
3159         } else if (!strcmp(command, "whereis")) {
3160             char dir[500];
3161 
3162             if (arg[0] == 0) {
3163                 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
3164                     fprintf(ctxt->output, "%s\n", dir);
3165             } else {
3166                 ctxt->pctxt->node = ctxt->node;
3167 #ifdef LIBXML_XPATH_ENABLED
3168                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3169 #else
3170                 list = NULL;
3171 #endif /* LIBXML_XPATH_ENABLED */
3172                 if (list != NULL) {
3173                     switch (list->type) {
3174                         case XPATH_UNDEFINED:
3175                             xmlGenericError(xmlGenericErrorContext,
3176                                             "%s: no such node\n", arg);
3177                             break;
3178                         case XPATH_NODESET:{
3179                                 int indx;
3180 
3181 				if (list->nodesetval == NULL)
3182 				    break;
3183 
3184                                 for (indx = 0;
3185                                      indx < list->nodesetval->nodeNr;
3186                                      indx++) {
3187                                     if (!xmlShellPwd(ctxt, dir, list->nodesetval->
3188                                                      nodeTab[indx], NULL))
3189                                         fprintf(ctxt->output, "%s\n", dir);
3190                                 }
3191                                 break;
3192                             }
3193                         case XPATH_BOOLEAN:
3194                             xmlGenericError(xmlGenericErrorContext,
3195                                             "%s is a Boolean\n", arg);
3196                             break;
3197                         case XPATH_NUMBER:
3198                             xmlGenericError(xmlGenericErrorContext,
3199                                             "%s is a number\n", arg);
3200                             break;
3201                         case XPATH_STRING:
3202                             xmlGenericError(xmlGenericErrorContext,
3203                                             "%s is a string\n", arg);
3204                             break;
3205                         case XPATH_POINT:
3206                             xmlGenericError(xmlGenericErrorContext,
3207                                             "%s is a point\n", arg);
3208                             break;
3209                         case XPATH_RANGE:
3210                             xmlGenericError(xmlGenericErrorContext,
3211                                             "%s is a range\n", arg);
3212                             break;
3213                         case XPATH_LOCATIONSET:
3214                             xmlGenericError(xmlGenericErrorContext,
3215                                             "%s is a range\n", arg);
3216                             break;
3217                         case XPATH_USERS:
3218                             xmlGenericError(xmlGenericErrorContext,
3219                                             "%s is user-defined\n", arg);
3220                             break;
3221                         case XPATH_XSLT_TREE:
3222                             xmlGenericError(xmlGenericErrorContext,
3223                                             "%s is an XSLT value tree\n",
3224                                             arg);
3225                             break;
3226                     }
3227 #ifdef LIBXML_XPATH_ENABLED
3228                     xmlXPathFreeObject(list);
3229 #endif
3230                 } else {
3231                     xmlGenericError(xmlGenericErrorContext,
3232                                     "%s: no such node\n", arg);
3233                 }
3234                 ctxt->pctxt->node = NULL;
3235             }
3236         } else if (!strcmp(command, "cd")) {
3237             if (arg[0] == 0) {
3238                 ctxt->node = (xmlNodePtr) ctxt->doc;
3239             } else {
3240 #ifdef LIBXML_XPATH_ENABLED
3241                 int l;
3242 
3243                 ctxt->pctxt->node = ctxt->node;
3244 		l = strlen(arg);
3245 		if ((l >= 2) && (arg[l - 1] == '/'))
3246 		    arg[l - 1] = 0;
3247                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3248 #else
3249                 list = NULL;
3250 #endif /* LIBXML_XPATH_ENABLED */
3251                 if (list != NULL) {
3252                     switch (list->type) {
3253                         case XPATH_UNDEFINED:
3254                             xmlGenericError(xmlGenericErrorContext,
3255                                             "%s: no such node\n", arg);
3256                             break;
3257                         case XPATH_NODESET:
3258                             if (list->nodesetval != NULL) {
3259 				if (list->nodesetval->nodeNr == 1) {
3260 				    ctxt->node = list->nodesetval->nodeTab[0];
3261 				    if ((ctxt->node != NULL) &&
3262 				        (ctxt->node->type ==
3263 					 XML_NAMESPACE_DECL)) {
3264 					xmlGenericError(xmlGenericErrorContext,
3265 						    "cannot cd to namespace\n");
3266 					ctxt->node = NULL;
3267 				    }
3268 				} else
3269 				    xmlGenericError(xmlGenericErrorContext,
3270 						    "%s is a %d Node Set\n",
3271 						    arg,
3272 						    list->nodesetval->nodeNr);
3273                             } else
3274                                 xmlGenericError(xmlGenericErrorContext,
3275                                                 "%s is an empty Node Set\n",
3276                                                 arg);
3277                             break;
3278                         case XPATH_BOOLEAN:
3279                             xmlGenericError(xmlGenericErrorContext,
3280                                             "%s is a Boolean\n", arg);
3281                             break;
3282                         case XPATH_NUMBER:
3283                             xmlGenericError(xmlGenericErrorContext,
3284                                             "%s is a number\n", arg);
3285                             break;
3286                         case XPATH_STRING:
3287                             xmlGenericError(xmlGenericErrorContext,
3288                                             "%s is a string\n", arg);
3289                             break;
3290                         case XPATH_POINT:
3291                             xmlGenericError(xmlGenericErrorContext,
3292                                             "%s is a point\n", arg);
3293                             break;
3294                         case XPATH_RANGE:
3295                             xmlGenericError(xmlGenericErrorContext,
3296                                             "%s is a range\n", arg);
3297                             break;
3298                         case XPATH_LOCATIONSET:
3299                             xmlGenericError(xmlGenericErrorContext,
3300                                             "%s is a range\n", arg);
3301                             break;
3302                         case XPATH_USERS:
3303                             xmlGenericError(xmlGenericErrorContext,
3304                                             "%s is user-defined\n", arg);
3305                             break;
3306                         case XPATH_XSLT_TREE:
3307                             xmlGenericError(xmlGenericErrorContext,
3308                                             "%s is an XSLT value tree\n",
3309                                             arg);
3310                             break;
3311                     }
3312 #ifdef LIBXML_XPATH_ENABLED
3313                     xmlXPathFreeObject(list);
3314 #endif
3315                 } else {
3316                     xmlGenericError(xmlGenericErrorContext,
3317                                     "%s: no such node\n", arg);
3318                 }
3319                 ctxt->pctxt->node = NULL;
3320             }
3321 #ifdef LIBXML_OUTPUT_ENABLED
3322         } else if (!strcmp(command, "cat")) {
3323             if (arg[0] == 0) {
3324                 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
3325             } else {
3326                 ctxt->pctxt->node = ctxt->node;
3327 #ifdef LIBXML_XPATH_ENABLED
3328                 ctxt->pctxt->node = ctxt->node;
3329                 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3330 #else
3331                 list = NULL;
3332 #endif /* LIBXML_XPATH_ENABLED */
3333                 if (list != NULL) {
3334                     switch (list->type) {
3335                         case XPATH_UNDEFINED:
3336                             xmlGenericError(xmlGenericErrorContext,
3337                                             "%s: no such node\n", arg);
3338                             break;
3339                         case XPATH_NODESET:{
3340                                 int indx;
3341 
3342 				if (list->nodesetval == NULL)
3343 				    break;
3344 
3345                                 for (indx = 0;
3346                                      indx < list->nodesetval->nodeNr;
3347                                      indx++) {
3348                                     if (i > 0)
3349                                         fprintf(ctxt->output, " -------\n");
3350                                     xmlShellCat(ctxt, NULL,
3351                                                 list->nodesetval->
3352                                                 nodeTab[indx], NULL);
3353                                 }
3354                                 break;
3355                             }
3356                         case XPATH_BOOLEAN:
3357                             xmlGenericError(xmlGenericErrorContext,
3358                                             "%s is a Boolean\n", arg);
3359                             break;
3360                         case XPATH_NUMBER:
3361                             xmlGenericError(xmlGenericErrorContext,
3362                                             "%s is a number\n", arg);
3363                             break;
3364                         case XPATH_STRING:
3365                             xmlGenericError(xmlGenericErrorContext,
3366                                             "%s is a string\n", arg);
3367                             break;
3368                         case XPATH_POINT:
3369                             xmlGenericError(xmlGenericErrorContext,
3370                                             "%s is a point\n", arg);
3371                             break;
3372                         case XPATH_RANGE:
3373                             xmlGenericError(xmlGenericErrorContext,
3374                                             "%s is a range\n", arg);
3375                             break;
3376                         case XPATH_LOCATIONSET:
3377                             xmlGenericError(xmlGenericErrorContext,
3378                                             "%s is a range\n", arg);
3379                             break;
3380                         case XPATH_USERS:
3381                             xmlGenericError(xmlGenericErrorContext,
3382                                             "%s is user-defined\n", arg);
3383                             break;
3384                         case XPATH_XSLT_TREE:
3385                             xmlGenericError(xmlGenericErrorContext,
3386                                             "%s is an XSLT value tree\n",
3387                                             arg);
3388                             break;
3389                     }
3390 #ifdef LIBXML_XPATH_ENABLED
3391                     xmlXPathFreeObject(list);
3392 #endif
3393                 } else {
3394                     xmlGenericError(xmlGenericErrorContext,
3395                                     "%s: no such node\n", arg);
3396                 }
3397                 ctxt->pctxt->node = NULL;
3398             }
3399 #endif /* LIBXML_OUTPUT_ENABLED */
3400         } else {
3401             xmlGenericError(xmlGenericErrorContext,
3402                             "Unknown command %s\n", command);
3403         }
3404         free(cmdline);          /* not xmlFree here ! */
3405 	cmdline = NULL;
3406     }
3407 #ifdef LIBXML_XPATH_ENABLED
3408     xmlXPathFreeContext(ctxt->pctxt);
3409 #endif /* LIBXML_XPATH_ENABLED */
3410     if (ctxt->loaded) {
3411         xmlFreeDoc(ctxt->doc);
3412     }
3413     if (ctxt->filename != NULL)
3414         xmlFree(ctxt->filename);
3415     xmlFree(ctxt);
3416     if (cmdline != NULL)
3417         free(cmdline);          /* not xmlFree here ! */
3418 }
3419 
3420 #endif /* LIBXML_XPATH_ENABLED */
3421 #define bottom_debugXML
3422 #include "elfgcchack.h"
3423 #endif /* LIBXML_DEBUG_ENABLED */
3424