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