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