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