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