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