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