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