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