debugXML.c revision f54cd533d8014ab04e9601ca8b05ee8a6b5c6e3f
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/** 38 * xmlDebugDumpString: 39 * @output: the FILE * for the output 40 * @str: the string 41 * 42 * Dumps informations about the string, shorten it if necessary 43 */ 44void 45xmlDebugDumpString(FILE * output, const xmlChar * str) 46{ 47 int i; 48 49 if (output == NULL) 50 output = stdout; 51 if (str == NULL) { 52 fprintf(output, "(NULL)"); 53 return; 54 } 55 for (i = 0; i < 40; i++) 56 if (str[i] == 0) 57 return; 58 else if (IS_BLANK_CH(str[i])) 59 fputc(' ', output); 60 else if (str[i] >= 0x80) 61 fprintf(output, "#%X", str[i]); 62 else 63 fputc(str[i], output); 64 fprintf(output, "..."); 65} 66 67static void 68xmlDebugDumpDtdNode(FILE *output, xmlDtdPtr dtd, int depth) { 69 int i; 70 char shift[100]; 71 72 for (i = 0;((i < depth) && (i < 25));i++) 73 shift[2 * i] = shift[2 * i + 1] = ' '; 74 shift[2 * i] = shift[2 * i + 1] = 0; 75 76 fprintf(output, shift); 77 78 if (dtd == NULL) { 79 fprintf(output, "DTD node is NULL\n"); 80 return; 81 } 82 83 if (dtd->type != XML_DTD_NODE) { 84 fprintf(output, "PBM: not a DTD\n"); 85 return; 86 } 87 if (dtd->name != NULL) 88 fprintf(output, "DTD(%s)", dtd->name); 89 else 90 fprintf(output, "DTD"); 91 if (dtd->ExternalID != NULL) 92 fprintf(output, ", PUBLIC %s", dtd->ExternalID); 93 if (dtd->SystemID != NULL) 94 fprintf(output, ", SYSTEM %s", dtd->SystemID); 95 fprintf(output, "\n"); 96 /* 97 * Do a bit of checking 98 */ 99 if (dtd->parent == NULL) 100 fprintf(output, "PBM: DTD has no parent\n"); 101 if (dtd->doc == NULL) 102 fprintf(output, "PBM: DTD has no doc\n"); 103 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc)) 104 fprintf(output, "PBM: DTD doc differs from parent's one\n"); 105 if (dtd->prev == NULL) { 106 if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd)) 107 fprintf(output, "PBM: DTD has no prev and not first of list\n"); 108 } else { 109 if (dtd->prev->next != (xmlNodePtr) dtd) 110 fprintf(output, "PBM: DTD prev->next : back link wrong\n"); 111 } 112 if (dtd->next == NULL) { 113 if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd)) 114 fprintf(output, "PBM: DTD has no next and not last of list\n"); 115 } else { 116 if (dtd->next->prev != (xmlNodePtr) dtd) 117 fprintf(output, "PBM: DTD next->prev : forward link wrong\n"); 118 } 119} 120 121static void 122xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) { 123 int i; 124 char shift[100]; 125 126 for (i = 0;((i < depth) && (i < 25));i++) 127 shift[2 * i] = shift[2 * i + 1] = ' '; 128 shift[2 * i] = shift[2 * i + 1] = 0; 129 130 fprintf(output, shift); 131 132 if (attr == NULL) { 133 fprintf(output, "Attribute declaration is NULL\n"); 134 return; 135 } 136 if (attr->type != XML_ATTRIBUTE_DECL) { 137 fprintf(output, "PBM: not a Attr\n"); 138 return; 139 } 140 if (attr->name != NULL) 141 fprintf(output, "ATTRDECL(%s)", attr->name); 142 else 143 fprintf(output, "PBM ATTRDECL noname!!!"); 144 if (attr->elem != NULL) 145 fprintf(output, " for %s", attr->elem); 146 else 147 fprintf(output, " PBM noelem!!!"); 148 switch (attr->atype) { 149 case XML_ATTRIBUTE_CDATA: 150 fprintf(output, " CDATA"); 151 break; 152 case XML_ATTRIBUTE_ID: 153 fprintf(output, " ID"); 154 break; 155 case XML_ATTRIBUTE_IDREF: 156 fprintf(output, " IDREF"); 157 break; 158 case XML_ATTRIBUTE_IDREFS: 159 fprintf(output, " IDREFS"); 160 break; 161 case XML_ATTRIBUTE_ENTITY: 162 fprintf(output, " ENTITY"); 163 break; 164 case XML_ATTRIBUTE_ENTITIES: 165 fprintf(output, " ENTITIES"); 166 break; 167 case XML_ATTRIBUTE_NMTOKEN: 168 fprintf(output, " NMTOKEN"); 169 break; 170 case XML_ATTRIBUTE_NMTOKENS: 171 fprintf(output, " NMTOKENS"); 172 break; 173 case XML_ATTRIBUTE_ENUMERATION: 174 fprintf(output, " ENUMERATION"); 175 break; 176 case XML_ATTRIBUTE_NOTATION: 177 fprintf(output, " NOTATION "); 178 break; 179 } 180 if (attr->tree != NULL) { 181 int indx; 182 xmlEnumerationPtr cur = attr->tree; 183 184 for (indx = 0;indx < 5; indx++) { 185 if (indx != 0) 186 fprintf(output, "|%s", cur->name); 187 else 188 fprintf(output, " (%s", cur->name); 189 cur = cur->next; 190 if (cur == NULL) break; 191 } 192 if (cur == NULL) 193 fprintf(output, ")"); 194 else 195 fprintf(output, "...)"); 196 } 197 switch (attr->def) { 198 case XML_ATTRIBUTE_NONE: 199 break; 200 case XML_ATTRIBUTE_REQUIRED: 201 fprintf(output, " REQUIRED"); 202 break; 203 case XML_ATTRIBUTE_IMPLIED: 204 fprintf(output, " IMPLIED"); 205 break; 206 case XML_ATTRIBUTE_FIXED: 207 fprintf(output, " FIXED"); 208 break; 209 } 210 if (attr->defaultValue != NULL) { 211 fprintf(output, "\""); 212 xmlDebugDumpString(output, attr->defaultValue); 213 fprintf(output, "\""); 214 } 215 fprintf(output, "\n"); 216 217 /* 218 * Do a bit of checking 219 */ 220 if (attr->parent == NULL) 221 fprintf(output, "PBM: Attr has no parent\n"); 222 if (attr->doc == NULL) 223 fprintf(output, "PBM: Attr has no doc\n"); 224 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc)) 225 fprintf(output, "PBM: Attr doc differs from parent's one\n"); 226 if (attr->prev == NULL) { 227 if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr)) 228 fprintf(output, "PBM: Attr has no prev and not first of list\n"); 229 } else { 230 if (attr->prev->next != (xmlNodePtr) attr) 231 fprintf(output, "PBM: Attr prev->next : back link wrong\n"); 232 } 233 if (attr->next == NULL) { 234 if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr)) 235 fprintf(output, "PBM: Attr has no next and not last of list\n"); 236 } else { 237 if (attr->next->prev != (xmlNodePtr) attr) 238 fprintf(output, "PBM: Attr next->prev : forward link wrong\n"); 239 } 240} 241 242static void 243xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) { 244 int i; 245 char shift[100]; 246 247 for (i = 0;((i < depth) && (i < 25));i++) 248 shift[2 * i] = shift[2 * i + 1] = ' '; 249 shift[2 * i] = shift[2 * i + 1] = 0; 250 251 fprintf(output, shift); 252 253 if (elem == NULL) { 254 fprintf(output, "Element declaration is NULL\n"); 255 return; 256 } 257 if (elem->type != XML_ELEMENT_DECL) { 258 fprintf(output, "PBM: not a Elem\n"); 259 return; 260 } 261 if (elem->name != NULL) { 262 fprintf(output, "ELEMDECL("); 263 xmlDebugDumpString(output, elem->name); 264 fprintf(output, ")"); 265 } else 266 fprintf(output, "PBM ELEMDECL noname!!!"); 267 switch (elem->etype) { 268 case XML_ELEMENT_TYPE_UNDEFINED: 269 fprintf(output, ", UNDEFINED"); 270 break; 271 case XML_ELEMENT_TYPE_EMPTY: 272 fprintf(output, ", EMPTY"); 273 break; 274 case XML_ELEMENT_TYPE_ANY: 275 fprintf(output, ", ANY"); 276 break; 277 case XML_ELEMENT_TYPE_MIXED: 278 fprintf(output, ", MIXED "); 279 break; 280 case XML_ELEMENT_TYPE_ELEMENT: 281 fprintf(output, ", MIXED "); 282 break; 283 } 284 if ((elem->type != XML_ELEMENT_NODE) && 285 (elem->content != NULL)) { 286 char buf[5001]; 287 288 buf[0] = 0; 289 xmlSnprintfElementContent(buf, 5000, elem->content, 1); 290 buf[5000] = 0; 291 fprintf(output, "%s", buf); 292 } 293 fprintf(output, "\n"); 294 295 /* 296 * Do a bit of checking 297 */ 298 if (elem->parent == NULL) 299 fprintf(output, "PBM: Elem has no parent\n"); 300 if (elem->doc == NULL) 301 fprintf(output, "PBM: Elem has no doc\n"); 302 if ((elem->parent != NULL) && (elem->doc != elem->parent->doc)) 303 fprintf(output, "PBM: Elem doc differs from parent's one\n"); 304 if (elem->prev == NULL) { 305 if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem)) 306 fprintf(output, "PBM: Elem has no prev and not first of list\n"); 307 } else { 308 if (elem->prev->next != (xmlNodePtr) elem) 309 fprintf(output, "PBM: Elem prev->next : back link wrong\n"); 310 } 311 if (elem->next == NULL) { 312 if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem)) 313 fprintf(output, "PBM: Elem has no next and not last of list\n"); 314 } else { 315 if (elem->next->prev != (xmlNodePtr) elem) 316 fprintf(output, "PBM: Elem next->prev : forward link wrong\n"); 317 } 318} 319 320static void 321xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) { 322 int i; 323 char shift[100]; 324 325 for (i = 0;((i < depth) && (i < 25));i++) 326 shift[2 * i] = shift[2 * i + 1] = ' '; 327 shift[2 * i] = shift[2 * i + 1] = 0; 328 329 fprintf(output, shift); 330 331 if (ent == NULL) { 332 fprintf(output, "Entity declaration is NULL\n"); 333 return; 334 } 335 if (ent->type != XML_ENTITY_DECL) { 336 fprintf(output, "PBM: not a Entity decl\n"); 337 return; 338 } 339 if (ent->name != NULL) { 340 fprintf(output, "ENTITYDECL("); 341 xmlDebugDumpString(output, ent->name); 342 fprintf(output, ")"); 343 } else 344 fprintf(output, "PBM ENTITYDECL noname!!!"); 345 switch (ent->etype) { 346 case XML_INTERNAL_GENERAL_ENTITY: 347 fprintf(output, ", internal\n"); 348 break; 349 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 350 fprintf(output, ", external parsed\n"); 351 break; 352 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 353 fprintf(output, ", unparsed\n"); 354 break; 355 case XML_INTERNAL_PARAMETER_ENTITY: 356 fprintf(output, ", parameter\n"); 357 break; 358 case XML_EXTERNAL_PARAMETER_ENTITY: 359 fprintf(output, ", external parameter\n"); 360 break; 361 case XML_INTERNAL_PREDEFINED_ENTITY: 362 fprintf(output, ", predefined\n"); 363 break; 364 } 365 if (ent->ExternalID) { 366 fprintf(output, shift); 367 fprintf(output, " ExternalID=%s\n", ent->ExternalID); 368 } 369 if (ent->SystemID) { 370 fprintf(output, shift); 371 fprintf(output, " SystemID=%s\n", ent->SystemID); 372 } 373 if (ent->URI != NULL) { 374 fprintf(output, shift); 375 fprintf(output, " URI=%s\n", ent->URI); 376 } 377 if (ent->content) { 378 fprintf(output, shift); 379 fprintf(output, " content="); 380 xmlDebugDumpString(output, ent->content); 381 fprintf(output, "\n"); 382 } 383 384 /* 385 * Do a bit of checking 386 */ 387 if (ent->parent == NULL) 388 fprintf(output, "PBM: Ent has no parent\n"); 389 if (ent->doc == NULL) 390 fprintf(output, "PBM: Ent has no doc\n"); 391 if ((ent->parent != NULL) && (ent->doc != ent->parent->doc)) 392 fprintf(output, "PBM: Ent doc differs from parent's one\n"); 393 if (ent->prev == NULL) { 394 if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent)) 395 fprintf(output, "PBM: Ent has no prev and not first of list\n"); 396 } else { 397 if (ent->prev->next != (xmlNodePtr) ent) 398 fprintf(output, "PBM: Ent prev->next : back link wrong\n"); 399 } 400 if (ent->next == NULL) { 401 if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent)) 402 fprintf(output, "PBM: Ent has no next and not last of list\n"); 403 } else { 404 if (ent->next->prev != (xmlNodePtr) ent) 405 fprintf(output, "PBM: Ent next->prev : forward link wrong\n"); 406 } 407} 408 409static void 410xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) { 411 int i; 412 char shift[100]; 413 414 for (i = 0;((i < depth) && (i < 25));i++) 415 shift[2 * i] = shift[2 * i + 1] = ' '; 416 shift[2 * i] = shift[2 * i + 1] = 0; 417 418 fprintf(output, shift); 419 420 if (ns == NULL) { 421 fprintf(output, "namespace node is NULL\n"); 422 return; 423 } 424 if (ns->type != XML_NAMESPACE_DECL) { 425 fprintf(output, "invalid namespace node %d\n", ns->type); 426 return; 427 } 428 if (ns->href == NULL) { 429 if (ns->prefix != NULL) 430 fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix); 431 else 432 fprintf(output, "incomplete default namespace href=NULL\n"); 433 } else { 434 if (ns->prefix != NULL) 435 fprintf(output, "namespace %s href=", ns->prefix); 436 else 437 fprintf(output, "default namespace href="); 438 439 xmlDebugDumpString(output, ns->href); 440 fprintf(output, "\n"); 441 } 442} 443 444static void 445xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) { 446 while (ns != NULL) { 447 xmlDebugDumpNamespace(output, ns, depth); 448 ns = ns->next; 449 } 450} 451 452static void 453xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) { 454 int i; 455 char shift[100]; 456 457 for (i = 0;((i < depth) && (i < 25));i++) 458 shift[2 * i] = shift[2 * i + 1] = ' '; 459 shift[2 * i] = shift[2 * i + 1] = 0; 460 461 fprintf(output, shift); 462 463 if (ent == NULL) { 464 fprintf(output, "Entity is NULL\n"); 465 return; 466 } 467 switch (ent->etype) { 468 case XML_INTERNAL_GENERAL_ENTITY: 469 fprintf(output, "INTERNAL_GENERAL_ENTITY "); 470 break; 471 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 472 fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY "); 473 break; 474 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 475 fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY "); 476 break; 477 case XML_INTERNAL_PARAMETER_ENTITY: 478 fprintf(output, "INTERNAL_PARAMETER_ENTITY "); 479 break; 480 case XML_EXTERNAL_PARAMETER_ENTITY: 481 fprintf(output, "EXTERNAL_PARAMETER_ENTITY "); 482 break; 483 default: 484 fprintf(output, "ENTITY_%d ! ", ent->etype); 485 } 486 fprintf(output, "%s\n", ent->name); 487 if (ent->ExternalID) { 488 fprintf(output, shift); 489 fprintf(output, "ExternalID=%s\n", ent->ExternalID); 490 } 491 if (ent->SystemID) { 492 fprintf(output, shift); 493 fprintf(output, "SystemID=%s\n", ent->SystemID); 494 } 495 if (ent->URI) { 496 fprintf(output, shift); 497 fprintf(output, "URI=%s\n", ent->URI); 498 } 499 if (ent->content) { 500 fprintf(output, shift); 501 fprintf(output, "content="); 502 xmlDebugDumpString(output, ent->content); 503 fprintf(output, "\n"); 504 } 505} 506 507/** 508 * xmlDebugDumpAttr: 509 * @output: the FILE * for the output 510 * @attr: the attribute 511 * @depth: the indentation level. 512 * 513 * Dumps debug information for the attribute 514 */ 515void 516xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) { 517 int i; 518 char shift[100]; 519 520 for (i = 0;((i < depth) && (i < 25));i++) 521 shift[2 * i] = shift[2 * i + 1] = ' '; 522 shift[2 * i] = shift[2 * i + 1] = 0; 523 524 fprintf(output, shift); 525 526 if (attr == NULL) { 527 fprintf(output, "Attr is NULL"); 528 return; 529 } 530 fprintf(output, "ATTRIBUTE "); 531 xmlDebugDumpString(output, attr->name); 532 fprintf(output, "\n"); 533 if (attr->children != NULL) 534 xmlDebugDumpNodeList(output, attr->children, depth + 1); 535 536 /* 537 * Do a bit of checking 538 */ 539 if (attr->parent == NULL) 540 fprintf(output, "PBM: Attr has no parent\n"); 541 if (attr->doc == NULL) 542 fprintf(output, "PBM: Attr has no doc\n"); 543 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc)) 544 fprintf(output, "PBM: Attr doc differs from parent's one\n"); 545 if (attr->prev == NULL) { 546 if ((attr->parent != NULL) && (attr->parent->properties != attr)) 547 fprintf(output, "PBM: Attr has no prev and not first of list\n"); 548 } else { 549 if (attr->prev->next != attr) 550 fprintf(output, "PBM: Attr prev->next : back link wrong\n"); 551 } 552 if (attr->next != NULL) { 553 if (attr->next->prev != attr) 554 fprintf(output, "PBM: Attr next->prev : forward link wrong\n"); 555 } 556} 557 558/** 559 * xmlDebugDumpAttrList: 560 * @output: the FILE * for the output 561 * @attr: the attribute list 562 * @depth: the indentation level. 563 * 564 * Dumps debug information for the attribute list 565 */ 566void 567xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth) 568{ 569 if (output == NULL) 570 output = stdout; 571 while (attr != NULL) { 572 xmlDebugDumpAttr(output, attr, depth); 573 attr = attr->next; 574 } 575} 576 577/** 578 * xmlDebugDumpOneNode: 579 * @output: the FILE * for the output 580 * @node: the node 581 * @depth: the indentation level. 582 * 583 * Dumps debug information for the element node, it is not recursive 584 */ 585void 586xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth) 587{ 588 int i; 589 char shift[100]; 590 591 if (output == NULL) 592 output = stdout; 593 for (i = 0; ((i < depth) && (i < 25)); i++) 594 shift[2 * i] = shift[2 * i + 1] = ' '; 595 shift[2 * i] = shift[2 * i + 1] = 0; 596 597 if (node == NULL) { 598 fprintf(output, shift); 599 fprintf(output, "node is NULL\n"); 600 return; 601 } 602 switch (node->type) { 603 case XML_ELEMENT_NODE: 604 fprintf(output, shift); 605 fprintf(output, "ELEMENT "); 606 if ((node->ns != NULL) && (node->ns->prefix != NULL)) { 607 xmlDebugDumpString(output, node->ns->prefix); 608 fprintf(output, ":"); 609 } 610 xmlDebugDumpString(output, node->name); 611 fprintf(output, "\n"); 612 break; 613 case XML_ATTRIBUTE_NODE: 614 fprintf(output, shift); 615 fprintf(output, "Error, ATTRIBUTE found here\n"); 616 break; 617 case XML_TEXT_NODE: 618 fprintf(output, shift); 619 if (node->name == (const xmlChar *) xmlStringTextNoenc) 620 fprintf(output, "TEXT no enc\n"); 621 else 622 fprintf(output, "TEXT\n"); 623 break; 624 case XML_CDATA_SECTION_NODE: 625 fprintf(output, shift); 626 fprintf(output, "CDATA_SECTION\n"); 627 break; 628 case XML_ENTITY_REF_NODE: 629 fprintf(output, shift); 630 fprintf(output, "ENTITY_REF(%s)\n", node->name); 631 break; 632 case XML_ENTITY_NODE: 633 fprintf(output, shift); 634 fprintf(output, "ENTITY\n"); 635 break; 636 case XML_PI_NODE: 637 fprintf(output, shift); 638 fprintf(output, "PI %s\n", node->name); 639 break; 640 case XML_COMMENT_NODE: 641 fprintf(output, shift); 642 fprintf(output, "COMMENT\n"); 643 break; 644 case XML_DOCUMENT_NODE: 645 case XML_HTML_DOCUMENT_NODE: 646 fprintf(output, shift); 647 fprintf(output, "Error, DOCUMENT found here\n"); 648 break; 649 case XML_DOCUMENT_TYPE_NODE: 650 fprintf(output, shift); 651 fprintf(output, "DOCUMENT_TYPE\n"); 652 break; 653 case XML_DOCUMENT_FRAG_NODE: 654 fprintf(output, shift); 655 fprintf(output, "DOCUMENT_FRAG\n"); 656 break; 657 case XML_NOTATION_NODE: 658 fprintf(output, shift); 659 fprintf(output, "NOTATION\n"); 660 break; 661 case XML_DTD_NODE: 662 xmlDebugDumpDtdNode(output, (xmlDtdPtr) node, depth); 663 return; 664 case XML_ELEMENT_DECL: 665 xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth); 666 return; 667 case XML_ATTRIBUTE_DECL: 668 xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth); 669 return; 670 case XML_ENTITY_DECL: 671 xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth); 672 return; 673 case XML_NAMESPACE_DECL: 674 xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth); 675 return; 676 case XML_XINCLUDE_START: 677 fprintf(output, shift); 678 fprintf(output, "INCLUDE START\n"); 679 return; 680 case XML_XINCLUDE_END: 681 fprintf(output, shift); 682 fprintf(output, "INCLUDE END\n"); 683 return; 684 default: 685 fprintf(output, shift); 686 fprintf(output, "NODE_%d !!!\n", node->type); 687 return; 688 } 689 if (node->doc == NULL) { 690 fprintf(output, shift); 691 fprintf(output, "doc == NULL !!!\n"); 692 } 693 if (node->nsDef != NULL) 694 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1); 695 if (node->properties != NULL) 696 xmlDebugDumpAttrList(output, node->properties, depth + 1); 697 if (node->type != XML_ENTITY_REF_NODE) { 698 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) { 699 shift[2 * i] = shift[2 * i + 1] = ' '; 700 shift[2 * i + 2] = shift[2 * i + 3] = 0; 701 fprintf(output, shift); 702 fprintf(output, "content="); 703 xmlDebugDumpString(output, node->content); 704 fprintf(output, "\n"); 705 } 706 } else { 707 xmlEntityPtr ent; 708 709 ent = xmlGetDocEntity(node->doc, node->name); 710 if (ent != NULL) 711 xmlDebugDumpEntity(output, ent, depth + 1); 712 } 713 /* 714 * Do a bit of checking 715 */ 716 if (node->parent == NULL) 717 fprintf(output, "PBM: Node has no parent\n"); 718 if (node->doc == NULL) 719 fprintf(output, "PBM: Node has no doc\n"); 720 if ((node->parent != NULL) && (node->doc != node->parent->doc)) 721 fprintf(output, "PBM: Node doc differs from parent's one\n"); 722 if (node->prev == NULL) { 723 if ((node->parent != NULL) && (node->parent->children != node)) 724 fprintf(output, 725 "PBM: Node has no prev and not first of list\n"); 726 } else { 727 if (node->prev->next != node) 728 fprintf(output, "PBM: Node prev->next : back link wrong\n"); 729 } 730 if (node->next == NULL) { 731 if ((node->parent != NULL) && (node->parent->last != node)) 732 fprintf(output, 733 "PBM: Node has no next and not last of list\n"); 734 } else { 735 if (node->next->prev != node) 736 fprintf(output, "PBM: Node next->prev : forward link wrong\n"); 737 } 738} 739 740/** 741 * xmlDebugDumpNode: 742 * @output: the FILE * for the output 743 * @node: the node 744 * @depth: the indentation level. 745 * 746 * Dumps debug information for the element node, it is recursive 747 */ 748void 749xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth) 750{ 751 if (output == NULL) 752 output = stdout; 753 if (node == NULL) { 754 int i; 755 char shift[100]; 756 757 for (i = 0; ((i < depth) && (i < 25)); i++) 758 shift[2 * i] = shift[2 * i + 1] = ' '; 759 shift[2 * i] = shift[2 * i + 1] = 0; 760 761 fprintf(output, shift); 762 fprintf(output, "node is NULL\n"); 763 return; 764 } 765 xmlDebugDumpOneNode(output, node, depth); 766 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) 767 xmlDebugDumpNodeList(output, node->children, depth + 1); 768} 769 770/** 771 * xmlDebugDumpNodeList: 772 * @output: the FILE * for the output 773 * @node: the node list 774 * @depth: the indentation level. 775 * 776 * Dumps debug information for the list of element node, it is recursive 777 */ 778void 779xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth) 780{ 781 if (output == NULL) 782 output = stdout; 783 while (node != NULL) { 784 xmlDebugDumpNode(output, node, depth); 785 node = node->next; 786 } 787} 788 789 790/** 791 * xmlDebugDumpDocumentHead: 792 * @output: the FILE * for the output 793 * @doc: the document 794 * 795 * Dumps debug information cncerning the document, not recursive 796 */ 797void 798xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc) 799{ 800 if (output == NULL) 801 output = stdout; 802 if (doc == NULL) { 803 fprintf(output, "DOCUMENT == NULL !\n"); 804 return; 805 } 806 807 switch (doc->type) { 808 case XML_ELEMENT_NODE: 809 fprintf(output, "Error, ELEMENT found here "); 810 break; 811 case XML_ATTRIBUTE_NODE: 812 fprintf(output, "Error, ATTRIBUTE found here\n"); 813 break; 814 case XML_TEXT_NODE: 815 fprintf(output, "Error, TEXT\n"); 816 break; 817 case XML_CDATA_SECTION_NODE: 818 fprintf(output, "Error, CDATA_SECTION\n"); 819 break; 820 case XML_ENTITY_REF_NODE: 821 fprintf(output, "Error, ENTITY_REF\n"); 822 break; 823 case XML_ENTITY_NODE: 824 fprintf(output, "Error, ENTITY\n"); 825 break; 826 case XML_PI_NODE: 827 fprintf(output, "Error, PI\n"); 828 break; 829 case XML_COMMENT_NODE: 830 fprintf(output, "Error, COMMENT\n"); 831 break; 832 case XML_DOCUMENT_NODE: 833 fprintf(output, "DOCUMENT\n"); 834 break; 835 case XML_HTML_DOCUMENT_NODE: 836 fprintf(output, "HTML DOCUMENT\n"); 837 break; 838 case XML_DOCUMENT_TYPE_NODE: 839 fprintf(output, "Error, DOCUMENT_TYPE\n"); 840 break; 841 case XML_DOCUMENT_FRAG_NODE: 842 fprintf(output, "Error, DOCUMENT_FRAG\n"); 843 break; 844 case XML_NOTATION_NODE: 845 fprintf(output, "Error, NOTATION\n"); 846 break; 847 default: 848 fprintf(output, "NODE_%d\n", doc->type); 849 } 850 if (doc->name != NULL) { 851 fprintf(output, "name="); 852 xmlDebugDumpString(output, BAD_CAST doc->name); 853 fprintf(output, "\n"); 854 } 855 if (doc->version != NULL) { 856 fprintf(output, "version="); 857 xmlDebugDumpString(output, doc->version); 858 fprintf(output, "\n"); 859 } 860 if (doc->encoding != NULL) { 861 fprintf(output, "encoding="); 862 xmlDebugDumpString(output, doc->encoding); 863 fprintf(output, "\n"); 864 } 865 if (doc->URL != NULL) { 866 fprintf(output, "URL="); 867 xmlDebugDumpString(output, doc->URL); 868 fprintf(output, "\n"); 869 } 870 if (doc->standalone) 871 fprintf(output, "standalone=true\n"); 872 if (doc->oldNs != NULL) 873 xmlDebugDumpNamespaceList(output, doc->oldNs, 0); 874} 875 876/** 877 * xmlDebugDumpDocument: 878 * @output: the FILE * for the output 879 * @doc: the document 880 * 881 * Dumps debug information for the document, it's recursive 882 */ 883void 884xmlDebugDumpDocument(FILE * output, xmlDocPtr doc) 885{ 886 if (output == NULL) 887 output = stdout; 888 if (doc == NULL) { 889 fprintf(output, "DOCUMENT == NULL !\n"); 890 return; 891 } 892 xmlDebugDumpDocumentHead(output, doc); 893 if (((doc->type == XML_DOCUMENT_NODE) || 894 (doc->type == XML_HTML_DOCUMENT_NODE)) && (doc->children != NULL)) 895 xmlDebugDumpNodeList(output, doc->children, 1); 896} 897 898/** 899 * xmlDebugDumpDTD: 900 * @output: the FILE * for the output 901 * @dtd: the DTD 902 * 903 * Dumps debug information for the DTD 904 */ 905void 906xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd) 907{ 908 if (output == NULL) 909 output = stdout; 910 if (dtd == NULL) { 911 fprintf(output, "DTD is NULL\n"); 912 return; 913 } 914 if (dtd->type != XML_DTD_NODE) { 915 fprintf(output, "PBM: not a DTD\n"); 916 return; 917 } 918 if (dtd->name != NULL) 919 fprintf(output, "DTD(%s)", dtd->name); 920 else 921 fprintf(output, "DTD"); 922 if (dtd->ExternalID != NULL) 923 fprintf(output, ", PUBLIC %s", dtd->ExternalID); 924 if (dtd->SystemID != NULL) 925 fprintf(output, ", SYSTEM %s", dtd->SystemID); 926 fprintf(output, "\n"); 927 /* 928 * Do a bit of checking 929 */ 930 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc)) 931 fprintf(output, "PBM: DTD doc differs from parent's one\n"); 932 if (dtd->prev == NULL) { 933 if ((dtd->parent != NULL) 934 && (dtd->parent->children != (xmlNodePtr) dtd)) 935 fprintf(output, 936 "PBM: DTD has no prev and not first of list\n"); 937 } else { 938 if (dtd->prev->next != (xmlNodePtr) dtd) 939 fprintf(output, "PBM: DTD prev->next : back link wrong\n"); 940 } 941 if (dtd->next == NULL) { 942 if ((dtd->parent != NULL) 943 && (dtd->parent->last != (xmlNodePtr) dtd)) 944 fprintf(output, "PBM: DTD has no next and not last of list\n"); 945 } else { 946 if (dtd->next->prev != (xmlNodePtr) dtd) 947 fprintf(output, "PBM: DTD next->prev : forward link wrong\n"); 948 } 949 if (dtd->children == NULL) 950 fprintf(output, " DTD is empty\n"); 951 else 952 xmlDebugDumpNodeList(output, dtd->children, 1); 953} 954 955static void 956xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output) { 957 if (cur == NULL) { 958 fprintf(output, "Entity is NULL"); 959 return; 960 } 961 fprintf(output, "%s : ", cur->name); 962 switch (cur->etype) { 963 case XML_INTERNAL_GENERAL_ENTITY: 964 fprintf(output, "INTERNAL GENERAL, "); 965 break; 966 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 967 fprintf(output, "EXTERNAL PARSED, "); 968 break; 969 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 970 fprintf(output, "EXTERNAL UNPARSED, "); 971 break; 972 case XML_INTERNAL_PARAMETER_ENTITY: 973 fprintf(output, "INTERNAL PARAMETER, "); 974 break; 975 case XML_EXTERNAL_PARAMETER_ENTITY: 976 fprintf(output, "EXTERNAL PARAMETER, "); 977 break; 978 default: 979 fprintf(output, "UNKNOWN TYPE %d", 980 cur->etype); 981 } 982 if (cur->ExternalID != NULL) 983 fprintf(output, "ID \"%s\"", cur->ExternalID); 984 if (cur->SystemID != NULL) 985 fprintf(output, "SYSTEM \"%s\"", cur->SystemID); 986 if (cur->orig != NULL) 987 fprintf(output, "\n orig \"%s\"", cur->orig); 988 if ((cur->type != XML_ELEMENT_NODE) && 989 (cur->content != NULL)) 990 fprintf(output, "\n content \"%s\"", cur->content); 991 fprintf(output, "\n"); 992} 993 994/** 995 * xmlDebugDumpEntities: 996 * @output: the FILE * for the output 997 * @doc: the document 998 * 999 * Dumps debug information for all the entities in use by the document 1000 */ 1001void 1002xmlDebugDumpEntities(FILE * output, xmlDocPtr doc) 1003{ 1004 if (output == NULL) 1005 output = stdout; 1006 if (doc == NULL) { 1007 fprintf(output, "DOCUMENT == NULL !\n"); 1008 return; 1009 } 1010 1011 switch (doc->type) { 1012 case XML_ELEMENT_NODE: 1013 fprintf(output, "Error, ELEMENT found here "); 1014 break; 1015 case XML_ATTRIBUTE_NODE: 1016 fprintf(output, "Error, ATTRIBUTE found here\n"); 1017 break; 1018 case XML_TEXT_NODE: 1019 fprintf(output, "Error, TEXT\n"); 1020 break; 1021 case XML_CDATA_SECTION_NODE: 1022 fprintf(output, "Error, CDATA_SECTION\n"); 1023 break; 1024 case XML_ENTITY_REF_NODE: 1025 fprintf(output, "Error, ENTITY_REF\n"); 1026 break; 1027 case XML_ENTITY_NODE: 1028 fprintf(output, "Error, ENTITY\n"); 1029 break; 1030 case XML_PI_NODE: 1031 fprintf(output, "Error, PI\n"); 1032 break; 1033 case XML_COMMENT_NODE: 1034 fprintf(output, "Error, COMMENT\n"); 1035 break; 1036 case XML_DOCUMENT_NODE: 1037 fprintf(output, "DOCUMENT\n"); 1038 break; 1039 case XML_HTML_DOCUMENT_NODE: 1040 fprintf(output, "HTML DOCUMENT\n"); 1041 break; 1042 case XML_DOCUMENT_TYPE_NODE: 1043 fprintf(output, "Error, DOCUMENT_TYPE\n"); 1044 break; 1045 case XML_DOCUMENT_FRAG_NODE: 1046 fprintf(output, "Error, DOCUMENT_FRAG\n"); 1047 break; 1048 case XML_NOTATION_NODE: 1049 fprintf(output, "Error, NOTATION\n"); 1050 break; 1051 default: 1052 fprintf(output, "NODE_%d\n", doc->type); 1053 } 1054 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) { 1055 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 1056 doc->intSubset->entities; 1057 1058 fprintf(output, "Entities in internal subset\n"); 1059 xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback, 1060 output); 1061 } else 1062 fprintf(output, "No entities in internal subset\n"); 1063 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) { 1064 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 1065 doc->extSubset->entities; 1066 1067 fprintf(output, "Entities in external subset\n"); 1068 xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback, 1069 output); 1070 } else 1071 fprintf(output, "No entities in external subset\n"); 1072} 1073 1074/** 1075 * xmlLsCountNode: 1076 * @node: the node to count 1077 * 1078 * Count the children of @node. 1079 * 1080 * Returns the number of children of @node. 1081 */ 1082int 1083xmlLsCountNode(xmlNodePtr node) { 1084 int ret = 0; 1085 xmlNodePtr list = NULL; 1086 1087 if (node == NULL) 1088 return(0); 1089 1090 switch (node->type) { 1091 case XML_ELEMENT_NODE: 1092 list = node->children; 1093 break; 1094 case XML_DOCUMENT_NODE: 1095 case XML_HTML_DOCUMENT_NODE: 1096#ifdef LIBXML_DOCB_ENABLED 1097 case XML_DOCB_DOCUMENT_NODE: 1098#endif 1099 list = ((xmlDocPtr) node)->children; 1100 break; 1101 case XML_ATTRIBUTE_NODE: 1102 list = ((xmlAttrPtr) node)->children; 1103 break; 1104 case XML_TEXT_NODE: 1105 case XML_CDATA_SECTION_NODE: 1106 case XML_PI_NODE: 1107 case XML_COMMENT_NODE: 1108 if (node->content != NULL) { 1109 ret = xmlStrlen(node->content); 1110 } 1111 break; 1112 case XML_ENTITY_REF_NODE: 1113 case XML_DOCUMENT_TYPE_NODE: 1114 case XML_ENTITY_NODE: 1115 case XML_DOCUMENT_FRAG_NODE: 1116 case XML_NOTATION_NODE: 1117 case XML_DTD_NODE: 1118 case XML_ELEMENT_DECL: 1119 case XML_ATTRIBUTE_DECL: 1120 case XML_ENTITY_DECL: 1121 case XML_NAMESPACE_DECL: 1122 case XML_XINCLUDE_START: 1123 case XML_XINCLUDE_END: 1124 ret = 1; 1125 break; 1126 } 1127 for (;list != NULL;ret++) 1128 list = list->next; 1129 return(ret); 1130} 1131 1132/** 1133 * xmlLsOneNode: 1134 * @output: the FILE * for the output 1135 * @node: the node to dump 1136 * 1137 * Dump to @output the type and name of @node. 1138 */ 1139void 1140xmlLsOneNode(FILE *output, xmlNodePtr node) { 1141 if (node == NULL) { 1142 fprintf(output, "NULL\n"); 1143 return; 1144 } 1145 switch (node->type) { 1146 case XML_ELEMENT_NODE: 1147 fprintf(output, "-"); 1148 break; 1149 case XML_ATTRIBUTE_NODE: 1150 fprintf(output, "a"); 1151 break; 1152 case XML_TEXT_NODE: 1153 fprintf(output, "t"); 1154 break; 1155 case XML_CDATA_SECTION_NODE: 1156 fprintf(output, "C"); 1157 break; 1158 case XML_ENTITY_REF_NODE: 1159 fprintf(output, "e"); 1160 break; 1161 case XML_ENTITY_NODE: 1162 fprintf(output, "E"); 1163 break; 1164 case XML_PI_NODE: 1165 fprintf(output, "p"); 1166 break; 1167 case XML_COMMENT_NODE: 1168 fprintf(output, "c"); 1169 break; 1170 case XML_DOCUMENT_NODE: 1171 fprintf(output, "d"); 1172 break; 1173 case XML_HTML_DOCUMENT_NODE: 1174 fprintf(output, "h"); 1175 break; 1176 case XML_DOCUMENT_TYPE_NODE: 1177 fprintf(output, "T"); 1178 break; 1179 case XML_DOCUMENT_FRAG_NODE: 1180 fprintf(output, "F"); 1181 break; 1182 case XML_NOTATION_NODE: 1183 fprintf(output, "N"); 1184 break; 1185 case XML_NAMESPACE_DECL: 1186 fprintf(output, "n"); 1187 break; 1188 default: 1189 fprintf(output, "?"); 1190 } 1191 if (node->type != XML_NAMESPACE_DECL) { 1192 if (node->properties != NULL) 1193 fprintf(output, "a"); 1194 else 1195 fprintf(output, "-"); 1196 if (node->nsDef != NULL) 1197 fprintf(output, "n"); 1198 else 1199 fprintf(output, "-"); 1200 } 1201 1202 fprintf(output, " %8d ", xmlLsCountNode(node)); 1203 1204 switch (node->type) { 1205 case XML_ELEMENT_NODE: 1206 if (node->name != NULL) 1207 fprintf(output, "%s", (const char *) node->name); 1208 break; 1209 case XML_ATTRIBUTE_NODE: 1210 if (node->name != NULL) 1211 fprintf(output, "%s", (const char *) node->name); 1212 break; 1213 case XML_TEXT_NODE: 1214 if (node->content != NULL) { 1215 xmlDebugDumpString(output, node->content); 1216 } 1217 break; 1218 case XML_CDATA_SECTION_NODE: 1219 break; 1220 case XML_ENTITY_REF_NODE: 1221 if (node->name != NULL) 1222 fprintf(output, "%s", (const char *) node->name); 1223 break; 1224 case XML_ENTITY_NODE: 1225 if (node->name != NULL) 1226 fprintf(output, "%s", (const char *) node->name); 1227 break; 1228 case XML_PI_NODE: 1229 if (node->name != NULL) 1230 fprintf(output, "%s", (const char *) node->name); 1231 break; 1232 case XML_COMMENT_NODE: 1233 break; 1234 case XML_DOCUMENT_NODE: 1235 break; 1236 case XML_HTML_DOCUMENT_NODE: 1237 break; 1238 case XML_DOCUMENT_TYPE_NODE: 1239 break; 1240 case XML_DOCUMENT_FRAG_NODE: 1241 break; 1242 case XML_NOTATION_NODE: 1243 break; 1244 case XML_NAMESPACE_DECL: { 1245 xmlNsPtr ns = (xmlNsPtr) node; 1246 1247 if (ns->prefix == NULL) 1248 fprintf(output, "default -> %s", ns->href); 1249 else 1250 fprintf(output, "%s -> %s", ns->prefix, ns->href); 1251 break; 1252 } 1253 default: 1254 if (node->name != NULL) 1255 fprintf(output, "%s", (const char *) node->name); 1256 } 1257 fprintf(output, "\n"); 1258} 1259 1260/** 1261 * xmlBoolToText: 1262 * @boolval: a bool to turn into text 1263 * 1264 * Convenient way to turn bool into text 1265 * 1266 * Returns a pointer to either "True" or "False" 1267 */ 1268const char * 1269xmlBoolToText(int boolval) 1270{ 1271 if (boolval) 1272 return("True"); 1273 else 1274 return("False"); 1275} 1276 1277/**************************************************************** 1278 * * 1279 * The XML shell related functions * 1280 * * 1281 ****************************************************************/ 1282 1283 1284 1285/* 1286 * TODO: Improvement/cleanups for the XML shell 1287 * - allow to shell out an editor on a subpart 1288 * - cleanup function registrations (with help) and calling 1289 * - provide registration routines 1290 */ 1291 1292/** 1293 * xmlShellPrintXPathError: 1294 * @errorType: valid xpath error id 1295 * @arg: the argument that cause xpath to fail 1296 * 1297 * Print the xpath error to libxml default error channel 1298 */ 1299void 1300xmlShellPrintXPathError(int errorType, const char *arg) 1301{ 1302 const char *default_arg = "Result"; 1303 1304 if (!arg) 1305 arg = default_arg; 1306 1307 switch (errorType) { 1308 case XPATH_UNDEFINED: 1309 xmlGenericError(xmlGenericErrorContext, 1310 "%s: no such node\n", arg); 1311 break; 1312 1313 case XPATH_BOOLEAN: 1314 xmlGenericError(xmlGenericErrorContext, 1315 "%s is a Boolean\n", arg); 1316 break; 1317 case XPATH_NUMBER: 1318 xmlGenericError(xmlGenericErrorContext, 1319 "%s is a number\n", arg); 1320 break; 1321 case XPATH_STRING: 1322 xmlGenericError(xmlGenericErrorContext, 1323 "%s is a string\n", arg); 1324 break; 1325 case XPATH_POINT: 1326 xmlGenericError(xmlGenericErrorContext, 1327 "%s is a point\n", arg); 1328 break; 1329 case XPATH_RANGE: 1330 xmlGenericError(xmlGenericErrorContext, 1331 "%s is a range\n", arg); 1332 break; 1333 case XPATH_LOCATIONSET: 1334 xmlGenericError(xmlGenericErrorContext, 1335 "%s is a range\n", arg); 1336 break; 1337 case XPATH_USERS: 1338 xmlGenericError(xmlGenericErrorContext, 1339 "%s is user-defined\n", arg); 1340 break; 1341 case XPATH_XSLT_TREE: 1342 xmlGenericError(xmlGenericErrorContext, 1343 "%s is an XSLT value tree\n", arg); 1344 break; 1345 } 1346 xmlGenericError(xmlGenericErrorContext, 1347 "Try casting the result string function (xpath builtin)\n", 1348 arg); 1349} 1350 1351 1352#ifdef LIBXML_OUTPUT_ENABLED 1353/** 1354 * xmlShellPrintNodeCtxt: 1355 * @ctxt : a non-null shell context 1356 * @node : a non-null node to print to the output FILE 1357 * 1358 * Print node to the output FILE 1359 */ 1360static void 1361xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node) 1362{ 1363 FILE *fp; 1364 1365 if (!node) 1366 return; 1367 if (ctxt == NULL) 1368 fp = stdout; 1369 else 1370 fp = ctxt->output; 1371 1372 if (node->type == XML_DOCUMENT_NODE) 1373 xmlDocDump(fp, (xmlDocPtr) node); 1374 else if (node->type == XML_ATTRIBUTE_NODE) 1375 xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0); 1376 else 1377 xmlElemDump(fp, node->doc, node); 1378 1379 fprintf(fp, "\n"); 1380} 1381 1382/** 1383 * xmlShellPrintNode: 1384 * @node : a non-null node to print to the output FILE 1385 * 1386 * Print node to the output FILE 1387 */ 1388void 1389xmlShellPrintNode(xmlNodePtr node) 1390{ 1391 xmlShellPrintNodeCtxt(NULL, node); 1392} 1393#endif /* LIBXML_OUTPUT_ENABLED */ 1394 1395/** 1396 * xmlShellPrintXPathResultCtxt: 1397 * @ctxt: a valid shell context 1398 * @list: a valid result generated by an xpath evaluation 1399 * 1400 * Prints result to the output FILE 1401 */ 1402static void 1403xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list) 1404{ 1405 if (!ctxt) 1406 return; 1407 1408 if (list != NULL) { 1409 switch (list->type) { 1410 case XPATH_NODESET:{ 1411#ifdef LIBXML_OUTPUT_ENABLED 1412 int indx; 1413 1414 if (list->nodesetval) { 1415 for (indx = 0; indx < list->nodesetval->nodeNr; 1416 indx++) { 1417 xmlShellPrintNodeCtxt(ctxt, 1418 list->nodesetval->nodeTab[indx]); 1419 } 1420 } else { 1421 xmlGenericError(xmlGenericErrorContext, 1422 "Empty node set\n"); 1423 } 1424 break; 1425#else 1426 xmlGenericError(xmlGenericErrorContext, 1427 "Node set\n"); 1428#endif /* LIBXML_OUTPUT_ENABLED */ 1429 } 1430 case XPATH_BOOLEAN: 1431 xmlGenericError(xmlGenericErrorContext, 1432 "Is a Boolean:%s\n", 1433 xmlBoolToText(list->boolval)); 1434 break; 1435 case XPATH_NUMBER: 1436 xmlGenericError(xmlGenericErrorContext, 1437 "Is a number:%0g\n", list->floatval); 1438 break; 1439 case XPATH_STRING: 1440 xmlGenericError(xmlGenericErrorContext, 1441 "Is a string:%s\n", list->stringval); 1442 break; 1443 1444 default: 1445 xmlShellPrintXPathError(list->type, NULL); 1446 } 1447 } 1448} 1449 1450/** 1451 * xmlShellPrintXPathResult: 1452 * @list: a valid result generated by an xpath evaluation 1453 * 1454 * Prints result to the output FILE 1455 */ 1456void 1457xmlShellPrintXPathResult(xmlXPathObjectPtr list) 1458{ 1459 xmlShellPrintXPathResultCtxt(NULL, list); 1460} 1461 1462/** 1463 * xmlShellList: 1464 * @ctxt: the shell context 1465 * @arg: unused 1466 * @node: a node 1467 * @node2: unused 1468 * 1469 * Implements the XML shell function "ls" 1470 * Does an Unix like listing of the given node (like a directory) 1471 * 1472 * Returns 0 1473 */ 1474int 1475xmlShellList(xmlShellCtxtPtr ctxt, 1476 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, 1477 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1478{ 1479 xmlNodePtr cur; 1480 if (!ctxt) 1481 return (0); 1482 if (node == NULL) { 1483 fprintf(ctxt->output, "NULL\n"); 1484 return (0); 1485 } 1486 if ((node->type == XML_DOCUMENT_NODE) || 1487 (node->type == XML_HTML_DOCUMENT_NODE)) { 1488 cur = ((xmlDocPtr) node)->children; 1489 } else if (node->type == XML_NAMESPACE_DECL) { 1490 xmlLsOneNode(ctxt->output, node); 1491 return (0); 1492 } else if (node->children != NULL) { 1493 cur = node->children; 1494 } else { 1495 xmlLsOneNode(ctxt->output, node); 1496 return (0); 1497 } 1498 while (cur != NULL) { 1499 xmlLsOneNode(ctxt->output, cur); 1500 cur = cur->next; 1501 } 1502 return (0); 1503} 1504 1505/** 1506 * xmlShellBase: 1507 * @ctxt: the shell context 1508 * @arg: unused 1509 * @node: a node 1510 * @node2: unused 1511 * 1512 * Implements the XML shell function "base" 1513 * dumps the current XML base of the node 1514 * 1515 * Returns 0 1516 */ 1517int 1518xmlShellBase(xmlShellCtxtPtr ctxt, 1519 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, 1520 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1521{ 1522 xmlChar *base; 1523 if (!ctxt) 1524 return 0; 1525 if (node == NULL) { 1526 fprintf(ctxt->output, "NULL\n"); 1527 return (0); 1528 } 1529 1530 base = xmlNodeGetBase(node->doc, node); 1531 1532 if (base == NULL) { 1533 fprintf(ctxt->output, " No base found !!!\n"); 1534 } else { 1535 fprintf(ctxt->output, "%s\n", base); 1536 xmlFree(base); 1537 } 1538 return (0); 1539} 1540 1541/** 1542 * xmlShellSetBase: 1543 * @ctxt: the shell context 1544 * @arg: the new base 1545 * @node: a node 1546 * @node2: unused 1547 * 1548 * Implements the XML shell function "setbase" 1549 * change the current XML base of the node 1550 * 1551 * Returns 0 1552 */ 1553static int 1554xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, 1555 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, 1556 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1557{ 1558 xmlNodeSetBase(node, (xmlChar*) arg); 1559 return (0); 1560} 1561 1562/** 1563 * xmlShellGrep: 1564 * @ctxt: the shell context 1565 * @arg: the string or regular expression to find 1566 * @node: a node 1567 * @node2: unused 1568 * 1569 * Implements the XML shell function "grep" 1570 * dumps informations about the node (namespace, attributes, content). 1571 * 1572 * Returns 0 1573 */ 1574static int 1575xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, 1576 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) 1577{ 1578 if (!ctxt) 1579 return (0); 1580 if (node == NULL) 1581 return (0); 1582 if (arg == NULL) 1583 return (0); 1584#ifdef LIBXML_REGEXP_ENABLED 1585 if ((xmlStrchr((xmlChar *) arg, '?')) || 1586 (xmlStrchr((xmlChar *) arg, '*')) || 1587 (xmlStrchr((xmlChar *) arg, '.')) || 1588 (xmlStrchr((xmlChar *) arg, '['))) { 1589 } 1590#endif 1591 while (node != NULL) { 1592 if (node->type == XML_COMMENT_NODE) { 1593 if (xmlStrstr(node->content, (xmlChar *) arg)) { 1594 1595 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node)); 1596 xmlShellList(ctxt, NULL, node, NULL); 1597 } 1598 } else if (node->type == XML_TEXT_NODE) { 1599 if (xmlStrstr(node->content, (xmlChar *) arg)) { 1600 1601 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent)); 1602 xmlShellList(ctxt, NULL, node->parent, NULL); 1603 } 1604 } 1605 1606 /* 1607 * Browse the full subtree, deep first 1608 */ 1609 1610 if ((node->type == XML_DOCUMENT_NODE) || 1611 (node->type == XML_HTML_DOCUMENT_NODE)) { 1612 node = ((xmlDocPtr) node)->children; 1613 } else if ((node->children != NULL) 1614 && (node->type != XML_ENTITY_REF_NODE)) { 1615 /* deep first */ 1616 node = node->children; 1617 } else if (node->next != NULL) { 1618 /* then siblings */ 1619 node = node->next; 1620 } else { 1621 /* go up to parents->next if needed */ 1622 while (node != NULL) { 1623 if (node->parent != NULL) { 1624 node = node->parent; 1625 } 1626 if (node->next != NULL) { 1627 node = node->next; 1628 break; 1629 } 1630 if (node->parent == NULL) { 1631 node = NULL; 1632 break; 1633 } 1634 } 1635 } 1636 } 1637 return (0); 1638} 1639 1640/** 1641 * xmlShellDir: 1642 * @ctxt: the shell context 1643 * @arg: unused 1644 * @node: a node 1645 * @node2: unused 1646 * 1647 * Implements the XML shell function "dir" 1648 * dumps informations about the node (namespace, attributes, content). 1649 * 1650 * Returns 0 1651 */ 1652int 1653xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, 1654 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, 1655 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1656{ 1657 if (!ctxt) 1658 return (0); 1659 if (node == NULL) { 1660 fprintf(ctxt->output, "NULL\n"); 1661 return (0); 1662 } 1663 if ((node->type == XML_DOCUMENT_NODE) || 1664 (node->type == XML_HTML_DOCUMENT_NODE)) { 1665 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node); 1666 } else if (node->type == XML_ATTRIBUTE_NODE) { 1667 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0); 1668 } else { 1669 xmlDebugDumpOneNode(ctxt->output, node, 0); 1670 } 1671 return (0); 1672} 1673 1674#ifdef LIBXML_SCHEMAS_ENABLED 1675/** 1676 * xmlShellRNGValidate: 1677 * @ctxt: the shell context 1678 * @schemas: the path to the Relax-NG schemas 1679 * @node: a node 1680 * @node2: unused 1681 * 1682 * Implements the XML shell function "relaxng" 1683 * validating the instance against a Relax-NG schemas 1684 * 1685 * Returns 0 1686 */ 1687static int 1688xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas, 1689 xmlNodePtr node ATTRIBUTE_UNUSED, 1690 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1691{ 1692 xmlRelaxNGPtr relaxngschemas; 1693 xmlRelaxNGParserCtxtPtr ctxt; 1694 xmlRelaxNGValidCtxtPtr vctxt; 1695 int ret; 1696 1697 ctxt = xmlRelaxNGNewParserCtxt(schemas); 1698 xmlRelaxNGSetParserErrors(ctxt, 1699 (xmlRelaxNGValidityErrorFunc) fprintf, 1700 (xmlRelaxNGValidityWarningFunc) fprintf, 1701 stderr); 1702 relaxngschemas = xmlRelaxNGParse(ctxt); 1703 xmlRelaxNGFreeParserCtxt(ctxt); 1704 if (relaxngschemas == NULL) { 1705 xmlGenericError(xmlGenericErrorContext, 1706 "Relax-NG schema %s failed to compile\n", schemas); 1707 return(-1); 1708 } 1709 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas); 1710 xmlRelaxNGSetValidErrors(vctxt, 1711 (xmlRelaxNGValidityErrorFunc) fprintf, 1712 (xmlRelaxNGValidityWarningFunc) fprintf, 1713 stderr); 1714 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc); 1715 if (ret == 0) { 1716 fprintf(stderr, "%s validates\n", sctxt->filename); 1717 } else if (ret > 0) { 1718 fprintf(stderr, "%s fails to validate\n", sctxt->filename); 1719 } else { 1720 fprintf(stderr, "%s validation generated an internal error\n", 1721 sctxt->filename); 1722 } 1723 xmlRelaxNGFreeValidCtxt(vctxt); 1724 if (relaxngschemas != NULL) 1725 xmlRelaxNGFree(relaxngschemas); 1726 return(0); 1727} 1728#endif 1729 1730#ifdef LIBXML_OUTPUT_ENABLED 1731/** 1732 * xmlShellCat: 1733 * @ctxt: the shell context 1734 * @arg: unused 1735 * @node: a node 1736 * @node2: unused 1737 * 1738 * Implements the XML shell function "cat" 1739 * dumps the serialization node content (XML or HTML). 1740 * 1741 * Returns 0 1742 */ 1743int 1744xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED, 1745 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) 1746{ 1747 if (!ctxt) 1748 return (0); 1749 if (node == NULL) { 1750 fprintf(ctxt->output, "NULL\n"); 1751 return (0); 1752 } 1753 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) { 1754#ifdef LIBXML_HTML_ENABLED 1755 if (node->type == XML_HTML_DOCUMENT_NODE) 1756 htmlDocDump(ctxt->output, (htmlDocPtr) node); 1757 else 1758 htmlNodeDumpFile(ctxt->output, ctxt->doc, node); 1759#else 1760 if (node->type == XML_DOCUMENT_NODE) 1761 xmlDocDump(ctxt->output, (xmlDocPtr) node); 1762 else 1763 xmlElemDump(ctxt->output, ctxt->doc, node); 1764#endif /* LIBXML_HTML_ENABLED */ 1765 } else { 1766 if (node->type == XML_DOCUMENT_NODE) 1767 xmlDocDump(ctxt->output, (xmlDocPtr) node); 1768 else 1769 xmlElemDump(ctxt->output, ctxt->doc, node); 1770 } 1771 fprintf(ctxt->output, "\n"); 1772 return (0); 1773} 1774#endif /* LIBXML_OUTPUT_ENABLED */ 1775 1776/** 1777 * xmlShellLoad: 1778 * @ctxt: the shell context 1779 * @filename: the file name 1780 * @node: unused 1781 * @node2: unused 1782 * 1783 * Implements the XML shell function "load" 1784 * loads a new document specified by the filename 1785 * 1786 * Returns 0 or -1 if loading failed 1787 */ 1788int 1789xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, 1790 xmlNodePtr node ATTRIBUTE_UNUSED, 1791 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1792{ 1793 xmlDocPtr doc; 1794 int html = 0; 1795 1796 if (ctxt->doc != NULL) 1797 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE); 1798 1799 if (html) { 1800#ifdef LIBXML_HTML_ENABLED 1801 doc = htmlParseFile(filename, NULL); 1802#else 1803 fprintf(ctxt->output, "HTML support not compiled in\n"); 1804 doc = NULL; 1805#endif /* LIBXML_HTML_ENABLED */ 1806 } else { 1807 doc = xmlParseFile(filename); 1808 } 1809 if (doc != NULL) { 1810 if (ctxt->loaded == 1) { 1811 xmlFreeDoc(ctxt->doc); 1812 } 1813 ctxt->loaded = 1; 1814#ifdef LIBXML_XPATH_ENABLED 1815 xmlXPathFreeContext(ctxt->pctxt); 1816#endif /* LIBXML_XPATH_ENABLED */ 1817 xmlFree(ctxt->filename); 1818 ctxt->doc = doc; 1819 ctxt->node = (xmlNodePtr) doc; 1820#ifdef LIBXML_XPATH_ENABLED 1821 ctxt->pctxt = xmlXPathNewContext(doc); 1822#endif /* LIBXML_XPATH_ENABLED */ 1823 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename); 1824 } else 1825 return (-1); 1826 return (0); 1827} 1828 1829#ifdef LIBXML_OUTPUT_ENABLED 1830/** 1831 * xmlShellWrite: 1832 * @ctxt: the shell context 1833 * @filename: the file name 1834 * @node: a node in the tree 1835 * @node2: unused 1836 * 1837 * Implements the XML shell function "write" 1838 * Write the current node to the filename, it saves the serialization 1839 * of the subtree under the @node specified 1840 * 1841 * Returns 0 or -1 in case of error 1842 */ 1843int 1844xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 1845 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1846{ 1847 if (node == NULL) 1848 return (-1); 1849 if ((filename == NULL) || (filename[0] == 0)) { 1850 xmlGenericError(xmlGenericErrorContext, 1851 "Write command requires a filename argument\n"); 1852 return (-1); 1853 } 1854#ifdef W_OK 1855 if (access((char *) filename, W_OK)) { 1856 xmlGenericError(xmlGenericErrorContext, 1857 "Cannot write to %s\n", filename); 1858 return (-1); 1859 } 1860#endif 1861 switch (node->type) { 1862 case XML_DOCUMENT_NODE: 1863 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { 1864 xmlGenericError(xmlGenericErrorContext, 1865 "Failed to write to %s\n", filename); 1866 return (-1); 1867 } 1868 break; 1869 case XML_HTML_DOCUMENT_NODE: 1870#ifdef LIBXML_HTML_ENABLED 1871 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 1872 xmlGenericError(xmlGenericErrorContext, 1873 "Failed to write to %s\n", filename); 1874 return (-1); 1875 } 1876#else 1877 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { 1878 xmlGenericError(xmlGenericErrorContext, 1879 "Failed to write to %s\n", filename); 1880 return (-1); 1881 } 1882#endif /* LIBXML_HTML_ENABLED */ 1883 break; 1884 default:{ 1885 FILE *f; 1886 1887 f = fopen((char *) filename, "w"); 1888 if (f == NULL) { 1889 xmlGenericError(xmlGenericErrorContext, 1890 "Failed to write to %s\n", filename); 1891 return (-1); 1892 } 1893 xmlElemDump(f, ctxt->doc, node); 1894 fclose(f); 1895 } 1896 } 1897 return (0); 1898} 1899 1900/** 1901 * xmlShellSave: 1902 * @ctxt: the shell context 1903 * @filename: the file name (optional) 1904 * @node: unused 1905 * @node2: unused 1906 * 1907 * Implements the XML shell function "save" 1908 * Write the current document to the filename, or it's original name 1909 * 1910 * Returns 0 or -1 in case of error 1911 */ 1912int 1913xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, 1914 xmlNodePtr node ATTRIBUTE_UNUSED, 1915 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1916{ 1917 if (ctxt->doc == NULL) 1918 return (-1); 1919 if ((filename == NULL) || (filename[0] == 0)) 1920 filename = ctxt->filename; 1921#ifdef W_OK 1922 if (access((char *) filename, W_OK)) { 1923 xmlGenericError(xmlGenericErrorContext, 1924 "Cannot save to %s\n", filename); 1925 return (-1); 1926 } 1927#endif 1928 switch (ctxt->doc->type) { 1929 case XML_DOCUMENT_NODE: 1930 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { 1931 xmlGenericError(xmlGenericErrorContext, 1932 "Failed to save to %s\n", filename); 1933 } 1934 break; 1935 case XML_HTML_DOCUMENT_NODE: 1936#ifdef LIBXML_HTML_ENABLED 1937 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 1938 xmlGenericError(xmlGenericErrorContext, 1939 "Failed to save to %s\n", filename); 1940 } 1941#else 1942 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { 1943 xmlGenericError(xmlGenericErrorContext, 1944 "Failed to save to %s\n", filename); 1945 } 1946#endif /* LIBXML_HTML_ENABLED */ 1947 break; 1948 default: 1949 xmlGenericError(xmlGenericErrorContext, 1950 "To save to subparts of a document use the 'write' command\n"); 1951 return (-1); 1952 1953 } 1954 return (0); 1955} 1956#endif /* LIBXML_OUTPUT_ENABLED */ 1957 1958#ifdef LIBXML_VALID_ENABLED 1959/** 1960 * xmlShellValidate: 1961 * @ctxt: the shell context 1962 * @dtd: the DTD URI (optional) 1963 * @node: unused 1964 * @node2: unused 1965 * 1966 * Implements the XML shell function "validate" 1967 * Validate the document, if a DTD path is provided, then the validation 1968 * is done against the given DTD. 1969 * 1970 * Returns 0 or -1 in case of error 1971 */ 1972int 1973xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, 1974 xmlNodePtr node ATTRIBUTE_UNUSED, 1975 xmlNodePtr node2 ATTRIBUTE_UNUSED) 1976{ 1977 xmlValidCtxt vctxt; 1978 int res = -1; 1979 1980 vctxt.userData = stderr; 1981 vctxt.error = (xmlValidityErrorFunc) fprintf; 1982 vctxt.warning = (xmlValidityWarningFunc) fprintf; 1983 1984 if ((dtd == NULL) || (dtd[0] == 0)) { 1985 res = xmlValidateDocument(&vctxt, ctxt->doc); 1986 } else { 1987 xmlDtdPtr subset; 1988 1989 subset = xmlParseDTD(NULL, (xmlChar *) dtd); 1990 if (subset != NULL) { 1991 res = xmlValidateDtd(&vctxt, ctxt->doc, subset); 1992 1993 xmlFreeDtd(subset); 1994 } 1995 } 1996 return (res); 1997} 1998#endif /* LIBXML_VALID_ENABLED */ 1999 2000/** 2001 * xmlShellDu: 2002 * @ctxt: the shell context 2003 * @arg: unused 2004 * @tree: a node defining a subtree 2005 * @node2: unused 2006 * 2007 * Implements the XML shell function "du" 2008 * show the structure of the subtree under node @tree 2009 * If @tree is null, the command works on the current node. 2010 * 2011 * Returns 0 or -1 in case of error 2012 */ 2013int 2014xmlShellDu(xmlShellCtxtPtr ctxt, 2015 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree, 2016 xmlNodePtr node2 ATTRIBUTE_UNUSED) 2017{ 2018 xmlNodePtr node; 2019 int indent = 0, i; 2020 2021 if (!ctxt) 2022 return (-1); 2023 2024 if (tree == NULL) 2025 return (-1); 2026 node = tree; 2027 while (node != NULL) { 2028 if ((node->type == XML_DOCUMENT_NODE) || 2029 (node->type == XML_HTML_DOCUMENT_NODE)) { 2030 fprintf(ctxt->output, "/\n"); 2031 } else if (node->type == XML_ELEMENT_NODE) { 2032 for (i = 0; i < indent; i++) 2033 fprintf(ctxt->output, " "); 2034 fprintf(ctxt->output, "%s\n", node->name); 2035 } else { 2036 } 2037 2038 /* 2039 * Browse the full subtree, deep first 2040 */ 2041 2042 if ((node->type == XML_DOCUMENT_NODE) || 2043 (node->type == XML_HTML_DOCUMENT_NODE)) { 2044 node = ((xmlDocPtr) node)->children; 2045 } else if ((node->children != NULL) 2046 && (node->type != XML_ENTITY_REF_NODE)) { 2047 /* deep first */ 2048 node = node->children; 2049 indent++; 2050 } else if ((node != tree) && (node->next != NULL)) { 2051 /* then siblings */ 2052 node = node->next; 2053 } else if (node != tree) { 2054 /* go up to parents->next if needed */ 2055 while (node != tree) { 2056 if (node->parent != NULL) { 2057 node = node->parent; 2058 indent--; 2059 } 2060 if ((node != tree) && (node->next != NULL)) { 2061 node = node->next; 2062 break; 2063 } 2064 if (node->parent == NULL) { 2065 node = NULL; 2066 break; 2067 } 2068 if (node == tree) { 2069 node = NULL; 2070 break; 2071 } 2072 } 2073 /* exit condition */ 2074 if (node == tree) 2075 node = NULL; 2076 } else 2077 node = NULL; 2078 } 2079 return (0); 2080} 2081 2082/** 2083 * xmlShellPwd: 2084 * @ctxt: the shell context 2085 * @buffer: the output buffer 2086 * @node: a node 2087 * @node2: unused 2088 * 2089 * Implements the XML shell function "pwd" 2090 * Show the full path from the root to the node, if needed building 2091 * thumblers when similar elements exists at a given ancestor level. 2092 * The output is compatible with XPath commands. 2093 * 2094 * Returns 0 or -1 in case of error 2095 */ 2096int 2097xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer, 2098 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) 2099{ 2100 xmlChar *path; 2101 2102 if (node == NULL) 2103 return (-1); 2104 2105 path = xmlGetNodePath(node); 2106 if (path == NULL) 2107 return (-1); 2108 2109 /* 2110 * This test prevents buffer overflow, because this routine 2111 * is only called by xmlShell, in which the second argument is 2112 * 500 chars long. 2113 * It is a dirty hack before a cleaner solution is found. 2114 * Documentation should mention that the second argument must 2115 * be at least 500 chars long, and could be stripped if too long. 2116 */ 2117 snprintf(buffer, 499, "%s", path); 2118 buffer[499] = '0'; 2119 xmlFree(path); 2120 2121 return (0); 2122} 2123 2124/** 2125 * xmlShell: 2126 * @doc: the initial document 2127 * @filename: the output buffer 2128 * @input: the line reading function 2129 * @output: the output FILE*, defaults to stdout if NULL 2130 * 2131 * Implements the XML shell 2132 * This allow to load, validate, view, modify and save a document 2133 * using a environment similar to a UNIX commandline. 2134 */ 2135void 2136xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, 2137 FILE * output) 2138{ 2139 char prompt[500] = "/ > "; 2140 char *cmdline = NULL, *cur; 2141 int nbargs; 2142 char command[100]; 2143 char arg[400]; 2144 int i; 2145 xmlShellCtxtPtr ctxt; 2146 xmlXPathObjectPtr list; 2147 2148 if (doc == NULL) 2149 return; 2150 if (filename == NULL) 2151 return; 2152 if (input == NULL) 2153 return; 2154 if (output == NULL) 2155 output = stdout; 2156 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt)); 2157 if (ctxt == NULL) 2158 return; 2159 ctxt->loaded = 0; 2160 ctxt->doc = doc; 2161 ctxt->input = input; 2162 ctxt->output = output; 2163 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename); 2164 ctxt->node = (xmlNodePtr) ctxt->doc; 2165 2166#ifdef LIBXML_XPATH_ENABLED 2167 ctxt->pctxt = xmlXPathNewContext(ctxt->doc); 2168 if (ctxt->pctxt == NULL) { 2169 xmlFree(ctxt); 2170 return; 2171 } 2172#endif /* LIBXML_XPATH_ENABLED */ 2173 while (1) { 2174 if (ctxt->node == (xmlNodePtr) ctxt->doc) 2175 snprintf(prompt, sizeof(prompt), "%s > ", "/"); 2176 else if ((ctxt->node != NULL) && (ctxt->node->name)) 2177 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name); 2178 else 2179 snprintf(prompt, sizeof(prompt), "? > "); 2180 prompt[sizeof(prompt) - 1] = 0; 2181 2182 /* 2183 * Get a new command line 2184 */ 2185 cmdline = ctxt->input(prompt); 2186 if (cmdline == NULL) 2187 break; 2188 2189 /* 2190 * Parse the command itself 2191 */ 2192 cur = cmdline; 2193 nbargs = 0; 2194 while ((*cur == ' ') || (*cur == '\t')) 2195 cur++; 2196 i = 0; 2197 while ((*cur != ' ') && (*cur != '\t') && 2198 (*cur != '\n') && (*cur != '\r')) { 2199 if (*cur == 0) 2200 break; 2201 command[i++] = *cur++; 2202 } 2203 command[i] = 0; 2204 if (i == 0) 2205 continue; 2206 nbargs++; 2207 2208 /* 2209 * Parse the argument 2210 */ 2211 while ((*cur == ' ') || (*cur == '\t')) 2212 cur++; 2213 i = 0; 2214 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) { 2215 if (*cur == 0) 2216 break; 2217 arg[i++] = *cur++; 2218 } 2219 arg[i] = 0; 2220 if (i != 0) 2221 nbargs++; 2222 2223 /* 2224 * start interpreting the command 2225 */ 2226 if (!strcmp(command, "exit")) 2227 break; 2228 if (!strcmp(command, "quit")) 2229 break; 2230 if (!strcmp(command, "bye")) 2231 break; 2232 if (!strcmp(command, "help")) { 2233 fprintf(ctxt->output, "\tbase display XML base of the node\n"); 2234 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n"); 2235 fprintf(ctxt->output, "\tbye leave shell\n"); 2236 fprintf(ctxt->output, "\tcat [node] display node or current node\n"); 2237 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n"); 2238 fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n"); 2239 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n"); 2240 fprintf(ctxt->output, "\texit leave shell\n"); 2241 fprintf(ctxt->output, "\thelp display this help\n"); 2242 fprintf(ctxt->output, "\tfree display memory usage\n"); 2243 fprintf(ctxt->output, "\tload [name] load a new document with name\n"); 2244 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n"); 2245#ifdef LIBXML_XPATH_ENABLED 2246 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n"); 2247#endif /* LIBXML_XPATH_ENABLED */ 2248 fprintf(ctxt->output, "\tpwd display current working directory\n"); 2249 fprintf(ctxt->output, "\tquit leave shell\n"); 2250#ifdef LIBXML_OUTPUT_ENABLED 2251 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n"); 2252 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n"); 2253#endif /* LIBXML_OUTPUT_ENABLED */ 2254#ifdef LIBXML_VALID_ENABLED 2255 fprintf(ctxt->output, "\tvalidate check the document for errors\n"); 2256#endif /* LIBXML_VALID_ENABLED */ 2257#ifdef LIBXML_SCHEMAS_ENABLED 2258 fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n"); 2259#endif 2260 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n"); 2261#ifdef LIBXML_VALID_ENABLED 2262 } else if (!strcmp(command, "validate")) { 2263 xmlShellValidate(ctxt, arg, NULL, NULL); 2264#endif /* LIBXML_VALID_ENABLED */ 2265 } else if (!strcmp(command, "load")) { 2266 xmlShellLoad(ctxt, arg, NULL, NULL); 2267#ifdef LIBXML_SCHEMAS_ENABLED 2268 } else if (!strcmp(command, "relaxng")) { 2269 xmlShellRNGValidate(ctxt, arg, NULL, NULL); 2270#endif 2271#ifdef LIBXML_OUTPUT_ENABLED 2272 } else if (!strcmp(command, "save")) { 2273 xmlShellSave(ctxt, arg, NULL, NULL); 2274 } else if (!strcmp(command, "write")) { 2275 xmlShellWrite(ctxt, arg, NULL, NULL); 2276#endif /* LIBXML_OUTPUT_ENABLED */ 2277 } else if (!strcmp(command, "grep")) { 2278 xmlShellGrep(ctxt, arg, ctxt->node, NULL); 2279 } else if (!strcmp(command, "free")) { 2280 if (arg[0] == 0) { 2281 xmlMemShow(ctxt->output, 0); 2282 } else { 2283 int len = 0; 2284 2285 sscanf(arg, "%d", &len); 2286 xmlMemShow(ctxt->output, len); 2287 } 2288 } else if (!strcmp(command, "pwd")) { 2289 char dir[500]; 2290 2291 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL)) 2292 fprintf(ctxt->output, "%s\n", dir); 2293 } else if (!strcmp(command, "du")) { 2294 xmlShellDu(ctxt, NULL, ctxt->node, NULL); 2295 } else if (!strcmp(command, "base")) { 2296 xmlShellBase(ctxt, NULL, ctxt->node, NULL); 2297#ifdef LIBXML_XPATH_ENABLED 2298 } else if (!strcmp(command, "xpath")) { 2299 if (arg[0] == 0) { 2300 xmlGenericError(xmlGenericErrorContext, 2301 "xpath: expression required\n"); 2302 } else { 2303 ctxt->pctxt->node = ctxt->node; 2304 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 2305 xmlXPathDebugDumpObject(ctxt->output, list, 0); 2306 xmlXPathFreeObject(list); 2307 } 2308#endif /* LIBXML_XPATH_ENABLED */ 2309 } else if (!strcmp(command, "setbase")) { 2310 xmlShellSetBase(ctxt, arg, ctxt->node, NULL); 2311 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) { 2312 int dir = (!strcmp(command, "dir")); 2313 2314 if (arg[0] == 0) { 2315 if (dir) 2316 xmlShellDir(ctxt, NULL, ctxt->node, NULL); 2317 else 2318 xmlShellList(ctxt, NULL, ctxt->node, NULL); 2319 } else { 2320 ctxt->pctxt->node = ctxt->node; 2321#ifdef LIBXML_XPATH_ENABLED 2322 ctxt->pctxt->node = ctxt->node; 2323 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 2324#else 2325 list = NULL; 2326#endif /* LIBXML_XPATH_ENABLED */ 2327 if (list != NULL) { 2328 switch (list->type) { 2329 case XPATH_UNDEFINED: 2330 xmlGenericError(xmlGenericErrorContext, 2331 "%s: no such node\n", arg); 2332 break; 2333 case XPATH_NODESET:{ 2334 int indx; 2335 2336 if (list->nodesetval == NULL) 2337 break; 2338 2339 for (indx = 0; 2340 indx < list->nodesetval->nodeNr; 2341 indx++) { 2342 if (dir) 2343 xmlShellDir(ctxt, NULL, 2344 list->nodesetval-> 2345 nodeTab[indx], NULL); 2346 else 2347 xmlShellList(ctxt, NULL, 2348 list->nodesetval-> 2349 nodeTab[indx], NULL); 2350 } 2351 break; 2352 } 2353 case XPATH_BOOLEAN: 2354 xmlGenericError(xmlGenericErrorContext, 2355 "%s is a Boolean\n", arg); 2356 break; 2357 case XPATH_NUMBER: 2358 xmlGenericError(xmlGenericErrorContext, 2359 "%s is a number\n", arg); 2360 break; 2361 case XPATH_STRING: 2362 xmlGenericError(xmlGenericErrorContext, 2363 "%s is a string\n", arg); 2364 break; 2365 case XPATH_POINT: 2366 xmlGenericError(xmlGenericErrorContext, 2367 "%s is a point\n", arg); 2368 break; 2369 case XPATH_RANGE: 2370 xmlGenericError(xmlGenericErrorContext, 2371 "%s is a range\n", arg); 2372 break; 2373 case XPATH_LOCATIONSET: 2374 xmlGenericError(xmlGenericErrorContext, 2375 "%s is a range\n", arg); 2376 break; 2377 case XPATH_USERS: 2378 xmlGenericError(xmlGenericErrorContext, 2379 "%s is user-defined\n", arg); 2380 break; 2381 case XPATH_XSLT_TREE: 2382 xmlGenericError(xmlGenericErrorContext, 2383 "%s is an XSLT value tree\n", 2384 arg); 2385 break; 2386 } 2387#ifdef LIBXML_XPATH_ENABLED 2388 xmlXPathFreeObject(list); 2389#endif 2390 } else { 2391 xmlGenericError(xmlGenericErrorContext, 2392 "%s: no such node\n", arg); 2393 } 2394 ctxt->pctxt->node = NULL; 2395 } 2396 } else if (!strcmp(command, "cd")) { 2397 if (arg[0] == 0) { 2398 ctxt->node = (xmlNodePtr) ctxt->doc; 2399 } else { 2400#ifdef LIBXML_XPATH_ENABLED 2401 ctxt->pctxt->node = ctxt->node; 2402 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 2403#else 2404 list = NULL; 2405#endif /* LIBXML_XPATH_ENABLED */ 2406 if (list != NULL) { 2407 switch (list->type) { 2408 case XPATH_UNDEFINED: 2409 xmlGenericError(xmlGenericErrorContext, 2410 "%s: no such node\n", arg); 2411 break; 2412 case XPATH_NODESET: 2413 if (list->nodesetval != NULL) { 2414 if (list->nodesetval->nodeNr == 1) { 2415 ctxt->node = list->nodesetval->nodeTab[0]; 2416 if ((ctxt->node != NULL) && 2417 (ctxt->node->type == 2418 XML_NAMESPACE_DECL)) { 2419 xmlGenericError(xmlGenericErrorContext, 2420 "cannot cd to namespace\n"); 2421 ctxt->node = NULL; 2422 } 2423 } else 2424 xmlGenericError(xmlGenericErrorContext, 2425 "%s is a %d Node Set\n", 2426 arg, 2427 list->nodesetval->nodeNr); 2428 } else 2429 xmlGenericError(xmlGenericErrorContext, 2430 "%s is an empty Node Set\n", 2431 arg); 2432 break; 2433 case XPATH_BOOLEAN: 2434 xmlGenericError(xmlGenericErrorContext, 2435 "%s is a Boolean\n", arg); 2436 break; 2437 case XPATH_NUMBER: 2438 xmlGenericError(xmlGenericErrorContext, 2439 "%s is a number\n", arg); 2440 break; 2441 case XPATH_STRING: 2442 xmlGenericError(xmlGenericErrorContext, 2443 "%s is a string\n", arg); 2444 break; 2445 case XPATH_POINT: 2446 xmlGenericError(xmlGenericErrorContext, 2447 "%s is a point\n", arg); 2448 break; 2449 case XPATH_RANGE: 2450 xmlGenericError(xmlGenericErrorContext, 2451 "%s is a range\n", arg); 2452 break; 2453 case XPATH_LOCATIONSET: 2454 xmlGenericError(xmlGenericErrorContext, 2455 "%s is a range\n", arg); 2456 break; 2457 case XPATH_USERS: 2458 xmlGenericError(xmlGenericErrorContext, 2459 "%s is user-defined\n", arg); 2460 break; 2461 case XPATH_XSLT_TREE: 2462 xmlGenericError(xmlGenericErrorContext, 2463 "%s is an XSLT value tree\n", 2464 arg); 2465 break; 2466 } 2467#ifdef LIBXML_XPATH_ENABLED 2468 xmlXPathFreeObject(list); 2469#endif 2470 } else { 2471 xmlGenericError(xmlGenericErrorContext, 2472 "%s: no such node\n", arg); 2473 } 2474 ctxt->pctxt->node = NULL; 2475 } 2476#ifdef LIBXML_OUTPUT_ENABLED 2477 } else if (!strcmp(command, "cat")) { 2478 if (arg[0] == 0) { 2479 xmlShellCat(ctxt, NULL, ctxt->node, NULL); 2480 } else { 2481 ctxt->pctxt->node = ctxt->node; 2482#ifdef LIBXML_XPATH_ENABLED 2483 ctxt->pctxt->node = ctxt->node; 2484 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 2485#else 2486 list = NULL; 2487#endif /* LIBXML_XPATH_ENABLED */ 2488 if (list != NULL) { 2489 switch (list->type) { 2490 case XPATH_UNDEFINED: 2491 xmlGenericError(xmlGenericErrorContext, 2492 "%s: no such node\n", arg); 2493 break; 2494 case XPATH_NODESET:{ 2495 int indx; 2496 2497 if (list->nodesetval == NULL) 2498 break; 2499 2500 for (indx = 0; 2501 indx < list->nodesetval->nodeNr; 2502 indx++) { 2503 if (i > 0) 2504 fprintf(ctxt->output, " -------\n"); 2505 xmlShellCat(ctxt, NULL, 2506 list->nodesetval-> 2507 nodeTab[indx], NULL); 2508 } 2509 break; 2510 } 2511 case XPATH_BOOLEAN: 2512 xmlGenericError(xmlGenericErrorContext, 2513 "%s is a Boolean\n", arg); 2514 break; 2515 case XPATH_NUMBER: 2516 xmlGenericError(xmlGenericErrorContext, 2517 "%s is a number\n", arg); 2518 break; 2519 case XPATH_STRING: 2520 xmlGenericError(xmlGenericErrorContext, 2521 "%s is a string\n", arg); 2522 break; 2523 case XPATH_POINT: 2524 xmlGenericError(xmlGenericErrorContext, 2525 "%s is a point\n", arg); 2526 break; 2527 case XPATH_RANGE: 2528 xmlGenericError(xmlGenericErrorContext, 2529 "%s is a range\n", arg); 2530 break; 2531 case XPATH_LOCATIONSET: 2532 xmlGenericError(xmlGenericErrorContext, 2533 "%s is a range\n", arg); 2534 break; 2535 case XPATH_USERS: 2536 xmlGenericError(xmlGenericErrorContext, 2537 "%s is user-defined\n", arg); 2538 break; 2539 case XPATH_XSLT_TREE: 2540 xmlGenericError(xmlGenericErrorContext, 2541 "%s is an XSLT value tree\n", 2542 arg); 2543 break; 2544 } 2545#ifdef LIBXML_XPATH_ENABLED 2546 xmlXPathFreeObject(list); 2547#endif 2548 } else { 2549 xmlGenericError(xmlGenericErrorContext, 2550 "%s: no such node\n", arg); 2551 } 2552 ctxt->pctxt->node = NULL; 2553 } 2554#endif /* LIBXML_OUTPUT_ENABLED */ 2555 } else { 2556 xmlGenericError(xmlGenericErrorContext, 2557 "Unknown command %s\n", command); 2558 } 2559 free(cmdline); /* not xmlFree here ! */ 2560 } 2561#ifdef LIBXML_XPATH_ENABLED 2562 xmlXPathFreeContext(ctxt->pctxt); 2563#endif /* LIBXML_XPATH_ENABLED */ 2564 if (ctxt->loaded) { 2565 xmlFreeDoc(ctxt->doc); 2566 } 2567 if (ctxt->filename != NULL) 2568 xmlFree(ctxt->filename); 2569 xmlFree(ctxt); 2570 if (cmdline != NULL) 2571 free(cmdline); /* not xmlFree here ! */ 2572} 2573 2574#endif /* LIBXML_DEBUG_ENABLED */ 2575