source: trunk/third/libxml2/debugXML.c @ 21532

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