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