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