1/* 2 * debugXML.c : This is a set of routines used for debugging the tree 3 * produced by the XML parser. 4 * 5 * See Copyright for the status of this software. 6 * 7 * Daniel Veillard <daniel@veillard.com> 8 */ 9 10#define IN_LIBXML 11#include "libxml.h" 12#ifdef LIBXML_DEBUG_ENABLED 13 14#include <string.h> 15#ifdef HAVE_STDLIB_H 16#include <stdlib.h> 17#endif 18#ifdef HAVE_STRING_H 19#include <string.h> 20#endif 21#include <libxml/xmlmemory.h> 22#include <libxml/tree.h> 23#include <libxml/parser.h> 24#include <libxml/parserInternals.h> 25#include <libxml/valid.h> 26#include <libxml/debugXML.h> 27#include <libxml/HTMLtree.h> 28#include <libxml/HTMLparser.h> 29#include <libxml/xmlerror.h> 30#include <libxml/globals.h> 31#include <libxml/xpathInternals.h> 32#include <libxml/uri.h> 33#ifdef LIBXML_SCHEMAS_ENABLED 34#include <libxml/relaxng.h> 35#endif 36 37#define DUMP_TEXT_TYPE 1 38 39typedef struct _xmlDebugCtxt xmlDebugCtxt; 40typedef xmlDebugCtxt *xmlDebugCtxtPtr; 41struct _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 54static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node); 55 56static void 57xmlCtxtDumpInitCtxt(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 75static void 76xmlCtxtDumpCleanCtxt(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 */ 92static int 93xmlNsCheckScope(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 137static void 138xmlCtxtDumpSpaces(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 */ 157static void 158xmlDebugErr(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} 167static void 168xmlDebugErr2(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} 177static void 178xmlDebugErr3(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 */ 196static void 197xmlCtxtNsCheckScope(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 */ 229static void 230xmlCtxtCheckString(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 */ 249static void 250xmlCtxtCheckName(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 270static void 271xmlCtxtGenericNodeCheck(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 xmlDebugErr(ctxt, XML_CHECK_NO_NEXT, 325 "Node has no next and not last of parent list\n"); 326 } else { 327 if (node->next->prev != node) 328 xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT, 329 "Node next->prev : forward link wrong\n"); 330 if (node->next->parent != node->parent) 331 xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT, 332 "Node next->prev : forward link wrong\n"); 333 } 334 if (node->type == XML_ELEMENT_NODE) { 335 xmlNsPtr ns; 336 337 ns = node->nsDef; 338 while (ns != NULL) { 339 xmlCtxtNsCheckScope(ctxt, node, ns); 340 ns = ns->next; 341 } 342 if (node->ns != NULL) 343 xmlCtxtNsCheckScope(ctxt, node, node->ns); 344 } else if (node->type == XML_ATTRIBUTE_NODE) { 345 if (node->ns != NULL) 346 xmlCtxtNsCheckScope(ctxt, node, node->ns); 347 } 348 349 if ((node->type != XML_ELEMENT_NODE) && 350 (node->type != XML_ATTRIBUTE_NODE) && 351 (node->type != XML_ELEMENT_DECL) && 352 (node->type != XML_ATTRIBUTE_DECL) && 353 (node->type != XML_DTD_NODE) && 354 (node->type != XML_ELEMENT_DECL) && 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#ifdef LIBXML_DOCB_ENABLED 409 case XML_DOCB_DOCUMENT_NODE: 410#endif 411 case XML_DOCUMENT_NODE: 412 case XML_HTML_DOCUMENT_NODE: 413 break; 414 } 415} 416 417static void 418xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str) 419{ 420 int i; 421 422 if (ctxt->check) { 423 return; 424 } 425 /* TODO: check UTF8 content of the string */ 426 if (str == NULL) { 427 fprintf(ctxt->output, "(NULL)"); 428 return; 429 } 430 for (i = 0; i < 40; i++) 431 if (str[i] == 0) 432 return; 433 else if (IS_BLANK_CH(str[i])) 434 fputc(' ', ctxt->output); 435 else if (str[i] >= 0x80) 436 fprintf(ctxt->output, "#%X", str[i]); 437 else 438 fputc(str[i], ctxt->output); 439 fprintf(ctxt->output, "..."); 440} 441 442static void 443xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd) 444{ 445 xmlCtxtDumpSpaces(ctxt); 446 447 if (dtd == NULL) { 448 if (!ctxt->check) 449 fprintf(ctxt->output, "DTD node is NULL\n"); 450 return; 451 } 452 453 if (dtd->type != XML_DTD_NODE) { 454 xmlDebugErr(ctxt, XML_CHECK_NOT_DTD, 455 "Node is not a DTD"); 456 return; 457 } 458 if (!ctxt->check) { 459 if (dtd->name != NULL) 460 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name); 461 else 462 fprintf(ctxt->output, "DTD"); 463 if (dtd->ExternalID != NULL) 464 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID); 465 if (dtd->SystemID != NULL) 466 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID); 467 fprintf(ctxt->output, "\n"); 468 } 469 /* 470 * Do a bit of checking 471 */ 472 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd); 473} 474 475static void 476xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr) 477{ 478 xmlCtxtDumpSpaces(ctxt); 479 480 if (attr == NULL) { 481 if (!ctxt->check) 482 fprintf(ctxt->output, "Attribute declaration is NULL\n"); 483 return; 484 } 485 if (attr->type != XML_ATTRIBUTE_DECL) { 486 xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL, 487 "Node is not an attribute declaration"); 488 return; 489 } 490 if (attr->name != NULL) { 491 if (!ctxt->check) 492 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name); 493 } else 494 xmlDebugErr(ctxt, XML_CHECK_NO_NAME, 495 "Node attribute declaration has no name"); 496 if (attr->elem != NULL) { 497 if (!ctxt->check) 498 fprintf(ctxt->output, " for %s", (char *) attr->elem); 499 } else 500 xmlDebugErr(ctxt, XML_CHECK_NO_ELEM, 501 "Node attribute declaration has no element name"); 502 if (!ctxt->check) { 503 switch (attr->atype) { 504 case XML_ATTRIBUTE_CDATA: 505 fprintf(ctxt->output, " CDATA"); 506 break; 507 case XML_ATTRIBUTE_ID: 508 fprintf(ctxt->output, " ID"); 509 break; 510 case XML_ATTRIBUTE_IDREF: 511 fprintf(ctxt->output, " IDREF"); 512 break; 513 case XML_ATTRIBUTE_IDREFS: 514 fprintf(ctxt->output, " IDREFS"); 515 break; 516 case XML_ATTRIBUTE_ENTITY: 517 fprintf(ctxt->output, " ENTITY"); 518 break; 519 case XML_ATTRIBUTE_ENTITIES: 520 fprintf(ctxt->output, " ENTITIES"); 521 break; 522 case XML_ATTRIBUTE_NMTOKEN: 523 fprintf(ctxt->output, " NMTOKEN"); 524 break; 525 case XML_ATTRIBUTE_NMTOKENS: 526 fprintf(ctxt->output, " NMTOKENS"); 527 break; 528 case XML_ATTRIBUTE_ENUMERATION: 529 fprintf(ctxt->output, " ENUMERATION"); 530 break; 531 case XML_ATTRIBUTE_NOTATION: 532 fprintf(ctxt->output, " NOTATION "); 533 break; 534 } 535 if (attr->tree != NULL) { 536 int indx; 537 xmlEnumerationPtr cur = attr->tree; 538 539 for (indx = 0; indx < 5; indx++) { 540 if (indx != 0) 541 fprintf(ctxt->output, "|%s", (char *) cur->name); 542 else 543 fprintf(ctxt->output, " (%s", (char *) cur->name); 544 cur = cur->next; 545 if (cur == NULL) 546 break; 547 } 548 if (cur == NULL) 549 fprintf(ctxt->output, ")"); 550 else 551 fprintf(ctxt->output, "...)"); 552 } 553 switch (attr->def) { 554 case XML_ATTRIBUTE_NONE: 555 break; 556 case XML_ATTRIBUTE_REQUIRED: 557 fprintf(ctxt->output, " REQUIRED"); 558 break; 559 case XML_ATTRIBUTE_IMPLIED: 560 fprintf(ctxt->output, " IMPLIED"); 561 break; 562 case XML_ATTRIBUTE_FIXED: 563 fprintf(ctxt->output, " FIXED"); 564 break; 565 } 566 if (attr->defaultValue != NULL) { 567 fprintf(ctxt->output, "\""); 568 xmlCtxtDumpString(ctxt, attr->defaultValue); 569 fprintf(ctxt->output, "\""); 570 } 571 fprintf(ctxt->output, "\n"); 572 } 573 574 /* 575 * Do a bit of checking 576 */ 577 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr); 578} 579 580static void 581xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem) 582{ 583 xmlCtxtDumpSpaces(ctxt); 584 585 if (elem == NULL) { 586 if (!ctxt->check) 587 fprintf(ctxt->output, "Element declaration is NULL\n"); 588 return; 589 } 590 if (elem->type != XML_ELEMENT_DECL) { 591 xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL, 592 "Node is not an element declaration"); 593 return; 594 } 595 if (elem->name != NULL) { 596 if (!ctxt->check) { 597 fprintf(ctxt->output, "ELEMDECL("); 598 xmlCtxtDumpString(ctxt, elem->name); 599 fprintf(ctxt->output, ")"); 600 } 601 } else 602 xmlDebugErr(ctxt, XML_CHECK_NO_NAME, 603 "Element declaration has no name"); 604 if (!ctxt->check) { 605 switch (elem->etype) { 606 case XML_ELEMENT_TYPE_UNDEFINED: 607 fprintf(ctxt->output, ", UNDEFINED"); 608 break; 609 case XML_ELEMENT_TYPE_EMPTY: 610 fprintf(ctxt->output, ", EMPTY"); 611 break; 612 case XML_ELEMENT_TYPE_ANY: 613 fprintf(ctxt->output, ", ANY"); 614 break; 615 case XML_ELEMENT_TYPE_MIXED: 616 fprintf(ctxt->output, ", MIXED "); 617 break; 618 case XML_ELEMENT_TYPE_ELEMENT: 619 fprintf(ctxt->output, ", MIXED "); 620 break; 621 } 622 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) { 623 char buf[5001]; 624 625 buf[0] = 0; 626 xmlSnprintfElementContent(buf, 5000, elem->content, 1); 627 buf[5000] = 0; 628 fprintf(ctxt->output, "%s", buf); 629 } 630 fprintf(ctxt->output, "\n"); 631 } 632 633 /* 634 * Do a bit of checking 635 */ 636 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem); 637} 638 639static void 640xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent) 641{ 642 xmlCtxtDumpSpaces(ctxt); 643 644 if (ent == NULL) { 645 if (!ctxt->check) 646 fprintf(ctxt->output, "Entity declaration is NULL\n"); 647 return; 648 } 649 if (ent->type != XML_ENTITY_DECL) { 650 xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL, 651 "Node is not an entity declaration"); 652 return; 653 } 654 if (ent->name != NULL) { 655 if (!ctxt->check) { 656 fprintf(ctxt->output, "ENTITYDECL("); 657 xmlCtxtDumpString(ctxt, ent->name); 658 fprintf(ctxt->output, ")"); 659 } 660 } else 661 xmlDebugErr(ctxt, XML_CHECK_NO_NAME, 662 "Entity declaration has no name"); 663 if (!ctxt->check) { 664 switch (ent->etype) { 665 case XML_INTERNAL_GENERAL_ENTITY: 666 fprintf(ctxt->output, ", internal\n"); 667 break; 668 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 669 fprintf(ctxt->output, ", external parsed\n"); 670 break; 671 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 672 fprintf(ctxt->output, ", unparsed\n"); 673 break; 674 case XML_INTERNAL_PARAMETER_ENTITY: 675 fprintf(ctxt->output, ", parameter\n"); 676 break; 677 case XML_EXTERNAL_PARAMETER_ENTITY: 678 fprintf(ctxt->output, ", external parameter\n"); 679 break; 680 case XML_INTERNAL_PREDEFINED_ENTITY: 681 fprintf(ctxt->output, ", predefined\n"); 682 break; 683 } 684 if (ent->ExternalID) { 685 xmlCtxtDumpSpaces(ctxt); 686 fprintf(ctxt->output, " ExternalID=%s\n", 687 (char *) ent->ExternalID); 688 } 689 if (ent->SystemID) { 690 xmlCtxtDumpSpaces(ctxt); 691 fprintf(ctxt->output, " SystemID=%s\n", 692 (char *) ent->SystemID); 693 } 694 if (ent->URI != NULL) { 695 xmlCtxtDumpSpaces(ctxt); 696 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI); 697 } 698 if (ent->content) { 699 xmlCtxtDumpSpaces(ctxt); 700 fprintf(ctxt->output, " content="); 701 xmlCtxtDumpString(ctxt, ent->content); 702 fprintf(ctxt->output, "\n"); 703 } 704 } 705 706 /* 707 * Do a bit of checking 708 */ 709 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent); 710} 711 712static void 713xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns) 714{ 715 xmlCtxtDumpSpaces(ctxt); 716 717 if (ns == NULL) { 718 if (!ctxt->check) 719 fprintf(ctxt->output, "namespace node is NULL\n"); 720 return; 721 } 722 if (ns->type != XML_NAMESPACE_DECL) { 723 xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL, 724 "Node is not a namespace declaration"); 725 return; 726 } 727 if (ns->href == NULL) { 728 if (ns->prefix != NULL) 729 xmlDebugErr3(ctxt, XML_CHECK_NO_HREF, 730 "Incomplete namespace %s href=NULL\n", 731 (char *) ns->prefix); 732 else 733 xmlDebugErr(ctxt, XML_CHECK_NO_HREF, 734 "Incomplete default namespace href=NULL\n"); 735 } else { 736 if (!ctxt->check) { 737 if (ns->prefix != NULL) 738 fprintf(ctxt->output, "namespace %s href=", 739 (char *) ns->prefix); 740 else 741 fprintf(ctxt->output, "default namespace href="); 742 743 xmlCtxtDumpString(ctxt, ns->href); 744 fprintf(ctxt->output, "\n"); 745 } 746 } 747} 748 749static void 750xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns) 751{ 752 while (ns != NULL) { 753 xmlCtxtDumpNamespace(ctxt, ns); 754 ns = ns->next; 755 } 756} 757 758static void 759xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent) 760{ 761 xmlCtxtDumpSpaces(ctxt); 762 763 if (ent == NULL) { 764 if (!ctxt->check) 765 fprintf(ctxt->output, "Entity is NULL\n"); 766 return; 767 } 768 if (!ctxt->check) { 769 switch (ent->etype) { 770 case XML_INTERNAL_GENERAL_ENTITY: 771 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY "); 772 break; 773 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 774 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY "); 775 break; 776 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 777 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY "); 778 break; 779 case XML_INTERNAL_PARAMETER_ENTITY: 780 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY "); 781 break; 782 case XML_EXTERNAL_PARAMETER_ENTITY: 783 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY "); 784 break; 785 default: 786 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype); 787 } 788 fprintf(ctxt->output, "%s\n", ent->name); 789 if (ent->ExternalID) { 790 xmlCtxtDumpSpaces(ctxt); 791 fprintf(ctxt->output, "ExternalID=%s\n", 792 (char *) ent->ExternalID); 793 } 794 if (ent->SystemID) { 795 xmlCtxtDumpSpaces(ctxt); 796 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID); 797 } 798 if (ent->URI) { 799 xmlCtxtDumpSpaces(ctxt); 800 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI); 801 } 802 if (ent->content) { 803 xmlCtxtDumpSpaces(ctxt); 804 fprintf(ctxt->output, "content="); 805 xmlCtxtDumpString(ctxt, ent->content); 806 fprintf(ctxt->output, "\n"); 807 } 808 } 809} 810 811/** 812 * xmlCtxtDumpAttr: 813 * @output: the FILE * for the output 814 * @attr: the attribute 815 * @depth: the indentation level. 816 * 817 * Dumps debug information for the attribute 818 */ 819static void 820xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr) 821{ 822 xmlCtxtDumpSpaces(ctxt); 823 824 if (attr == NULL) { 825 if (!ctxt->check) 826 fprintf(ctxt->output, "Attr is NULL"); 827 return; 828 } 829 if (!ctxt->check) { 830 fprintf(ctxt->output, "ATTRIBUTE "); 831 xmlCtxtDumpString(ctxt, attr->name); 832 fprintf(ctxt->output, "\n"); 833 if (attr->children != NULL) { 834 ctxt->depth++; 835 xmlCtxtDumpNodeList(ctxt, attr->children); 836 ctxt->depth--; 837 } 838 } 839 if (attr->name == NULL) 840 xmlDebugErr(ctxt, XML_CHECK_NO_NAME, 841 "Attribute has no name"); 842 843 /* 844 * Do a bit of checking 845 */ 846 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr); 847} 848 849/** 850 * xmlCtxtDumpAttrList: 851 * @output: the FILE * for the output 852 * @attr: the attribute list 853 * @depth: the indentation level. 854 * 855 * Dumps debug information for the attribute list 856 */ 857static void 858xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr) 859{ 860 while (attr != NULL) { 861 xmlCtxtDumpAttr(ctxt, attr); 862 attr = attr->next; 863 } 864} 865 866/** 867 * xmlCtxtDumpOneNode: 868 * @output: the FILE * for the output 869 * @node: the node 870 * @depth: the indentation level. 871 * 872 * Dumps debug information for the element node, it is not recursive 873 */ 874static void 875xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node) 876{ 877 if (node == NULL) { 878 if (!ctxt->check) { 879 xmlCtxtDumpSpaces(ctxt); 880 fprintf(ctxt->output, "node is NULL\n"); 881 } 882 return; 883 } 884 ctxt->node = node; 885 886 switch (node->type) { 887 case XML_ELEMENT_NODE: 888 if (!ctxt->check) { 889 xmlCtxtDumpSpaces(ctxt); 890 fprintf(ctxt->output, "ELEMENT "); 891 if ((node->ns != NULL) && (node->ns->prefix != NULL)) { 892 xmlCtxtDumpString(ctxt, node->ns->prefix); 893 fprintf(ctxt->output, ":"); 894 } 895 xmlCtxtDumpString(ctxt, node->name); 896 fprintf(ctxt->output, "\n"); 897 } 898 break; 899 case XML_ATTRIBUTE_NODE: 900 if (!ctxt->check) 901 xmlCtxtDumpSpaces(ctxt); 902 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n"); 903 xmlCtxtGenericNodeCheck(ctxt, node); 904 return; 905 case XML_TEXT_NODE: 906 if (!ctxt->check) { 907 xmlCtxtDumpSpaces(ctxt); 908 if (node->name == (const xmlChar *) xmlStringTextNoenc) 909 fprintf(ctxt->output, "TEXT no enc"); 910 else 911 fprintf(ctxt->output, "TEXT"); 912 if (ctxt->options & DUMP_TEXT_TYPE) { 913 if (node->content == (xmlChar *) &(node->properties)) 914 fprintf(ctxt->output, " compact\n"); 915 else if (xmlDictOwns(ctxt->dict, node->content) == 1) 916 fprintf(ctxt->output, " interned\n"); 917 else 918 fprintf(ctxt->output, "\n"); 919 } else 920 fprintf(ctxt->output, "\n"); 921 } 922 break; 923 case XML_CDATA_SECTION_NODE: 924 if (!ctxt->check) { 925 xmlCtxtDumpSpaces(ctxt); 926 fprintf(ctxt->output, "CDATA_SECTION\n"); 927 } 928 break; 929 case XML_ENTITY_REF_NODE: 930 if (!ctxt->check) { 931 xmlCtxtDumpSpaces(ctxt); 932 fprintf(ctxt->output, "ENTITY_REF(%s)\n", 933 (char *) node->name); 934 } 935 break; 936 case XML_ENTITY_NODE: 937 if (!ctxt->check) { 938 xmlCtxtDumpSpaces(ctxt); 939 fprintf(ctxt->output, "ENTITY\n"); 940 } 941 break; 942 case XML_PI_NODE: 943 if (!ctxt->check) { 944 xmlCtxtDumpSpaces(ctxt); 945 fprintf(ctxt->output, "PI %s\n", (char *) node->name); 946 } 947 break; 948 case XML_COMMENT_NODE: 949 if (!ctxt->check) { 950 xmlCtxtDumpSpaces(ctxt); 951 fprintf(ctxt->output, "COMMENT\n"); 952 } 953 break; 954 case XML_DOCUMENT_NODE: 955 case XML_HTML_DOCUMENT_NODE: 956 if (!ctxt->check) { 957 xmlCtxtDumpSpaces(ctxt); 958 } 959 fprintf(ctxt->output, "Error, DOCUMENT found here\n"); 960 xmlCtxtGenericNodeCheck(ctxt, node); 961 return; 962 case XML_DOCUMENT_TYPE_NODE: 963 if (!ctxt->check) { 964 xmlCtxtDumpSpaces(ctxt); 965 fprintf(ctxt->output, "DOCUMENT_TYPE\n"); 966 } 967 break; 968 case XML_DOCUMENT_FRAG_NODE: 969 if (!ctxt->check) { 970 xmlCtxtDumpSpaces(ctxt); 971 fprintf(ctxt->output, "DOCUMENT_FRAG\n"); 972 } 973 break; 974 case XML_NOTATION_NODE: 975 if (!ctxt->check) { 976 xmlCtxtDumpSpaces(ctxt); 977 fprintf(ctxt->output, "NOTATION\n"); 978 } 979 break; 980 case XML_DTD_NODE: 981 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node); 982 return; 983 case XML_ELEMENT_DECL: 984 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node); 985 return; 986 case XML_ATTRIBUTE_DECL: 987 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node); 988 return; 989 case XML_ENTITY_DECL: 990 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node); 991 return; 992 case XML_NAMESPACE_DECL: 993 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node); 994 return; 995 case XML_XINCLUDE_START: 996 if (!ctxt->check) { 997 xmlCtxtDumpSpaces(ctxt); 998 fprintf(ctxt->output, "INCLUDE START\n"); 999 } 1000 return; 1001 case XML_XINCLUDE_END: 1002 if (!ctxt->check) { 1003 xmlCtxtDumpSpaces(ctxt); 1004 fprintf(ctxt->output, "INCLUDE END\n"); 1005 } 1006 return; 1007 default: 1008 if (!ctxt->check) 1009 xmlCtxtDumpSpaces(ctxt); 1010 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE, 1011 "Unknown node type %d\n", node->type); 1012 return; 1013 } 1014 if (node->doc == NULL) { 1015 if (!ctxt->check) { 1016 xmlCtxtDumpSpaces(ctxt); 1017 } 1018 fprintf(ctxt->output, "PBM: doc == NULL !!!\n"); 1019 } 1020 ctxt->depth++; 1021 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL)) 1022 xmlCtxtDumpNamespaceList(ctxt, node->nsDef); 1023 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) 1024 xmlCtxtDumpAttrList(ctxt, node->properties); 1025 if (node->type != XML_ENTITY_REF_NODE) { 1026 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) { 1027 if (!ctxt->check) { 1028 xmlCtxtDumpSpaces(ctxt); 1029 fprintf(ctxt->output, "content="); 1030 xmlCtxtDumpString(ctxt, node->content); 1031 fprintf(ctxt->output, "\n"); 1032 } 1033 } 1034 } else { 1035 xmlEntityPtr ent; 1036 1037 ent = xmlGetDocEntity(node->doc, node->name); 1038 if (ent != NULL) 1039 xmlCtxtDumpEntity(ctxt, ent); 1040 } 1041 ctxt->depth--; 1042 1043 /* 1044 * Do a bit of checking 1045 */ 1046 xmlCtxtGenericNodeCheck(ctxt, node); 1047} 1048 1049/** 1050 * xmlCtxtDumpNode: 1051 * @output: the FILE * for the output 1052 * @node: the node 1053 * @depth: the indentation level. 1054 * 1055 * Dumps debug information for the element node, it is recursive 1056 */ 1057static void 1058xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node) 1059{ 1060 if (node == NULL) { 1061 if (!ctxt->check) { 1062 xmlCtxtDumpSpaces(ctxt); 1063 fprintf(ctxt->output, "node is NULL\n"); 1064 } 1065 return; 1066 } 1067 xmlCtxtDumpOneNode(ctxt, node); 1068 if ((node->type != XML_NAMESPACE_DECL) && 1069 (node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { 1070 ctxt->depth++; 1071 xmlCtxtDumpNodeList(ctxt, node->children); 1072 ctxt->depth--; 1073 } 1074} 1075 1076/** 1077 * xmlCtxtDumpNodeList: 1078 * @output: the FILE * for the output 1079 * @node: the node list 1080 * @depth: the indentation level. 1081 * 1082 * Dumps debug information for the list of element node, it is recursive 1083 */ 1084static void 1085xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node) 1086{ 1087 while (node != NULL) { 1088 xmlCtxtDumpNode(ctxt, node); 1089 node = node->next; 1090 } 1091} 1092 1093static void 1094xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc) 1095{ 1096 if (doc == NULL) { 1097 if (!ctxt->check) 1098 fprintf(ctxt->output, "DOCUMENT == NULL !\n"); 1099 return; 1100 } 1101 ctxt->node = (xmlNodePtr) doc; 1102 1103 switch (doc->type) { 1104 case XML_ELEMENT_NODE: 1105 xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT, 1106 "Misplaced ELEMENT node\n"); 1107 break; 1108 case XML_ATTRIBUTE_NODE: 1109 xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE, 1110 "Misplaced ATTRIBUTE node\n"); 1111 break; 1112 case XML_TEXT_NODE: 1113 xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT, 1114 "Misplaced TEXT node\n"); 1115 break; 1116 case XML_CDATA_SECTION_NODE: 1117 xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA, 1118 "Misplaced CDATA node\n"); 1119 break; 1120 case XML_ENTITY_REF_NODE: 1121 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF, 1122 "Misplaced ENTITYREF node\n"); 1123 break; 1124 case XML_ENTITY_NODE: 1125 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY, 1126 "Misplaced ENTITY node\n"); 1127 break; 1128 case XML_PI_NODE: 1129 xmlDebugErr(ctxt, XML_CHECK_FOUND_PI, 1130 "Misplaced PI node\n"); 1131 break; 1132 case XML_COMMENT_NODE: 1133 xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT, 1134 "Misplaced COMMENT node\n"); 1135 break; 1136 case XML_DOCUMENT_NODE: 1137 if (!ctxt->check) 1138 fprintf(ctxt->output, "DOCUMENT\n"); 1139 break; 1140 case XML_HTML_DOCUMENT_NODE: 1141 if (!ctxt->check) 1142 fprintf(ctxt->output, "HTML DOCUMENT\n"); 1143 break; 1144 case XML_DOCUMENT_TYPE_NODE: 1145 xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE, 1146 "Misplaced DOCTYPE node\n"); 1147 break; 1148 case XML_DOCUMENT_FRAG_NODE: 1149 xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT, 1150 "Misplaced FRAGMENT node\n"); 1151 break; 1152 case XML_NOTATION_NODE: 1153 xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION, 1154 "Misplaced NOTATION node\n"); 1155 break; 1156 default: 1157 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE, 1158 "Unknown node type %d\n", doc->type); 1159 } 1160} 1161 1162/** 1163 * xmlCtxtDumpDocumentHead: 1164 * @output: the FILE * for the output 1165 * @doc: the document 1166 * 1167 * Dumps debug information cncerning the document, not recursive 1168 */ 1169static void 1170xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc) 1171{ 1172 if (doc == NULL) return; 1173 xmlCtxtDumpDocHead(ctxt, doc); 1174 if (!ctxt->check) { 1175 if (doc->name != NULL) { 1176 fprintf(ctxt->output, "name="); 1177 xmlCtxtDumpString(ctxt, BAD_CAST doc->name); 1178 fprintf(ctxt->output, "\n"); 1179 } 1180 if (doc->version != NULL) { 1181 fprintf(ctxt->output, "version="); 1182 xmlCtxtDumpString(ctxt, doc->version); 1183 fprintf(ctxt->output, "\n"); 1184 } 1185 if (doc->encoding != NULL) { 1186 fprintf(ctxt->output, "encoding="); 1187 xmlCtxtDumpString(ctxt, doc->encoding); 1188 fprintf(ctxt->output, "\n"); 1189 } 1190 if (doc->URL != NULL) { 1191 fprintf(ctxt->output, "URL="); 1192 xmlCtxtDumpString(ctxt, doc->URL); 1193 fprintf(ctxt->output, "\n"); 1194 } 1195 if (doc->standalone) 1196 fprintf(ctxt->output, "standalone=true\n"); 1197 } 1198 if (doc->oldNs != NULL) 1199 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs); 1200} 1201 1202/** 1203 * xmlCtxtDumpDocument: 1204 * @output: the FILE * for the output 1205 * @doc: the document 1206 * 1207 * Dumps debug information for the document, it's recursive 1208 */ 1209static void 1210xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc) 1211{ 1212 if (doc == NULL) { 1213 if (!ctxt->check) 1214 fprintf(ctxt->output, "DOCUMENT == NULL !\n"); 1215 return; 1216 } 1217 xmlCtxtDumpDocumentHead(ctxt, doc); 1218 if (((doc->type == XML_DOCUMENT_NODE) || 1219 (doc->type == XML_HTML_DOCUMENT_NODE)) 1220 && (doc->children != NULL)) { 1221 ctxt->depth++; 1222 xmlCtxtDumpNodeList(ctxt, doc->children); 1223 ctxt->depth--; 1224 } 1225} 1226 1227static void 1228xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt) 1229{ 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 */ 1277static void 1278xmlCtxtDumpEntities(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, (xmlHashScanner) xmlCtxtDumpEntityCallback, 1289 ctxt); 1290 } else 1291 fprintf(ctxt->output, "No entities in internal subset\n"); 1292 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) { 1293 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 1294 doc->extSubset->entities; 1295 1296 if (!ctxt->check) 1297 fprintf(ctxt->output, "Entities in external subset\n"); 1298 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback, 1299 ctxt); 1300 } else if (!ctxt->check) 1301 fprintf(ctxt->output, "No entities in external subset\n"); 1302} 1303 1304/** 1305 * xmlCtxtDumpDTD: 1306 * @output: the FILE * for the output 1307 * @dtd: the DTD 1308 * 1309 * Dumps debug information for the DTD 1310 */ 1311static void 1312xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd) 1313{ 1314 if (dtd == NULL) { 1315 if (!ctxt->check) 1316 fprintf(ctxt->output, "DTD is NULL\n"); 1317 return; 1318 } 1319 xmlCtxtDumpDtdNode(ctxt, dtd); 1320 if (dtd->children == NULL) 1321 fprintf(ctxt->output, " DTD is empty\n"); 1322 else { 1323 ctxt->depth++; 1324 xmlCtxtDumpNodeList(ctxt, dtd->children); 1325 ctxt->depth--; 1326 } 1327} 1328 1329/************************************************************************ 1330 * * 1331 * Public entry points for dump * 1332 * * 1333 ************************************************************************/ 1334 1335/** 1336 * xmlDebugDumpString: 1337 * @output: the FILE * for the output 1338 * @str: the string 1339 * 1340 * Dumps informations about the string, shorten it if necessary 1341 */ 1342void 1343xmlDebugDumpString(FILE * output, const xmlChar * str) 1344{ 1345 int i; 1346 1347 if (output == NULL) 1348 output = stdout; 1349 if (str == NULL) { 1350 fprintf(output, "(NULL)"); 1351 return; 1352 } 1353 for (i = 0; i < 40; i++) 1354 if (str[i] == 0) 1355 return; 1356 else if (IS_BLANK_CH(str[i])) 1357 fputc(' ', output); 1358 else if (str[i] >= 0x80) 1359 fprintf(output, "#%X", str[i]); 1360 else 1361 fputc(str[i], output); 1362 fprintf(output, "..."); 1363} 1364 1365/** 1366 * xmlDebugDumpAttr: 1367 * @output: the FILE * for the output 1368 * @attr: the attribute 1369 * @depth: the indentation level. 1370 * 1371 * Dumps debug information for the attribute 1372 */ 1373void 1374xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) { 1375 xmlDebugCtxt ctxt; 1376 1377 if (output == NULL) return; 1378 xmlCtxtDumpInitCtxt(&ctxt); 1379 ctxt.output = output; 1380 ctxt.depth = depth; 1381 xmlCtxtDumpAttr(&ctxt, attr); 1382 xmlCtxtDumpCleanCtxt(&ctxt); 1383} 1384 1385 1386/** 1387 * xmlDebugDumpEntities: 1388 * @output: the FILE * for the output 1389 * @doc: the document 1390 * 1391 * Dumps debug information for all the entities in use by the document 1392 */ 1393void 1394xmlDebugDumpEntities(FILE * output, xmlDocPtr doc) 1395{ 1396 xmlDebugCtxt ctxt; 1397 1398 if (output == NULL) return; 1399 xmlCtxtDumpInitCtxt(&ctxt); 1400 ctxt.output = output; 1401 xmlCtxtDumpEntities(&ctxt, doc); 1402 xmlCtxtDumpCleanCtxt(&ctxt); 1403} 1404 1405/** 1406 * xmlDebugDumpAttrList: 1407 * @output: the FILE * for the output 1408 * @attr: the attribute list 1409 * @depth: the indentation level. 1410 * 1411 * Dumps debug information for the attribute list 1412 */ 1413void 1414xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth) 1415{ 1416 xmlDebugCtxt ctxt; 1417 1418 if (output == NULL) return; 1419 xmlCtxtDumpInitCtxt(&ctxt); 1420 ctxt.output = output; 1421 ctxt.depth = depth; 1422 xmlCtxtDumpAttrList(&ctxt, attr); 1423 xmlCtxtDumpCleanCtxt(&ctxt); 1424} 1425 1426/** 1427 * xmlDebugDumpOneNode: 1428 * @output: the FILE * for the output 1429 * @node: the node 1430 * @depth: the indentation level. 1431 * 1432 * Dumps debug information for the element node, it is not recursive 1433 */ 1434void 1435xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth) 1436{ 1437 xmlDebugCtxt ctxt; 1438 1439 if (output == NULL) return; 1440 xmlCtxtDumpInitCtxt(&ctxt); 1441 ctxt.output = output; 1442 ctxt.depth = depth; 1443 xmlCtxtDumpOneNode(&ctxt, node); 1444 xmlCtxtDumpCleanCtxt(&ctxt); 1445} 1446 1447/** 1448 * xmlDebugDumpNode: 1449 * @output: the FILE * for the output 1450 * @node: the node 1451 * @depth: the indentation level. 1452 * 1453 * Dumps debug information for the element node, it is recursive 1454 */ 1455void 1456xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth) 1457{ 1458 xmlDebugCtxt ctxt; 1459 1460 if (output == NULL) 1461 output = stdout; 1462 xmlCtxtDumpInitCtxt(&ctxt); 1463 ctxt.output = output; 1464 ctxt.depth = depth; 1465 xmlCtxtDumpNode(&ctxt, node); 1466 xmlCtxtDumpCleanCtxt(&ctxt); 1467} 1468 1469/** 1470 * xmlDebugDumpNodeList: 1471 * @output: the FILE * for the output 1472 * @node: the node list 1473 * @depth: the indentation level. 1474 * 1475 * Dumps debug information for the list of element node, it is recursive 1476 */ 1477void 1478xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth) 1479{ 1480 xmlDebugCtxt ctxt; 1481 1482 if (output == NULL) 1483 output = stdout; 1484 xmlCtxtDumpInitCtxt(&ctxt); 1485 ctxt.output = output; 1486 ctxt.depth = depth; 1487 xmlCtxtDumpNodeList(&ctxt, node); 1488 xmlCtxtDumpCleanCtxt(&ctxt); 1489} 1490 1491/** 1492 * xmlDebugDumpDocumentHead: 1493 * @output: the FILE * for the output 1494 * @doc: the document 1495 * 1496 * Dumps debug information cncerning the document, not recursive 1497 */ 1498void 1499xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc) 1500{ 1501 xmlDebugCtxt ctxt; 1502 1503 if (output == NULL) 1504 output = stdout; 1505 xmlCtxtDumpInitCtxt(&ctxt); 1506 ctxt.options |= DUMP_TEXT_TYPE; 1507 ctxt.output = output; 1508 xmlCtxtDumpDocumentHead(&ctxt, doc); 1509 xmlCtxtDumpCleanCtxt(&ctxt); 1510} 1511 1512/** 1513 * xmlDebugDumpDocument: 1514 * @output: the FILE * for the output 1515 * @doc: the document 1516 * 1517 * Dumps debug information for the document, it's recursive 1518 */ 1519void 1520xmlDebugDumpDocument(FILE * output, xmlDocPtr doc) 1521{ 1522 xmlDebugCtxt ctxt; 1523 1524 if (output == NULL) 1525 output = stdout; 1526 xmlCtxtDumpInitCtxt(&ctxt); 1527 ctxt.options |= DUMP_TEXT_TYPE; 1528 ctxt.output = output; 1529 xmlCtxtDumpDocument(&ctxt, doc); 1530 xmlCtxtDumpCleanCtxt(&ctxt); 1531} 1532 1533/** 1534 * xmlDebugDumpDTD: 1535 * @output: the FILE * for the output 1536 * @dtd: the DTD 1537 * 1538 * Dumps debug information for the DTD 1539 */ 1540void 1541xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd) 1542{ 1543 xmlDebugCtxt ctxt; 1544 1545 if (output == NULL) 1546 output = stdout; 1547 xmlCtxtDumpInitCtxt(&ctxt); 1548 ctxt.options |= DUMP_TEXT_TYPE; 1549 ctxt.output = output; 1550 xmlCtxtDumpDTD(&ctxt, dtd); 1551 xmlCtxtDumpCleanCtxt(&ctxt); 1552} 1553 1554/************************************************************************ 1555 * * 1556 * Public entry points for checkings * 1557 * * 1558 ************************************************************************/ 1559 1560/** 1561 * xmlDebugCheckDocument: 1562 * @output: the FILE * for the output 1563 * @doc: the document 1564 * 1565 * Check the document for potential content problems, and output 1566 * the errors to @output 1567 * 1568 * Returns the number of errors found 1569 */ 1570int 1571xmlDebugCheckDocument(FILE * output, xmlDocPtr doc) 1572{ 1573 xmlDebugCtxt ctxt; 1574 1575 if (output == NULL) 1576 output = stdout; 1577 xmlCtxtDumpInitCtxt(&ctxt); 1578 ctxt.output = output; 1579 ctxt.check = 1; 1580 xmlCtxtDumpDocument(&ctxt, doc); 1581 xmlCtxtDumpCleanCtxt(&ctxt); 1582 return(ctxt.errors); 1583} 1584 1585/************************************************************************ 1586 * * 1587 * Helpers for Shell * 1588 * * 1589 ************************************************************************/ 1590 1591/** 1592 * xmlLsCountNode: 1593 * @node: the node to count 1594 * 1595 * Count the children of @node. 1596 * 1597 * Returns the number of children of @node. 1598 */ 1599int 1600xmlLsCountNode(xmlNodePtr node) { 1601 int ret = 0; 1602 xmlNodePtr list = NULL; 1603 1604 if (node == NULL) 1605 return(0); 1606 1607 switch (node->type) { 1608 case XML_ELEMENT_NODE: 1609 list = node->children; 1610 break; 1611 case XML_DOCUMENT_NODE: 1612 case XML_HTML_DOCUMENT_NODE: 1613#ifdef LIBXML_DOCB_ENABLED 1614 case XML_DOCB_DOCUMENT_NODE: 1615#endif 1616 list = ((xmlDocPtr) node)->children; 1617 break; 1618 case XML_ATTRIBUTE_NODE: 1619 list = ((xmlAttrPtr) node)->children; 1620 break; 1621 case XML_TEXT_NODE: 1622 case XML_CDATA_SECTION_NODE: 1623 case XML_PI_NODE: 1624 case XML_COMMENT_NODE: 1625 if (node->content != NULL) { 1626 ret = xmlStrlen(node->content); 1627 } 1628 break; 1629 case XML_ENTITY_REF_NODE: 1630 case XML_DOCUMENT_TYPE_NODE: 1631 case XML_ENTITY_NODE: 1632 case XML_DOCUMENT_FRAG_NODE: 1633 case XML_NOTATION_NODE: 1634 case XML_DTD_NODE: 1635 case XML_ELEMENT_DECL: 1636 case XML_ATTRIBUTE_DECL: 1637 case XML_ENTITY_DECL: 1638 case XML_NAMESPACE_DECL: 1639 case XML_XINCLUDE_START: 1640 case XML_XINCLUDE_END: 1641 ret = 1; 1642 break; 1643 } 1644 for (;list != NULL;ret++) 1645 list = list->next; 1646 return(ret); 1647} 1648 1649/** 1650 * xmlLsOneNode: 1651 * @output: the FILE * for the output 1652 * @node: the node to dump 1653 * 1654 * Dump to @output the type and name of @node. 1655 */ 1656void 1657xmlLsOneNode(FILE *output, xmlNodePtr node) { 1658 if (output == NULL) return; 1659 if (node == NULL) { 1660 fprintf(output, "NULL\n"); 1661 return; 1662 } 1663 switch (node->type) { 1664 case XML_ELEMENT_NODE: 1665 fprintf(output, "-"); 1666 break; 1667 case XML_ATTRIBUTE_NODE: 1668 fprintf(output, "a"); 1669 break; 1670 case XML_TEXT_NODE: 1671 fprintf(output, "t"); 1672 break; 1673 case XML_CDATA_SECTION_NODE: 1674 fprintf(output, "C"); 1675 break; 1676 case XML_ENTITY_REF_NODE: 1677 fprintf(output, "e"); 1678 break; 1679 case XML_ENTITY_NODE: 1680 fprintf(output, "E"); 1681 break; 1682 case XML_PI_NODE: 1683 fprintf(output, "p"); 1684 break; 1685 case XML_COMMENT_NODE: 1686 fprintf(output, "c"); 1687 break; 1688 case XML_DOCUMENT_NODE: 1689 fprintf(output, "d"); 1690 break; 1691 case XML_HTML_DOCUMENT_NODE: 1692 fprintf(output, "h"); 1693 break; 1694 case XML_DOCUMENT_TYPE_NODE: 1695 fprintf(output, "T"); 1696 break; 1697 case XML_DOCUMENT_FRAG_NODE: 1698 fprintf(output, "F"); 1699 break; 1700 case XML_NOTATION_NODE: 1701 fprintf(output, "N"); 1702 break; 1703 case XML_NAMESPACE_DECL: 1704 fprintf(output, "n"); 1705 break; 1706 default: 1707 fprintf(output, "?"); 1708 } 1709 if (node->type != XML_NAMESPACE_DECL) { 1710 if (node->properties != NULL) 1711 fprintf(output, "a"); 1712 else 1713 fprintf(output, "-"); 1714 if (node->nsDef != NULL) 1715 fprintf(output, "n"); 1716 else 1717 fprintf(output, "-"); 1718 } 1719 1720 fprintf(output, " %8d ", xmlLsCountNode(node)); 1721 1722 switch (node->type) { 1723 case XML_ELEMENT_NODE: 1724 if (node->name != NULL) 1725 fprintf(output, "%s", (const char *) node->name); 1726 break; 1727 case XML_ATTRIBUTE_NODE: 1728 if (node->name != NULL) 1729 fprintf(output, "%s", (const char *) node->name); 1730 break; 1731 case XML_TEXT_NODE: 1732 if (node->content != NULL) { 1733 xmlDebugDumpString(output, node->content); 1734 } 1735 break; 1736 case XML_CDATA_SECTION_NODE: 1737 break; 1738 case XML_ENTITY_REF_NODE: 1739 if (node->name != NULL) 1740 fprintf(output, "%s", (const char *) node->name); 1741 break; 1742 case XML_ENTITY_NODE: 1743 if (node->name != NULL) 1744 fprintf(output, "%s", (const char *) node->name); 1745 break; 1746 case XML_PI_NODE: 1747 if (node->name != NULL) 1748 fprintf(output, "%s", (const char *) node->name); 1749 break; 1750 case XML_COMMENT_NODE: 1751 break; 1752 case XML_DOCUMENT_NODE: 1753 break; 1754 case XML_HTML_DOCUMENT_NODE: 1755 break; 1756 case XML_DOCUMENT_TYPE_NODE: 1757 break; 1758 case XML_DOCUMENT_FRAG_NODE: 1759 break; 1760 case XML_NOTATION_NODE: 1761 break; 1762 case XML_NAMESPACE_DECL: { 1763 xmlNsPtr ns = (xmlNsPtr) node; 1764 1765 if (ns->prefix == NULL) 1766 fprintf(output, "default -> %s", (char *)ns->href); 1767 else 1768 fprintf(output, "%s -> %s", (char *)ns->prefix, 1769 (char *)ns->href); 1770 break; 1771 } 1772 default: 1773 if (node->name != NULL) 1774 fprintf(output, "%s", (const char *) node->name); 1775 } 1776 fprintf(output, "\n"); 1777} 1778 1779/** 1780 * xmlBoolToText: 1781 * @boolval: a bool to turn into text 1782 * 1783 * Convenient way to turn bool into text 1784 * 1785 * Returns a pointer to either "True" or "False" 1786 */ 1787const char * 1788xmlBoolToText(int boolval) 1789{ 1790 if (boolval) 1791 return("True"); 1792 else 1793 return("False"); 1794} 1795 1796#ifdef LIBXML_XPATH_ENABLED 1797/**************************************************************** 1798 * * 1799 * The XML shell related functions * 1800 * * 1801 ****************************************************************/ 1802 1803 1804 1805/* 1806 * TODO: Improvement/cleanups for the XML shell 1807 * - allow to shell out an editor on a subpart 1808 * - cleanup function registrations (with help) and calling 1809 * - provide registration routines 1810 */ 1811 1812/** 1813 * xmlShellPrintXPathError: 1814 * @errorType: valid xpath error id 1815 * @arg: the argument that cause xpath to fail 1816 * 1817 * Print the xpath error to libxml default error channel 1818 */ 1819void 1820xmlShellPrintXPathError(int errorType, const char *arg) 1821{ 1822 const char *default_arg = "Result"; 1823 1824 if (!arg) 1825 arg = default_arg; 1826 1827 switch (errorType) { 1828 case XPATH_UNDEFINED: 1829 xmlGenericError(xmlGenericErrorContext, 1830 "%s: no such node\n", arg); 1831 break; 1832 1833 case XPATH_BOOLEAN: 1834 xmlGenericError(xmlGenericErrorContext, 1835 "%s is a Boolean\n", arg); 1836 break; 1837 case XPATH_NUMBER: 1838 xmlGenericError(xmlGenericErrorContext, 1839 "%s is a number\n", arg); 1840 break; 1841 case XPATH_STRING: 1842 xmlGenericError(xmlGenericErrorContext, 1843 "%s is a string\n", arg); 1844 break; 1845 case XPATH_POINT: 1846 xmlGenericError(xmlGenericErrorContext, 1847 "%s is a point\n", arg); 1848 break; 1849 case XPATH_RANGE: 1850 xmlGenericError(xmlGenericErrorContext, 1851 "%s is a range\n", arg); 1852 break; 1853 case XPATH_LOCATIONSET: 1854 xmlGenericError(xmlGenericErrorContext, 1855 "%s is a range\n", arg); 1856 break; 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 */ 1882static void 1883xmlShellPrintNodeCtxt(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 */ 1910void 1911xmlShellPrintNode(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 */ 1924static void 1925xmlShellPrintXPathResultCtxt(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 */ 1978void 1979xmlShellPrintXPathResult(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 */ 1996int 1997xmlShellList(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 */ 2039int 2040xmlShellBase(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 */ 2076static int 2077xmlShellSetBase(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 */ 2100static int 2101xmlShellRegisterNamespace(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 */ 2156static int 2157xmlShellRegisterRootNamespaces(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 informations about the node (namespace, attributes, content). 2186 * 2187 * Returns 0 2188 */ 2189static int 2190xmlShellGrep(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 informations about the node (namespace, attributes, content). 2264 * 2265 * Returns 0 2266 */ 2267int 2268xmlShellDir(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 informations about the node (namespace, attributes, content). 2298 * 2299 * Returns 0 2300 */ 2301static int 2302xmlShellSetContent(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 */ 2347static int 2348xmlShellRNGValidate(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, 2359 (xmlRelaxNGValidityErrorFunc) fprintf, 2360 (xmlRelaxNGValidityWarningFunc) fprintf, 2361 stderr); 2362 relaxngschemas = xmlRelaxNGParse(ctxt); 2363 xmlRelaxNGFreeParserCtxt(ctxt); 2364 if (relaxngschemas == NULL) { 2365 xmlGenericError(xmlGenericErrorContext, 2366 "Relax-NG schema %s failed to compile\n", schemas); 2367 return(-1); 2368 } 2369 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas); 2370 xmlRelaxNGSetValidErrors(vctxt, 2371 (xmlRelaxNGValidityErrorFunc) fprintf, 2372 (xmlRelaxNGValidityWarningFunc) fprintf, 2373 stderr); 2374 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc); 2375 if (ret == 0) { 2376 fprintf(stderr, "%s validates\n", sctxt->filename); 2377 } else if (ret > 0) { 2378 fprintf(stderr, "%s fails to validate\n", sctxt->filename); 2379 } else { 2380 fprintf(stderr, "%s validation generated an internal error\n", 2381 sctxt->filename); 2382 } 2383 xmlRelaxNGFreeValidCtxt(vctxt); 2384 if (relaxngschemas != NULL) 2385 xmlRelaxNGFree(relaxngschemas); 2386 return(0); 2387} 2388#endif 2389 2390#ifdef LIBXML_OUTPUT_ENABLED 2391/** 2392 * xmlShellCat: 2393 * @ctxt: the shell context 2394 * @arg: unused 2395 * @node: a node 2396 * @node2: unused 2397 * 2398 * Implements the XML shell function "cat" 2399 * dumps the serialization node content (XML or HTML). 2400 * 2401 * Returns 0 2402 */ 2403int 2404xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED, 2405 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) 2406{ 2407 if (!ctxt) 2408 return (0); 2409 if (node == NULL) { 2410 fprintf(ctxt->output, "NULL\n"); 2411 return (0); 2412 } 2413 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) { 2414#ifdef LIBXML_HTML_ENABLED 2415 if (node->type == XML_HTML_DOCUMENT_NODE) 2416 htmlDocDump(ctxt->output, (htmlDocPtr) node); 2417 else 2418 htmlNodeDumpFile(ctxt->output, ctxt->doc, node); 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#endif /* LIBXML_HTML_ENABLED */ 2425 } else { 2426 if (node->type == XML_DOCUMENT_NODE) 2427 xmlDocDump(ctxt->output, (xmlDocPtr) node); 2428 else 2429 xmlElemDump(ctxt->output, ctxt->doc, node); 2430 } 2431 fprintf(ctxt->output, "\n"); 2432 return (0); 2433} 2434#endif /* LIBXML_OUTPUT_ENABLED */ 2435 2436/** 2437 * xmlShellLoad: 2438 * @ctxt: the shell context 2439 * @filename: the file name 2440 * @node: unused 2441 * @node2: unused 2442 * 2443 * Implements the XML shell function "load" 2444 * loads a new document specified by the filename 2445 * 2446 * Returns 0 or -1 if loading failed 2447 */ 2448int 2449xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, 2450 xmlNodePtr node ATTRIBUTE_UNUSED, 2451 xmlNodePtr node2 ATTRIBUTE_UNUSED) 2452{ 2453 xmlDocPtr doc; 2454 int html = 0; 2455 2456 if ((ctxt == NULL) || (filename == NULL)) return(-1); 2457 if (ctxt->doc != NULL) 2458 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE); 2459 2460 if (html) { 2461#ifdef LIBXML_HTML_ENABLED 2462 doc = htmlParseFile(filename, NULL); 2463#else 2464 fprintf(ctxt->output, "HTML support not compiled in\n"); 2465 doc = NULL; 2466#endif /* LIBXML_HTML_ENABLED */ 2467 } else { 2468 doc = xmlReadFile(filename,NULL,0); 2469 } 2470 if (doc != NULL) { 2471 if (ctxt->loaded == 1) { 2472 xmlFreeDoc(ctxt->doc); 2473 } 2474 ctxt->loaded = 1; 2475#ifdef LIBXML_XPATH_ENABLED 2476 xmlXPathFreeContext(ctxt->pctxt); 2477#endif /* LIBXML_XPATH_ENABLED */ 2478 xmlFree(ctxt->filename); 2479 ctxt->doc = doc; 2480 ctxt->node = (xmlNodePtr) doc; 2481#ifdef LIBXML_XPATH_ENABLED 2482 ctxt->pctxt = xmlXPathNewContext(doc); 2483#endif /* LIBXML_XPATH_ENABLED */ 2484 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename); 2485 } else 2486 return (-1); 2487 return (0); 2488} 2489 2490#ifdef LIBXML_OUTPUT_ENABLED 2491/** 2492 * xmlShellWrite: 2493 * @ctxt: the shell context 2494 * @filename: the file name 2495 * @node: a node in the tree 2496 * @node2: unused 2497 * 2498 * Implements the XML shell function "write" 2499 * Write the current node to the filename, it saves the serialization 2500 * of the subtree under the @node specified 2501 * 2502 * Returns 0 or -1 in case of error 2503 */ 2504int 2505xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 2506 xmlNodePtr node2 ATTRIBUTE_UNUSED) 2507{ 2508 if (node == NULL) 2509 return (-1); 2510 if ((filename == NULL) || (filename[0] == 0)) { 2511 return (-1); 2512 } 2513#ifdef W_OK 2514 if (access((char *) filename, W_OK)) { 2515 xmlGenericError(xmlGenericErrorContext, 2516 "Cannot write to %s\n", filename); 2517 return (-1); 2518 } 2519#endif 2520 switch (node->type) { 2521 case XML_DOCUMENT_NODE: 2522 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { 2523 xmlGenericError(xmlGenericErrorContext, 2524 "Failed to write to %s\n", filename); 2525 return (-1); 2526 } 2527 break; 2528 case XML_HTML_DOCUMENT_NODE: 2529#ifdef LIBXML_HTML_ENABLED 2530 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 2531 xmlGenericError(xmlGenericErrorContext, 2532 "Failed to write to %s\n", filename); 2533 return (-1); 2534 } 2535#else 2536 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { 2537 xmlGenericError(xmlGenericErrorContext, 2538 "Failed to write to %s\n", filename); 2539 return (-1); 2540 } 2541#endif /* LIBXML_HTML_ENABLED */ 2542 break; 2543 default:{ 2544 FILE *f; 2545 2546 f = fopen((char *) filename, "w"); 2547 if (f == NULL) { 2548 xmlGenericError(xmlGenericErrorContext, 2549 "Failed to write to %s\n", filename); 2550 return (-1); 2551 } 2552 xmlElemDump(f, ctxt->doc, node); 2553 fclose(f); 2554 } 2555 } 2556 return (0); 2557} 2558 2559/** 2560 * xmlShellSave: 2561 * @ctxt: the shell context 2562 * @filename: the file name (optional) 2563 * @node: unused 2564 * @node2: unused 2565 * 2566 * Implements the XML shell function "save" 2567 * Write the current document to the filename, or it's original name 2568 * 2569 * Returns 0 or -1 in case of error 2570 */ 2571int 2572xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, 2573 xmlNodePtr node ATTRIBUTE_UNUSED, 2574 xmlNodePtr node2 ATTRIBUTE_UNUSED) 2575{ 2576 if ((ctxt == NULL) || (ctxt->doc == NULL)) 2577 return (-1); 2578 if ((filename == NULL) || (filename[0] == 0)) 2579 filename = ctxt->filename; 2580 if (filename == NULL) 2581 return (-1); 2582#ifdef W_OK 2583 if (access((char *) filename, W_OK)) { 2584 xmlGenericError(xmlGenericErrorContext, 2585 "Cannot save to %s\n", filename); 2586 return (-1); 2587 } 2588#endif 2589 switch (ctxt->doc->type) { 2590 case XML_DOCUMENT_NODE: 2591 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { 2592 xmlGenericError(xmlGenericErrorContext, 2593 "Failed to save to %s\n", filename); 2594 } 2595 break; 2596 case XML_HTML_DOCUMENT_NODE: 2597#ifdef LIBXML_HTML_ENABLED 2598 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 2599 xmlGenericError(xmlGenericErrorContext, 2600 "Failed to save to %s\n", filename); 2601 } 2602#else 2603 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { 2604 xmlGenericError(xmlGenericErrorContext, 2605 "Failed to save to %s\n", filename); 2606 } 2607#endif /* LIBXML_HTML_ENABLED */ 2608 break; 2609 default: 2610 xmlGenericError(xmlGenericErrorContext, 2611 "To save to subparts of a document use the 'write' command\n"); 2612 return (-1); 2613 2614 } 2615 return (0); 2616} 2617#endif /* LIBXML_OUTPUT_ENABLED */ 2618 2619#ifdef LIBXML_VALID_ENABLED 2620/** 2621 * xmlShellValidate: 2622 * @ctxt: the shell context 2623 * @dtd: the DTD URI (optional) 2624 * @node: unused 2625 * @node2: unused 2626 * 2627 * Implements the XML shell function "validate" 2628 * Validate the document, if a DTD path is provided, then the validation 2629 * is done against the given DTD. 2630 * 2631 * Returns 0 or -1 in case of error 2632 */ 2633int 2634xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, 2635 xmlNodePtr node ATTRIBUTE_UNUSED, 2636 xmlNodePtr node2 ATTRIBUTE_UNUSED) 2637{ 2638 xmlValidCtxt vctxt; 2639 int res = -1; 2640 2641 if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1); 2642 vctxt.userData = stderr; 2643 vctxt.error = (xmlValidityErrorFunc) fprintf; 2644 vctxt.warning = (xmlValidityWarningFunc) fprintf; 2645 2646 if ((dtd == NULL) || (dtd[0] == 0)) { 2647 res = xmlValidateDocument(&vctxt, ctxt->doc); 2648 } else { 2649 xmlDtdPtr subset; 2650 2651 subset = xmlParseDTD(NULL, (xmlChar *) dtd); 2652 if (subset != NULL) { 2653 res = xmlValidateDtd(&vctxt, ctxt->doc, subset); 2654 2655 xmlFreeDtd(subset); 2656 } 2657 } 2658 return (res); 2659} 2660#endif /* LIBXML_VALID_ENABLED */ 2661 2662/** 2663 * xmlShellDu: 2664 * @ctxt: the shell context 2665 * @arg: unused 2666 * @tree: a node defining a subtree 2667 * @node2: unused 2668 * 2669 * Implements the XML shell function "du" 2670 * show the structure of the subtree under node @tree 2671 * If @tree is null, the command works on the current node. 2672 * 2673 * Returns 0 or -1 in case of error 2674 */ 2675int 2676xmlShellDu(xmlShellCtxtPtr ctxt, 2677 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree, 2678 xmlNodePtr node2 ATTRIBUTE_UNUSED) 2679{ 2680 xmlNodePtr node; 2681 int indent = 0, i; 2682 2683 if (!ctxt) 2684 return (-1); 2685 2686 if (tree == NULL) 2687 return (-1); 2688 node = tree; 2689 while (node != NULL) { 2690 if ((node->type == XML_DOCUMENT_NODE) || 2691 (node->type == XML_HTML_DOCUMENT_NODE)) { 2692 fprintf(ctxt->output, "/\n"); 2693 } else if (node->type == XML_ELEMENT_NODE) { 2694 for (i = 0; i < indent; i++) 2695 fprintf(ctxt->output, " "); 2696 fprintf(ctxt->output, "%s\n", node->name); 2697 } else { 2698 } 2699 2700 /* 2701 * Browse the full subtree, deep first 2702 */ 2703 2704 if ((node->type == XML_DOCUMENT_NODE) || 2705 (node->type == XML_HTML_DOCUMENT_NODE)) { 2706 node = ((xmlDocPtr) node)->children; 2707 } else if ((node->children != NULL) 2708 && (node->type != XML_ENTITY_REF_NODE)) { 2709 /* deep first */ 2710 node = node->children; 2711 indent++; 2712 } else if ((node != tree) && (node->next != NULL)) { 2713 /* then siblings */ 2714 node = node->next; 2715 } else if (node != tree) { 2716 /* go up to parents->next if needed */ 2717 while (node != tree) { 2718 if (node->parent != NULL) { 2719 node = node->parent; 2720 indent--; 2721 } 2722 if ((node != tree) && (node->next != NULL)) { 2723 node = node->next; 2724 break; 2725 } 2726 if (node->parent == NULL) { 2727 node = NULL; 2728 break; 2729 } 2730 if (node == tree) { 2731 node = NULL; 2732 break; 2733 } 2734 } 2735 /* exit condition */ 2736 if (node == tree) 2737 node = NULL; 2738 } else 2739 node = NULL; 2740 } 2741 return (0); 2742} 2743 2744/** 2745 * xmlShellPwd: 2746 * @ctxt: the shell context 2747 * @buffer: the output buffer 2748 * @node: a node 2749 * @node2: unused 2750 * 2751 * Implements the XML shell function "pwd" 2752 * Show the full path from the root to the node, if needed building 2753 * thumblers when similar elements exists at a given ancestor level. 2754 * The output is compatible with XPath commands. 2755 * 2756 * Returns 0 or -1 in case of error 2757 */ 2758int 2759xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer, 2760 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) 2761{ 2762 xmlChar *path; 2763 2764 if ((node == NULL) || (buffer == NULL)) 2765 return (-1); 2766 2767 path = xmlGetNodePath(node); 2768 if (path == NULL) 2769 return (-1); 2770 2771 /* 2772 * This test prevents buffer overflow, because this routine 2773 * is only called by xmlShell, in which the second argument is 2774 * 500 chars long. 2775 * It is a dirty hack before a cleaner solution is found. 2776 * Documentation should mention that the second argument must 2777 * be at least 500 chars long, and could be stripped if too long. 2778 */ 2779 snprintf(buffer, 499, "%s", path); 2780 buffer[499] = '0'; 2781 xmlFree(path); 2782 2783 return (0); 2784} 2785 2786/** 2787 * xmlShell: 2788 * @doc: the initial document 2789 * @filename: the output buffer 2790 * @input: the line reading function 2791 * @output: the output FILE*, defaults to stdout if NULL 2792 * 2793 * Implements the XML shell 2794 * This allow to load, validate, view, modify and save a document 2795 * using a environment similar to a UNIX commandline. 2796 */ 2797void 2798xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, 2799 FILE * output) 2800{ 2801 char prompt[500] = "/ > "; 2802 char *cmdline = NULL, *cur; 2803 int nbargs; 2804 char command[100]; 2805 char arg[400]; 2806 int i; 2807 xmlShellCtxtPtr ctxt; 2808 xmlXPathObjectPtr list; 2809 2810 if (doc == NULL) 2811 return; 2812 if (filename == NULL) 2813 return; 2814 if (input == NULL) 2815 return; 2816 if (output == NULL) 2817 output = stdout; 2818 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt)); 2819 if (ctxt == NULL) 2820 return; 2821 ctxt->loaded = 0; 2822 ctxt->doc = doc; 2823 ctxt->input = input; 2824 ctxt->output = output; 2825 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename); 2826 ctxt->node = (xmlNodePtr) ctxt->doc; 2827 2828#ifdef LIBXML_XPATH_ENABLED 2829 ctxt->pctxt = xmlXPathNewContext(ctxt->doc); 2830 if (ctxt->pctxt == NULL) { 2831 xmlFree(ctxt); 2832 return; 2833 } 2834#endif /* LIBXML_XPATH_ENABLED */ 2835 while (1) { 2836 if (ctxt->node == (xmlNodePtr) ctxt->doc) 2837 snprintf(prompt, sizeof(prompt), "%s > ", "/"); 2838 else if ((ctxt->node != NULL) && (ctxt->node->name)) 2839 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name); 2840 else 2841 snprintf(prompt, sizeof(prompt), "? > "); 2842 prompt[sizeof(prompt) - 1] = 0; 2843 2844 /* 2845 * Get a new command line 2846 */ 2847 cmdline = ctxt->input(prompt); 2848 if (cmdline == NULL) 2849 break; 2850 2851 /* 2852 * Parse the command itself 2853 */ 2854 cur = cmdline; 2855 nbargs = 0; 2856 while ((*cur == ' ') || (*cur == '\t')) 2857 cur++; 2858 i = 0; 2859 while ((*cur != ' ') && (*cur != '\t') && 2860 (*cur != '\n') && (*cur != '\r')) { 2861 if (*cur == 0) 2862 break; 2863 command[i++] = *cur++; 2864 } 2865 command[i] = 0; 2866 if (i == 0) 2867 continue; 2868 nbargs++; 2869 2870 /* 2871 * Parse the argument 2872 */ 2873 while ((*cur == ' ') || (*cur == '\t')) 2874 cur++; 2875 i = 0; 2876 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) { 2877 if (*cur == 0) 2878 break; 2879 arg[i++] = *cur++; 2880 } 2881 arg[i] = 0; 2882 if (i != 0) 2883 nbargs++; 2884 2885 /* 2886 * start interpreting the command 2887 */ 2888 if (!strcmp(command, "exit")) 2889 break; 2890 if (!strcmp(command, "quit")) 2891 break; 2892 if (!strcmp(command, "bye")) 2893 break; 2894 if (!strcmp(command, "help")) { 2895 fprintf(ctxt->output, "\tbase display XML base of the node\n"); 2896 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n"); 2897 fprintf(ctxt->output, "\tbye leave shell\n"); 2898 fprintf(ctxt->output, "\tcat [node] display node or current node\n"); 2899 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n"); 2900 fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n"); 2901 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n"); 2902 fprintf(ctxt->output, "\texit leave shell\n"); 2903 fprintf(ctxt->output, "\thelp display this help\n"); 2904 fprintf(ctxt->output, "\tfree display memory usage\n"); 2905 fprintf(ctxt->output, "\tload [name] load a new document with name\n"); 2906 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n"); 2907 fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n"); 2908#ifdef LIBXML_XPATH_ENABLED 2909 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n"); 2910 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n"); 2911 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n"); 2912 fprintf(ctxt->output, "\tsetrootns register all namespace found on the root element\n"); 2913 fprintf(ctxt->output, "\t the default namespace if any uses 'defaultns' prefix\n"); 2914#endif /* LIBXML_XPATH_ENABLED */ 2915 fprintf(ctxt->output, "\tpwd display current working directory\n"); 2916 fprintf(ctxt->output, "\tquit leave shell\n"); 2917#ifdef LIBXML_OUTPUT_ENABLED 2918 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n"); 2919 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n"); 2920#endif /* LIBXML_OUTPUT_ENABLED */ 2921#ifdef LIBXML_VALID_ENABLED 2922 fprintf(ctxt->output, "\tvalidate check the document for errors\n"); 2923#endif /* LIBXML_VALID_ENABLED */ 2924#ifdef LIBXML_SCHEMAS_ENABLED 2925 fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n"); 2926#endif 2927 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n"); 2928#ifdef LIBXML_VALID_ENABLED 2929 } else if (!strcmp(command, "validate")) { 2930 xmlShellValidate(ctxt, arg, NULL, NULL); 2931#endif /* LIBXML_VALID_ENABLED */ 2932 } else if (!strcmp(command, "load")) { 2933 xmlShellLoad(ctxt, arg, NULL, NULL); 2934#ifdef LIBXML_SCHEMAS_ENABLED 2935 } else if (!strcmp(command, "relaxng")) { 2936 xmlShellRNGValidate(ctxt, arg, NULL, NULL); 2937#endif 2938#ifdef LIBXML_OUTPUT_ENABLED 2939 } else if (!strcmp(command, "save")) { 2940 xmlShellSave(ctxt, arg, NULL, NULL); 2941 } else if (!strcmp(command, "write")) { 2942 if ((arg == NULL) || (arg[0] == 0)) 2943 xmlGenericError(xmlGenericErrorContext, 2944 "Write command requires a filename argument\n"); 2945 else 2946 xmlShellWrite(ctxt, arg, NULL, NULL); 2947#endif /* LIBXML_OUTPUT_ENABLED */ 2948 } else if (!strcmp(command, "grep")) { 2949 xmlShellGrep(ctxt, arg, ctxt->node, NULL); 2950 } else if (!strcmp(command, "free")) { 2951 if (arg[0] == 0) { 2952 xmlMemShow(ctxt->output, 0); 2953 } else { 2954 int len = 0; 2955 2956 sscanf(arg, "%d", &len); 2957 xmlMemShow(ctxt->output, len); 2958 } 2959 } else if (!strcmp(command, "pwd")) { 2960 char dir[500]; 2961 2962 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL)) 2963 fprintf(ctxt->output, "%s\n", dir); 2964 } else if (!strcmp(command, "du")) { 2965 xmlShellDu(ctxt, NULL, ctxt->node, NULL); 2966 } else if (!strcmp(command, "base")) { 2967 xmlShellBase(ctxt, NULL, ctxt->node, NULL); 2968 } else if (!strcmp(command, "set")) { 2969 xmlShellSetContent(ctxt, arg, ctxt->node, NULL); 2970#ifdef LIBXML_XPATH_ENABLED 2971 } else if (!strcmp(command, "setns")) { 2972 if (arg[0] == 0) { 2973 xmlGenericError(xmlGenericErrorContext, 2974 "setns: prefix=[nsuri] required\n"); 2975 } else { 2976 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL); 2977 } 2978 } else if (!strcmp(command, "setrootns")) { 2979 xmlNodePtr root; 2980 2981 root = xmlDocGetRootElement(ctxt->doc); 2982 xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL); 2983 } else if (!strcmp(command, "xpath")) { 2984 if (arg[0] == 0) { 2985 xmlGenericError(xmlGenericErrorContext, 2986 "xpath: expression required\n"); 2987 } else { 2988 ctxt->pctxt->node = ctxt->node; 2989 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 2990 xmlXPathDebugDumpObject(ctxt->output, list, 0); 2991 xmlXPathFreeObject(list); 2992 } 2993#endif /* LIBXML_XPATH_ENABLED */ 2994#ifdef LIBXML_TREE_ENABLED 2995 } else if (!strcmp(command, "setbase")) { 2996 xmlShellSetBase(ctxt, arg, ctxt->node, NULL); 2997#endif 2998 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) { 2999 int dir = (!strcmp(command, "dir")); 3000 3001 if (arg[0] == 0) { 3002 if (dir) 3003 xmlShellDir(ctxt, NULL, ctxt->node, NULL); 3004 else 3005 xmlShellList(ctxt, NULL, ctxt->node, NULL); 3006 } else { 3007 ctxt->pctxt->node = ctxt->node; 3008#ifdef LIBXML_XPATH_ENABLED 3009 ctxt->pctxt->node = ctxt->node; 3010 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 3011#else 3012 list = NULL; 3013#endif /* LIBXML_XPATH_ENABLED */ 3014 if (list != NULL) { 3015 switch (list->type) { 3016 case XPATH_UNDEFINED: 3017 xmlGenericError(xmlGenericErrorContext, 3018 "%s: no such node\n", arg); 3019 break; 3020 case XPATH_NODESET:{ 3021 int indx; 3022 3023 if (list->nodesetval == NULL) 3024 break; 3025 3026 for (indx = 0; 3027 indx < list->nodesetval->nodeNr; 3028 indx++) { 3029 if (dir) 3030 xmlShellDir(ctxt, NULL, 3031 list->nodesetval-> 3032 nodeTab[indx], NULL); 3033 else 3034 xmlShellList(ctxt, NULL, 3035 list->nodesetval-> 3036 nodeTab[indx], NULL); 3037 } 3038 break; 3039 } 3040 case XPATH_BOOLEAN: 3041 xmlGenericError(xmlGenericErrorContext, 3042 "%s is a Boolean\n", arg); 3043 break; 3044 case XPATH_NUMBER: 3045 xmlGenericError(xmlGenericErrorContext, 3046 "%s is a number\n", arg); 3047 break; 3048 case XPATH_STRING: 3049 xmlGenericError(xmlGenericErrorContext, 3050 "%s is a string\n", arg); 3051 break; 3052 case XPATH_POINT: 3053 xmlGenericError(xmlGenericErrorContext, 3054 "%s is a point\n", arg); 3055 break; 3056 case XPATH_RANGE: 3057 xmlGenericError(xmlGenericErrorContext, 3058 "%s is a range\n", arg); 3059 break; 3060 case XPATH_LOCATIONSET: 3061 xmlGenericError(xmlGenericErrorContext, 3062 "%s is a range\n", arg); 3063 break; 3064 case XPATH_USERS: 3065 xmlGenericError(xmlGenericErrorContext, 3066 "%s is user-defined\n", arg); 3067 break; 3068 case XPATH_XSLT_TREE: 3069 xmlGenericError(xmlGenericErrorContext, 3070 "%s is an XSLT value tree\n", 3071 arg); 3072 break; 3073 } 3074#ifdef LIBXML_XPATH_ENABLED 3075 xmlXPathFreeObject(list); 3076#endif 3077 } else { 3078 xmlGenericError(xmlGenericErrorContext, 3079 "%s: no such node\n", arg); 3080 } 3081 ctxt->pctxt->node = NULL; 3082 } 3083 } else if (!strcmp(command, "cd")) { 3084 if (arg[0] == 0) { 3085 ctxt->node = (xmlNodePtr) ctxt->doc; 3086 } else { 3087#ifdef LIBXML_XPATH_ENABLED 3088 ctxt->pctxt->node = ctxt->node; 3089 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 3090#else 3091 list = NULL; 3092#endif /* LIBXML_XPATH_ENABLED */ 3093 if (list != NULL) { 3094 switch (list->type) { 3095 case XPATH_UNDEFINED: 3096 xmlGenericError(xmlGenericErrorContext, 3097 "%s: no such node\n", arg); 3098 break; 3099 case XPATH_NODESET: 3100 if (list->nodesetval != NULL) { 3101 if (list->nodesetval->nodeNr == 1) { 3102 ctxt->node = list->nodesetval->nodeTab[0]; 3103 if ((ctxt->node != NULL) && 3104 (ctxt->node->type == 3105 XML_NAMESPACE_DECL)) { 3106 xmlGenericError(xmlGenericErrorContext, 3107 "cannot cd to namespace\n"); 3108 ctxt->node = NULL; 3109 } 3110 } else 3111 xmlGenericError(xmlGenericErrorContext, 3112 "%s is a %d Node Set\n", 3113 arg, 3114 list->nodesetval->nodeNr); 3115 } else 3116 xmlGenericError(xmlGenericErrorContext, 3117 "%s is an empty Node Set\n", 3118 arg); 3119 break; 3120 case XPATH_BOOLEAN: 3121 xmlGenericError(xmlGenericErrorContext, 3122 "%s is a Boolean\n", arg); 3123 break; 3124 case XPATH_NUMBER: 3125 xmlGenericError(xmlGenericErrorContext, 3126 "%s is a number\n", arg); 3127 break; 3128 case XPATH_STRING: 3129 xmlGenericError(xmlGenericErrorContext, 3130 "%s is a string\n", arg); 3131 break; 3132 case XPATH_POINT: 3133 xmlGenericError(xmlGenericErrorContext, 3134 "%s is a point\n", arg); 3135 break; 3136 case XPATH_RANGE: 3137 xmlGenericError(xmlGenericErrorContext, 3138 "%s is a range\n", arg); 3139 break; 3140 case XPATH_LOCATIONSET: 3141 xmlGenericError(xmlGenericErrorContext, 3142 "%s is a range\n", arg); 3143 break; 3144 case XPATH_USERS: 3145 xmlGenericError(xmlGenericErrorContext, 3146 "%s is user-defined\n", arg); 3147 break; 3148 case XPATH_XSLT_TREE: 3149 xmlGenericError(xmlGenericErrorContext, 3150 "%s is an XSLT value tree\n", 3151 arg); 3152 break; 3153 } 3154#ifdef LIBXML_XPATH_ENABLED 3155 xmlXPathFreeObject(list); 3156#endif 3157 } else { 3158 xmlGenericError(xmlGenericErrorContext, 3159 "%s: no such node\n", arg); 3160 } 3161 ctxt->pctxt->node = NULL; 3162 } 3163#ifdef LIBXML_OUTPUT_ENABLED 3164 } else if (!strcmp(command, "cat")) { 3165 if (arg[0] == 0) { 3166 xmlShellCat(ctxt, NULL, ctxt->node, NULL); 3167 } else { 3168 ctxt->pctxt->node = ctxt->node; 3169#ifdef LIBXML_XPATH_ENABLED 3170 ctxt->pctxt->node = ctxt->node; 3171 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 3172#else 3173 list = NULL; 3174#endif /* LIBXML_XPATH_ENABLED */ 3175 if (list != NULL) { 3176 switch (list->type) { 3177 case XPATH_UNDEFINED: 3178 xmlGenericError(xmlGenericErrorContext, 3179 "%s: no such node\n", arg); 3180 break; 3181 case XPATH_NODESET:{ 3182 int indx; 3183 3184 if (list->nodesetval == NULL) 3185 break; 3186 3187 for (indx = 0; 3188 indx < list->nodesetval->nodeNr; 3189 indx++) { 3190 if (i > 0) 3191 fprintf(ctxt->output, " -------\n"); 3192 xmlShellCat(ctxt, NULL, 3193 list->nodesetval-> 3194 nodeTab[indx], NULL); 3195 } 3196 break; 3197 } 3198 case XPATH_BOOLEAN: 3199 xmlGenericError(xmlGenericErrorContext, 3200 "%s is a Boolean\n", arg); 3201 break; 3202 case XPATH_NUMBER: 3203 xmlGenericError(xmlGenericErrorContext, 3204 "%s is a number\n", arg); 3205 break; 3206 case XPATH_STRING: 3207 xmlGenericError(xmlGenericErrorContext, 3208 "%s is a string\n", arg); 3209 break; 3210 case XPATH_POINT: 3211 xmlGenericError(xmlGenericErrorContext, 3212 "%s is a point\n", arg); 3213 break; 3214 case XPATH_RANGE: 3215 xmlGenericError(xmlGenericErrorContext, 3216 "%s is a range\n", arg); 3217 break; 3218 case XPATH_LOCATIONSET: 3219 xmlGenericError(xmlGenericErrorContext, 3220 "%s is a range\n", arg); 3221 break; 3222 case XPATH_USERS: 3223 xmlGenericError(xmlGenericErrorContext, 3224 "%s is user-defined\n", arg); 3225 break; 3226 case XPATH_XSLT_TREE: 3227 xmlGenericError(xmlGenericErrorContext, 3228 "%s is an XSLT value tree\n", 3229 arg); 3230 break; 3231 } 3232#ifdef LIBXML_XPATH_ENABLED 3233 xmlXPathFreeObject(list); 3234#endif 3235 } else { 3236 xmlGenericError(xmlGenericErrorContext, 3237 "%s: no such node\n", arg); 3238 } 3239 ctxt->pctxt->node = NULL; 3240 } 3241#endif /* LIBXML_OUTPUT_ENABLED */ 3242 } else { 3243 xmlGenericError(xmlGenericErrorContext, 3244 "Unknown command %s\n", command); 3245 } 3246 free(cmdline); /* not xmlFree here ! */ 3247 } 3248#ifdef LIBXML_XPATH_ENABLED 3249 xmlXPathFreeContext(ctxt->pctxt); 3250#endif /* LIBXML_XPATH_ENABLED */ 3251 if (ctxt->loaded) { 3252 xmlFreeDoc(ctxt->doc); 3253 } 3254 if (ctxt->filename != NULL) 3255 xmlFree(ctxt->filename); 3256 xmlFree(ctxt); 3257 if (cmdline != NULL) 3258 free(cmdline); /* not xmlFree here ! */ 3259} 3260 3261#endif /* LIBXML_XPATH_ENABLED */ 3262#define bottom_debugXML 3263#include "elfgcchack.h" 3264#endif /* LIBXML_DEBUG_ENABLED */ 3265