debugXML.c revision d6d7f7bf96a87688cc4bf756cf98367018e3ef88
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@w3.org> 8 */ 9 10#ifdef WIN32 11#include "win32config.h" 12#else 13#include "config.h" 14#endif 15 16#include <libxml/xmlversion.h> 17#ifdef LIBXML_DEBUG_ENABLED 18 19#include <stdio.h> 20#include <string.h> 21#ifdef HAVE_STDLIB_H 22#include <stdlib.h> 23#endif 24#ifdef HAVE_STRING_H 25#include <string.h> 26#endif 27#include <libxml/xmlmemory.h> 28#include <libxml/tree.h> 29#include <libxml/parser.h> 30#include <libxml/valid.h> 31#include <libxml/debugXML.h> 32#include <libxml/HTMLtree.h> 33#include <libxml/HTMLparser.h> 34#include <libxml/xmlerror.h> 35 36#define IS_BLANK(c) \ 37 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' ')) 38 39void xmlDebugDumpString(FILE *output, const xmlChar *str) { 40 int i; 41 if (str == NULL) { 42 fprintf(output, "(NULL)"); 43 return; 44 } 45 for (i = 0;i < 40;i++) 46 if (str[i] == 0) return; 47 else if (IS_BLANK(str[i])) fputc(' ', output); 48 else if (str[i] >= 0x80) 49 fprintf(output, "#%X", str[i]); 50 else fputc(str[i], output); 51 fprintf(output, "..."); 52} 53 54void xmlDebugDumpDtd(FILE *output, xmlDtdPtr dtd, int depth) { 55 int i; 56 char shift[100]; 57 58 for (i = 0;((i < depth) && (i < 25));i++) 59 shift[2 * i] = shift[2 * i + 1] = ' '; 60 shift[2 * i] = shift[2 * i + 1] = 0; 61 62 fprintf(output, shift); 63 64 if (dtd->type != XML_DTD_NODE) { 65 fprintf(output, "PBM: not a DTD\n"); 66 return; 67 } 68 if (dtd->name != NULL) 69 fprintf(output, "DTD(%s)", dtd->name); 70 else 71 fprintf(output, "DTD"); 72 if (dtd->ExternalID != NULL) 73 fprintf(output, ", PUBLIC %s", dtd->ExternalID); 74 if (dtd->SystemID != NULL) 75 fprintf(output, ", SYSTEM %s", dtd->SystemID); 76 fprintf(output, "\n"); 77 /* 78 * Do a bit of checking 79 */ 80 if (dtd->parent == NULL) 81 fprintf(output, "PBM: Dtd has no parent\n"); 82 if (dtd->doc == NULL) 83 fprintf(output, "PBM: Dtd has no doc\n"); 84 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc)) 85 fprintf(output, "PBM: Dtd doc differs from parent's one\n"); 86 if (dtd->prev == NULL) { 87 if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd)) 88 fprintf(output, "PBM: Dtd has no prev and not first of list\n"); 89 } else { 90 if (dtd->prev->next != (xmlNodePtr) dtd) 91 fprintf(output, "PBM: Dtd prev->next : back link wrong\n"); 92 } 93 if (dtd->next == NULL) { 94 if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd)) 95 fprintf(output, "PBM: Dtd has no next and not last of list\n"); 96 } else { 97 if (dtd->next->prev != (xmlNodePtr) dtd) 98 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n"); 99 } 100} 101 102void xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) { 103 int i; 104 char shift[100]; 105 106 for (i = 0;((i < depth) && (i < 25));i++) 107 shift[2 * i] = shift[2 * i + 1] = ' '; 108 shift[2 * i] = shift[2 * i + 1] = 0; 109 110 fprintf(output, shift); 111 112 if (attr->type != XML_ATTRIBUTE_DECL) { 113 fprintf(output, "PBM: not a Attr\n"); 114 return; 115 } 116 if (attr->name != NULL) 117 fprintf(output, "ATTRDECL(%s)", attr->name); 118 else 119 fprintf(output, "PBM ATTRDECL noname!!!"); 120 if (attr->elem != NULL) 121 fprintf(output, " for %s", attr->elem); 122 else 123 fprintf(output, " PBM noelem!!!"); 124 switch (attr->atype) { 125 case XML_ATTRIBUTE_CDATA: 126 fprintf(output, " CDATA"); 127 break; 128 case XML_ATTRIBUTE_ID: 129 fprintf(output, " ID"); 130 break; 131 case XML_ATTRIBUTE_IDREF: 132 fprintf(output, " IDREF"); 133 break; 134 case XML_ATTRIBUTE_IDREFS: 135 fprintf(output, " IDREFS"); 136 break; 137 case XML_ATTRIBUTE_ENTITY: 138 fprintf(output, " ENTITY"); 139 break; 140 case XML_ATTRIBUTE_ENTITIES: 141 fprintf(output, " ENTITIES"); 142 break; 143 case XML_ATTRIBUTE_NMTOKEN: 144 fprintf(output, " NMTOKEN"); 145 break; 146 case XML_ATTRIBUTE_NMTOKENS: 147 fprintf(output, " NMTOKENS"); 148 break; 149 case XML_ATTRIBUTE_ENUMERATION: 150 fprintf(output, " ENUMERATION"); 151 break; 152 case XML_ATTRIBUTE_NOTATION: 153 fprintf(output, " NOTATION "); 154 break; 155 } 156 if (attr->tree != NULL) { 157 int i; 158 xmlEnumerationPtr cur = attr->tree; 159 160 for (i = 0;i < 5; i++) { 161 if (i != 0) 162 fprintf(output, "|%s", cur->name); 163 else 164 fprintf(output, " (%s", cur->name); 165 cur = cur->next; 166 if (cur == NULL) break; 167 } 168 if (cur == NULL) 169 fprintf(output, ")"); 170 else 171 fprintf(output, "...)"); 172 } 173 switch (attr->def) { 174 case XML_ATTRIBUTE_NONE: 175 break; 176 case XML_ATTRIBUTE_REQUIRED: 177 fprintf(output, " REQUIRED"); 178 break; 179 case XML_ATTRIBUTE_IMPLIED: 180 fprintf(output, " IMPLIED"); 181 break; 182 case XML_ATTRIBUTE_FIXED: 183 fprintf(output, " FIXED"); 184 break; 185 } 186 if (attr->defaultValue != NULL) { 187 fprintf(output, "\""); 188 xmlDebugDumpString(output, attr->defaultValue); 189 fprintf(output, "\""); 190 } 191 printf("\n"); 192 193 /* 194 * Do a bit of checking 195 */ 196 if (attr->parent == NULL) 197 fprintf(output, "PBM: Attr has no parent\n"); 198 if (attr->doc == NULL) 199 fprintf(output, "PBM: Attr has no doc\n"); 200 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc)) 201 fprintf(output, "PBM: Attr doc differs from parent's one\n"); 202 if (attr->prev == NULL) { 203 if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr)) 204 fprintf(output, "PBM: Attr has no prev and not first of list\n"); 205 } else { 206 if (attr->prev->next != (xmlNodePtr) attr) 207 fprintf(output, "PBM: Attr prev->next : back link wrong\n"); 208 } 209 if (attr->next == NULL) { 210 if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr)) 211 fprintf(output, "PBM: Attr has no next and not last of list\n"); 212 } else { 213 if (attr->next->prev != (xmlNodePtr) attr) 214 fprintf(output, "PBM: Attr next->prev : forward link wrong\n"); 215 } 216} 217 218void xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) { 219 int i; 220 char shift[100]; 221 222 for (i = 0;((i < depth) && (i < 25));i++) 223 shift[2 * i] = shift[2 * i + 1] = ' '; 224 shift[2 * i] = shift[2 * i + 1] = 0; 225 226 fprintf(output, shift); 227 228 if (elem->type != XML_ELEMENT_DECL) { 229 fprintf(output, "PBM: not a Elem\n"); 230 return; 231 } 232 if (elem->name != NULL) { 233 fprintf(output, "ELEMDECL("); 234 xmlDebugDumpString(output, elem->name); 235 fprintf(output, ")"); 236 } else 237 fprintf(output, "PBM ELEMDECL noname!!!"); 238 switch (elem->etype) { 239 case XML_ELEMENT_TYPE_EMPTY: 240 fprintf(output, ", EMPTY"); 241 break; 242 case XML_ELEMENT_TYPE_ANY: 243 fprintf(output, ", ANY"); 244 break; 245 case XML_ELEMENT_TYPE_MIXED: 246 fprintf(output, ", MIXED "); 247 break; 248 case XML_ELEMENT_TYPE_ELEMENT: 249 fprintf(output, ", MIXED "); 250 break; 251 } 252 if (elem->content != NULL) { 253 char buf[5001]; 254 255 buf[0] = 0; 256 xmlSprintfElementContent(buf, elem->content, 1); 257 buf[5000] = 0; 258 fprintf(output, "%s", buf); 259 } 260 printf("\n"); 261 262 /* 263 * Do a bit of checking 264 */ 265 if (elem->parent == NULL) 266 fprintf(output, "PBM: Elem has no parent\n"); 267 if (elem->doc == NULL) 268 fprintf(output, "PBM: Elem has no doc\n"); 269 if ((elem->parent != NULL) && (elem->doc != elem->parent->doc)) 270 fprintf(output, "PBM: Elem doc differs from parent's one\n"); 271 if (elem->prev == NULL) { 272 if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem)) 273 fprintf(output, "PBM: Elem has no prev and not first of list\n"); 274 } else { 275 if (elem->prev->next != (xmlNodePtr) elem) 276 fprintf(output, "PBM: Elem prev->next : back link wrong\n"); 277 } 278 if (elem->next == NULL) { 279 if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem)) 280 fprintf(output, "PBM: Elem has no next and not last of list\n"); 281 } else { 282 if (elem->next->prev != (xmlNodePtr) elem) 283 fprintf(output, "PBM: Elem next->prev : forward link wrong\n"); 284 } 285} 286 287void xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) { 288 int i; 289 char shift[100]; 290 291 for (i = 0;((i < depth) && (i < 25));i++) 292 shift[2 * i] = shift[2 * i + 1] = ' '; 293 shift[2 * i] = shift[2 * i + 1] = 0; 294 295 fprintf(output, shift); 296 297 if (ent->type != XML_ENTITY_DECL) { 298 fprintf(output, "PBM: not a Entity decl\n"); 299 return; 300 } 301 if (ent->name != NULL) { 302 fprintf(output, "ENTITYDECL("); 303 xmlDebugDumpString(output, ent->name); 304 fprintf(output, ")"); 305 } else 306 fprintf(output, "PBM ENTITYDECL noname!!!"); 307 switch (ent->etype) { 308 case XML_INTERNAL_GENERAL_ENTITY: 309 fprintf(output, ", internal\n"); 310 break; 311 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 312 fprintf(output, ", external parsed\n"); 313 break; 314 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 315 fprintf(output, ", unparsed\n"); 316 break; 317 case XML_INTERNAL_PARAMETER_ENTITY: 318 fprintf(output, ", parameter\n"); 319 break; 320 case XML_EXTERNAL_PARAMETER_ENTITY: 321 fprintf(output, ", external parameter\n"); 322 break; 323 case XML_INTERNAL_PREDEFINED_ENTITY: 324 fprintf(output, ", predefined\n"); 325 break; 326 } 327 if (ent->ExternalID) { 328 fprintf(output, shift); 329 fprintf(output, " ExternalID=%s\n", ent->ExternalID); 330 } 331 if (ent->SystemID) { 332 fprintf(output, shift); 333 fprintf(output, " SystemID=%s\n", ent->SystemID); 334 } 335 if (ent->URI != NULL) { 336 fprintf(output, shift); 337 fprintf(output, " URI=%s\n", ent->URI); 338 } 339 if (ent->content) { 340 fprintf(output, shift); 341 fprintf(output, " content="); 342 xmlDebugDumpString(output, ent->content); 343 fprintf(output, "\n"); 344 } 345 346 /* 347 * Do a bit of checking 348 */ 349 if (ent->parent == NULL) 350 fprintf(output, "PBM: Ent has no parent\n"); 351 if (ent->doc == NULL) 352 fprintf(output, "PBM: Ent has no doc\n"); 353 if ((ent->parent != NULL) && (ent->doc != ent->parent->doc)) 354 fprintf(output, "PBM: Ent doc differs from parent's one\n"); 355 if (ent->prev == NULL) { 356 if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent)) 357 fprintf(output, "PBM: Ent has no prev and not first of list\n"); 358 } else { 359 if (ent->prev->next != (xmlNodePtr) ent) 360 fprintf(output, "PBM: Ent prev->next : back link wrong\n"); 361 } 362 if (ent->next == NULL) { 363 if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent)) 364 fprintf(output, "PBM: Ent has no next and not last of list\n"); 365 } else { 366 if (ent->next->prev != (xmlNodePtr) ent) 367 fprintf(output, "PBM: Ent next->prev : forward link wrong\n"); 368 } 369} 370 371void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) { 372 int i; 373 char shift[100]; 374 375 for (i = 0;((i < depth) && (i < 25));i++) 376 shift[2 * i] = shift[2 * i + 1] = ' '; 377 shift[2 * i] = shift[2 * i + 1] = 0; 378 379 fprintf(output, shift); 380 if (ns->type == XML_GLOBAL_NAMESPACE) 381 fprintf(output, "old "); 382 if (ns->href == NULL) { 383 if (ns->prefix != NULL) 384 fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix); 385 else 386 fprintf(output, "incomplete default namespace href=NULL\n"); 387 } else { 388 if (ns->prefix != NULL) 389 fprintf(output, "namespace %s href=", ns->prefix); 390 else 391 fprintf(output, "default namespace href="); 392 393 xmlDebugDumpString(output, ns->href); 394 fprintf(output, "\n"); 395 } 396} 397 398void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) { 399 while (ns != NULL) { 400 xmlDebugDumpNamespace(output, ns, depth); 401 ns = ns->next; 402 } 403} 404 405void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) { 406 int i; 407 char shift[100]; 408 409 for (i = 0;((i < depth) && (i < 25));i++) 410 shift[2 * i] = shift[2 * i + 1] = ' '; 411 shift[2 * i] = shift[2 * i + 1] = 0; 412 413 fprintf(output, shift); 414 switch (ent->etype) { 415 case XML_INTERNAL_GENERAL_ENTITY: 416 fprintf(output, "INTERNAL_GENERAL_ENTITY "); 417 break; 418 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 419 fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY "); 420 break; 421 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 422 fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY "); 423 break; 424 case XML_INTERNAL_PARAMETER_ENTITY: 425 fprintf(output, "INTERNAL_PARAMETER_ENTITY "); 426 break; 427 case XML_EXTERNAL_PARAMETER_ENTITY: 428 fprintf(output, "EXTERNAL_PARAMETER_ENTITY "); 429 break; 430 default: 431 fprintf(output, "ENTITY_%d ! ", ent->etype); 432 } 433 fprintf(output, "%s\n", ent->name); 434 if (ent->ExternalID) { 435 fprintf(output, shift); 436 fprintf(output, "ExternalID=%s\n", ent->ExternalID); 437 } 438 if (ent->SystemID) { 439 fprintf(output, shift); 440 fprintf(output, "SystemID=%s\n", ent->SystemID); 441 } 442 if (ent->URI) { 443 fprintf(output, shift); 444 fprintf(output, "URI=%s\n", ent->URI); 445 } 446 if (ent->content) { 447 fprintf(output, shift); 448 fprintf(output, "content="); 449 xmlDebugDumpString(output, ent->content); 450 fprintf(output, "\n"); 451 } 452} 453 454void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) { 455 int i; 456 char shift[100]; 457 458 for (i = 0;((i < depth) && (i < 25));i++) 459 shift[2 * i] = shift[2 * i + 1] = ' '; 460 shift[2 * i] = shift[2 * i + 1] = 0; 461 462 fprintf(output, shift); 463 464 fprintf(output, "ATTRIBUTE "); 465 xmlDebugDumpString(output, attr->name); 466 fprintf(output, "\n"); 467 if (attr->children != NULL) 468 xmlDebugDumpNodeList(output, attr->children, depth + 1); 469 470 /* 471 * Do a bit of checking 472 */ 473 if (attr->parent == NULL) 474 fprintf(output, "PBM: Attr has no parent\n"); 475 if (attr->doc == NULL) 476 fprintf(output, "PBM: Attr has no doc\n"); 477 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc)) 478 fprintf(output, "PBM: Attr doc differs from parent's one\n"); 479 if (attr->prev == NULL) { 480 if ((attr->parent != NULL) && (attr->parent->properties != attr)) 481 fprintf(output, "PBM: Attr has no prev and not first of list\n"); 482 } else { 483 if (attr->prev->next != attr) 484 fprintf(output, "PBM: Attr prev->next : back link wrong\n"); 485 } 486 if (attr->next != NULL) { 487 if (attr->next->prev != attr) 488 fprintf(output, "PBM: Attr next->prev : forward link wrong\n"); 489 } 490} 491 492void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) { 493 while (attr != NULL) { 494 xmlDebugDumpAttr(output, attr, depth); 495 attr = attr->next; 496 } 497} 498 499void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) { 500 int i; 501 char shift[100]; 502 503 for (i = 0;((i < depth) && (i < 25));i++) 504 shift[2 * i] = shift[2 * i + 1] = ' '; 505 shift[2 * i] = shift[2 * i + 1] = 0; 506 507 switch (node->type) { 508 case XML_ELEMENT_NODE: 509 fprintf(output, shift); 510 fprintf(output, "ELEMENT "); 511 if (node->ns != NULL) { 512 xmlDebugDumpString(output, node->ns->prefix); 513 fprintf(output, ":"); 514 } 515 xmlDebugDumpString(output, node->name); 516 fprintf(output, "\n"); 517 break; 518 case XML_ATTRIBUTE_NODE: 519 fprintf(output, shift); 520 fprintf(output, "Error, ATTRIBUTE found here\n"); 521 break; 522 case XML_TEXT_NODE: 523 fprintf(output, shift); 524 fprintf(output, "TEXT\n"); 525 break; 526 case XML_CDATA_SECTION_NODE: 527 fprintf(output, shift); 528 fprintf(output, "CDATA_SECTION\n"); 529 break; 530 case XML_ENTITY_REF_NODE: 531 fprintf(output, shift); 532 fprintf(output, "ENTITY_REF(%s)\n", node->name); 533 break; 534 case XML_ENTITY_NODE: 535 fprintf(output, shift); 536 fprintf(output, "ENTITY\n"); 537 break; 538 case XML_PI_NODE: 539 fprintf(output, shift); 540 fprintf(output, "PI %s\n", node->name); 541 break; 542 case XML_COMMENT_NODE: 543 fprintf(output, shift); 544 fprintf(output, "COMMENT\n"); 545 break; 546 case XML_DOCUMENT_NODE: 547 case XML_HTML_DOCUMENT_NODE: 548 fprintf(output, shift); 549 fprintf(output, "Error, DOCUMENT found here\n"); 550 break; 551 case XML_DOCUMENT_TYPE_NODE: 552 fprintf(output, shift); 553 fprintf(output, "DOCUMENT_TYPE\n"); 554 break; 555 case XML_DOCUMENT_FRAG_NODE: 556 fprintf(output, shift); 557 fprintf(output, "DOCUMENT_FRAG\n"); 558 break; 559 case XML_NOTATION_NODE: 560 fprintf(output, "NOTATION\n"); 561 break; 562 case XML_DTD_NODE: 563 xmlDebugDumpDtd(output, (xmlDtdPtr) node, depth); 564 return; 565 case XML_ELEMENT_DECL: 566 xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth); 567 return; 568 case XML_ATTRIBUTE_DECL: 569 xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth); 570 return; 571 case XML_ENTITY_DECL: 572 xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth); 573 return; 574 default: 575 fprintf(output, shift); 576 fprintf(output, "NODE_%d !!!\n", node->type); 577 return; 578 } 579 if (node->doc == NULL) { 580 fprintf(output, shift); 581 fprintf(output, "doc == NULL !!!\n"); 582 } 583 if (node->nsDef != NULL) 584 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1); 585 if (node->properties != NULL) 586 xmlDebugDumpAttrList(output, node->properties, depth + 1); 587 if (node->type != XML_ENTITY_REF_NODE) { 588 if (node->content != NULL) { 589 shift[2 * i] = shift[2 * i + 1] = ' ' ; 590 shift[2 * i + 2] = shift[2 * i + 3] = 0 ; 591 fprintf(output, shift); 592 fprintf(output, "content="); 593#ifndef XML_USE_BUFFER_CONTENT 594 xmlDebugDumpString(output, node->content); 595#else 596 xmlDebugDumpString(output, xmlBufferContent(node->content)); 597#endif 598 fprintf(output, "\n"); 599 } 600 } else { 601 xmlEntityPtr ent; 602 ent = xmlGetDocEntity(node->doc, node->name); 603 if (ent != NULL) 604 xmlDebugDumpEntity(output, ent, depth + 1); 605 } 606 /* 607 * Do a bit of checking 608 */ 609 if (node->parent == NULL) 610 fprintf(output, "PBM: Node has no parent\n"); 611 if (node->doc == NULL) 612 fprintf(output, "PBM: Node has no doc\n"); 613 if ((node->parent != NULL) && (node->doc != node->parent->doc)) 614 fprintf(output, "PBM: Node doc differs from parent's one\n"); 615 if (node->prev == NULL) { 616 if ((node->parent != NULL) && (node->parent->children != node)) 617 fprintf(output, "PBM: Node has no prev and not first of list\n"); 618 } else { 619 if (node->prev->next != node) 620 fprintf(output, "PBM: Node prev->next : back link wrong\n"); 621 } 622 if (node->next == NULL) { 623 if ((node->parent != NULL) && (node->parent->last != node)) 624 fprintf(output, "PBM: Node has no next and not last of list\n"); 625 } else { 626 if (node->next->prev != node) 627 fprintf(output, "PBM: Node next->prev : forward link wrong\n"); 628 } 629} 630 631void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) { 632 xmlDebugDumpOneNode(output, node, depth); 633 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) 634 xmlDebugDumpNodeList(output, node->children, depth + 1); 635} 636 637void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) { 638 while (node != NULL) { 639 xmlDebugDumpNode(output, node, depth); 640 node = node->next; 641 } 642} 643 644 645void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) { 646 if (output == NULL) output = stdout; 647 if (doc == NULL) { 648 fprintf(output, "DOCUMENT == NULL !\n"); 649 return; 650 } 651 652 switch (doc->type) { 653 case XML_ELEMENT_NODE: 654 fprintf(output, "Error, ELEMENT found here "); 655 break; 656 case XML_ATTRIBUTE_NODE: 657 fprintf(output, "Error, ATTRIBUTE found here\n"); 658 break; 659 case XML_TEXT_NODE: 660 fprintf(output, "Error, TEXT\n"); 661 break; 662 case XML_CDATA_SECTION_NODE: 663 fprintf(output, "Error, CDATA_SECTION\n"); 664 break; 665 case XML_ENTITY_REF_NODE: 666 fprintf(output, "Error, ENTITY_REF\n"); 667 break; 668 case XML_ENTITY_NODE: 669 fprintf(output, "Error, ENTITY\n"); 670 break; 671 case XML_PI_NODE: 672 fprintf(output, "Error, PI\n"); 673 break; 674 case XML_COMMENT_NODE: 675 fprintf(output, "Error, COMMENT\n"); 676 break; 677 case XML_DOCUMENT_NODE: 678 fprintf(output, "DOCUMENT\n"); 679 break; 680 case XML_HTML_DOCUMENT_NODE: 681 fprintf(output, "HTML DOCUMENT\n"); 682 break; 683 case XML_DOCUMENT_TYPE_NODE: 684 fprintf(output, "Error, DOCUMENT_TYPE\n"); 685 break; 686 case XML_DOCUMENT_FRAG_NODE: 687 fprintf(output, "Error, DOCUMENT_FRAG\n"); 688 break; 689 case XML_NOTATION_NODE: 690 fprintf(output, "Error, NOTATION\n"); 691 break; 692 default: 693 fprintf(output, "NODE_%d\n", doc->type); 694 } 695 if (doc->name != NULL) { 696 fprintf(output, "name="); 697 xmlDebugDumpString(output, BAD_CAST doc->name); 698 fprintf(output, "\n"); 699 } 700 if (doc->version != NULL) { 701 fprintf(output, "version="); 702 xmlDebugDumpString(output, doc->version); 703 fprintf(output, "\n"); 704 } 705 if (doc->encoding != NULL) { 706 fprintf(output, "encoding="); 707 xmlDebugDumpString(output, doc->encoding); 708 fprintf(output, "\n"); 709 } 710 if (doc->URL != NULL) { 711 fprintf(output, "URL="); 712 xmlDebugDumpString(output, doc->URL); 713 fprintf(output, "\n"); 714 } 715 if (doc->standalone) 716 fprintf(output, "standalone=true\n"); 717 if (doc->oldNs != NULL) 718 xmlDebugDumpNamespaceList(output, doc->oldNs, 0); 719} 720 721void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) { 722 if (output == NULL) output = stdout; 723 if (doc == NULL) { 724 fprintf(output, "DOCUMENT == NULL !\n"); 725 return; 726 } 727 xmlDebugDumpDocumentHead(output, doc); 728 if (((doc->type == XML_DOCUMENT_NODE) || 729 (doc->type == XML_HTML_DOCUMENT_NODE)) && 730 (doc->children != NULL)) 731 xmlDebugDumpNodeList(output, doc->children, 1); 732} 733 734void xmlDebugDumpDTD(FILE *output, xmlDtdPtr dtd) { 735 if (dtd == NULL) 736 return; 737 if (dtd->type != XML_DTD_NODE) { 738 fprintf(output, "PBM: not a DTD\n"); 739 return; 740 } 741 if (dtd->name != NULL) 742 fprintf(output, "DTD(%s)", dtd->name); 743 else 744 fprintf(output, "DTD"); 745 if (dtd->ExternalID != NULL) 746 fprintf(output, ", PUBLIC %s", dtd->ExternalID); 747 if (dtd->SystemID != NULL) 748 fprintf(output, ", SYSTEM %s", dtd->SystemID); 749 fprintf(output, "\n"); 750 /* 751 * Do a bit of checking 752 */ 753 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc)) 754 fprintf(output, "PBM: Dtd doc differs from parent's one\n"); 755 if (dtd->prev == NULL) { 756 if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd)) 757 fprintf(output, "PBM: Dtd has no prev and not first of list\n"); 758 } else { 759 if (dtd->prev->next != (xmlNodePtr) dtd) 760 fprintf(output, "PBM: Dtd prev->next : back link wrong\n"); 761 } 762 if (dtd->next == NULL) { 763 if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd)) 764 fprintf(output, "PBM: Dtd has no next and not last of list\n"); 765 } else { 766 if (dtd->next->prev != (xmlNodePtr) dtd) 767 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n"); 768 } 769 if (dtd->children == NULL) 770 fprintf(output, " DTD is empty\n"); 771 else 772 xmlDebugDumpNodeList(output, dtd->children, 1); 773} 774 775void xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output, 776 const xmlChar *name) { 777 fprintf(output, "%s : ", cur->name); 778 switch (cur->etype) { 779 case XML_INTERNAL_GENERAL_ENTITY: 780 fprintf(output, "INTERNAL GENERAL, "); 781 break; 782 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 783 fprintf(output, "EXTERNAL PARSED, "); 784 break; 785 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 786 fprintf(output, "EXTERNAL UNPARSED, "); 787 break; 788 case XML_INTERNAL_PARAMETER_ENTITY: 789 fprintf(output, "INTERNAL PARAMETER, "); 790 break; 791 case XML_EXTERNAL_PARAMETER_ENTITY: 792 fprintf(output, "EXTERNAL PARAMETER, "); 793 break; 794 default: 795 fprintf(output, "UNKNOWN TYPE %d", 796 cur->etype); 797 } 798 if (cur->ExternalID != NULL) 799 fprintf(output, "ID \"%s\"", cur->ExternalID); 800 if (cur->SystemID != NULL) 801 fprintf(output, "SYSTEM \"%s\"", cur->SystemID); 802 if (cur->orig != NULL) 803 fprintf(output, "\n orig \"%s\"", cur->orig); 804 if (cur->content != NULL) 805 fprintf(output, "\n content \"%s\"", cur->content); 806 fprintf(output, "\n"); 807} 808 809void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) { 810 if (output == NULL) output = stdout; 811 if (doc == NULL) { 812 fprintf(output, "DOCUMENT == NULL !\n"); 813 return; 814 } 815 816 switch (doc->type) { 817 case XML_ELEMENT_NODE: 818 fprintf(output, "Error, ELEMENT found here "); 819 break; 820 case XML_ATTRIBUTE_NODE: 821 fprintf(output, "Error, ATTRIBUTE found here\n"); 822 break; 823 case XML_TEXT_NODE: 824 fprintf(output, "Error, TEXT\n"); 825 break; 826 case XML_CDATA_SECTION_NODE: 827 fprintf(output, "Error, CDATA_SECTION\n"); 828 break; 829 case XML_ENTITY_REF_NODE: 830 fprintf(output, "Error, ENTITY_REF\n"); 831 break; 832 case XML_ENTITY_NODE: 833 fprintf(output, "Error, ENTITY\n"); 834 break; 835 case XML_PI_NODE: 836 fprintf(output, "Error, PI\n"); 837 break; 838 case XML_COMMENT_NODE: 839 fprintf(output, "Error, COMMENT\n"); 840 break; 841 case XML_DOCUMENT_NODE: 842 fprintf(output, "DOCUMENT\n"); 843 break; 844 case XML_HTML_DOCUMENT_NODE: 845 fprintf(output, "HTML DOCUMENT\n"); 846 break; 847 case XML_DOCUMENT_TYPE_NODE: 848 fprintf(output, "Error, DOCUMENT_TYPE\n"); 849 break; 850 case XML_DOCUMENT_FRAG_NODE: 851 fprintf(output, "Error, DOCUMENT_FRAG\n"); 852 break; 853 case XML_NOTATION_NODE: 854 fprintf(output, "Error, NOTATION\n"); 855 break; 856 default: 857 fprintf(output, "NODE_%d\n", doc->type); 858 } 859 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) { 860 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 861 doc->intSubset->entities; 862 fprintf(output, "Entities in internal subset\n"); 863 xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output); 864 } else 865 fprintf(output, "No entities in internal subset\n"); 866 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) { 867 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 868 doc->extSubset->entities; 869 fprintf(output, "Entities in external subset\n"); 870 xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output); 871 } else 872 fprintf(output, "No entities in external subset\n"); 873} 874 875static int xmlLsCountNode(xmlNodePtr node) { 876 int ret = 0; 877 xmlNodePtr list = NULL; 878 879 switch (node->type) { 880 case XML_ELEMENT_NODE: 881 list = node->children; 882 break; 883 case XML_DOCUMENT_NODE: 884 case XML_HTML_DOCUMENT_NODE: 885#ifdef LIBXML_SGML_ENABLED 886 case XML_SGML_DOCUMENT_NODE: 887#endif 888 list = ((xmlDocPtr) node)->children; 889 break; 890 case XML_ATTRIBUTE_NODE: 891 list = ((xmlAttrPtr) node)->children; 892 break; 893 case XML_TEXT_NODE: 894 case XML_CDATA_SECTION_NODE: 895 case XML_PI_NODE: 896 case XML_COMMENT_NODE: 897 if (node->content != NULL) { 898#ifndef XML_USE_BUFFER_CONTENT 899 ret = xmlStrlen(node->content); 900#else 901 ret = xmlBufferLength(node->content); 902#endif 903 } 904 break; 905 case XML_ENTITY_REF_NODE: 906 case XML_DOCUMENT_TYPE_NODE: 907 case XML_ENTITY_NODE: 908 case XML_DOCUMENT_FRAG_NODE: 909 case XML_NOTATION_NODE: 910 case XML_DTD_NODE: 911 case XML_ELEMENT_DECL: 912 case XML_ATTRIBUTE_DECL: 913 case XML_ENTITY_DECL: 914 ret = 1; 915 break; 916 } 917 for (;list != NULL;ret++) 918 list = list->next; 919 return(ret); 920} 921 922void xmlLsOneNode(FILE *output, xmlNodePtr node) { 923 switch (node->type) { 924 case XML_ELEMENT_NODE: 925 fprintf(output, "-"); 926 break; 927 case XML_ATTRIBUTE_NODE: 928 fprintf(output, "a"); 929 break; 930 case XML_TEXT_NODE: 931 fprintf(output, "t"); 932 break; 933 case XML_CDATA_SECTION_NODE: 934 fprintf(output, "c"); 935 break; 936 case XML_ENTITY_REF_NODE: 937 fprintf(output, "e"); 938 break; 939 case XML_ENTITY_NODE: 940 fprintf(output, "E"); 941 break; 942 case XML_PI_NODE: 943 fprintf(output, "p"); 944 break; 945 case XML_COMMENT_NODE: 946 fprintf(output, "c"); 947 break; 948 case XML_DOCUMENT_NODE: 949 fprintf(output, "d"); 950 break; 951 case XML_HTML_DOCUMENT_NODE: 952 fprintf(output, "h"); 953 break; 954 case XML_DOCUMENT_TYPE_NODE: 955 fprintf(output, "T"); 956 break; 957 case XML_DOCUMENT_FRAG_NODE: 958 fprintf(output, "F"); 959 break; 960 case XML_NOTATION_NODE: 961 fprintf(output, "N"); 962 break; 963 default: 964 fprintf(output, "?"); 965 } 966 if (node->properties != NULL) 967 fprintf(output, "a"); 968 else 969 fprintf(output, "-"); 970 if (node->nsDef != NULL) 971 fprintf(output, "n"); 972 else 973 fprintf(output, "-"); 974 975 fprintf(output, " %8d ", xmlLsCountNode(node)); 976 977 switch (node->type) { 978 case XML_ELEMENT_NODE: 979 if (node->name != NULL) 980 fprintf(output, "%s", node->name); 981 break; 982 case XML_ATTRIBUTE_NODE: 983 if (node->name != NULL) 984 fprintf(output, "%s", node->name); 985 break; 986 case XML_TEXT_NODE: 987 if (node->content != NULL) { 988#ifndef XML_USE_BUFFER_CONTENT 989 xmlDebugDumpString(output, node->content); 990#else 991 xmlDebugDumpString(output, xmlBufferContent(node->content)); 992#endif 993 } 994 break; 995 case XML_CDATA_SECTION_NODE: 996 break; 997 case XML_ENTITY_REF_NODE: 998 if (node->name != NULL) 999 fprintf(output, "%s", node->name); 1000 break; 1001 case XML_ENTITY_NODE: 1002 if (node->name != NULL) 1003 fprintf(output, "%s", node->name); 1004 break; 1005 case XML_PI_NODE: 1006 if (node->name != NULL) 1007 fprintf(output, "%s", node->name); 1008 break; 1009 case XML_COMMENT_NODE: 1010 break; 1011 case XML_DOCUMENT_NODE: 1012 break; 1013 case XML_HTML_DOCUMENT_NODE: 1014 break; 1015 case XML_DOCUMENT_TYPE_NODE: 1016 break; 1017 case XML_DOCUMENT_FRAG_NODE: 1018 break; 1019 case XML_NOTATION_NODE: 1020 break; 1021 default: 1022 if (node->name != NULL) 1023 fprintf(output, "%s", node->name); 1024 } 1025 fprintf(output, "\n"); 1026} 1027 1028/**************************************************************** 1029 * * 1030 * The XML shell related functions * 1031 * * 1032 ****************************************************************/ 1033 1034/* 1035 * TODO: Improvement/cleanups for the XML shell 1036 * - allow to shell out an editor on a subpart 1037 * - cleanup function registrations (with help) and calling 1038 * - provide registration routines 1039 */ 1040 1041/** 1042 * xmlShellList: 1043 * @ctxt: the shell context 1044 * @arg: unused 1045 * @node: a node 1046 * @node2: unused 1047 * 1048 * Implements the XML shell function "ls" 1049 * Does an Unix like listing of the given node (like a directory) 1050 * 1051 * Returns 0 1052 */ 1053int 1054xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, 1055 xmlNodePtr node2) { 1056 xmlNodePtr cur; 1057 1058 if ((node->type == XML_DOCUMENT_NODE) || 1059 (node->type == XML_HTML_DOCUMENT_NODE)) { 1060 cur = ((xmlDocPtr) node)->children; 1061 } else if (node->children != NULL) { 1062 cur = node->children; 1063 } else { 1064 xmlLsOneNode(stdout, node); 1065 return(0); 1066 } 1067 while (cur != NULL) { 1068 xmlLsOneNode(stdout, cur); 1069 cur = cur->next; 1070 } 1071 return(0); 1072} 1073 1074/** 1075 * xmlShellDir: 1076 * @ctxt: the shell context 1077 * @arg: unused 1078 * @node: a node 1079 * @node2: unused 1080 * 1081 * Implements the XML shell function "dir" 1082 * dumps informations about the node (namespace, attributes, content). 1083 * 1084 * Returns 0 1085 */ 1086int 1087xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, 1088 xmlNodePtr node2) { 1089 if ((node->type == XML_DOCUMENT_NODE) || 1090 (node->type == XML_HTML_DOCUMENT_NODE)) { 1091 xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node); 1092 } else if (node->type == XML_ATTRIBUTE_NODE) { 1093 xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0); 1094 } else { 1095 xmlDebugDumpOneNode(stdout, node, 0); 1096 } 1097 return(0); 1098} 1099 1100/** 1101 * xmlShellCat: 1102 * @ctxt: the shell context 1103 * @arg: unused 1104 * @node: a node 1105 * @node2: unused 1106 * 1107 * Implements the XML shell function "cat" 1108 * dumps the serialization node content (XML or HTML). 1109 * 1110 * Returns 0 1111 */ 1112int 1113xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, 1114 xmlNodePtr node2) { 1115 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) { 1116#ifdef LIBXML_HTML_ENABLED 1117 if (node->type == XML_HTML_DOCUMENT_NODE) 1118 htmlDocDump(stdout, (htmlDocPtr) node); 1119 else 1120 htmlNodeDumpFile(stdout, ctxt->doc, node); 1121#else 1122 if (node->type == XML_DOCUMENT_NODE) 1123 xmlDocDump(stdout, (xmlDocPtr) node); 1124 else 1125 xmlElemDump(stdout, ctxt->doc, node); 1126#endif /* LIBXML_HTML_ENABLED */ 1127 } else { 1128 if (node->type == XML_DOCUMENT_NODE) 1129 xmlDocDump(stdout, (xmlDocPtr) node); 1130 else 1131 xmlElemDump(stdout, ctxt->doc, node); 1132 } 1133 printf("\n"); 1134 return(0); 1135} 1136 1137/** 1138 * xmlShellLoad: 1139 * @ctxt: the shell context 1140 * @filename: the file name 1141 * @node: unused 1142 * @node2: unused 1143 * 1144 * Implements the XML shell function "load" 1145 * loads a new document specified by the filename 1146 * 1147 * Returns 0 or -1 if loading failed 1148 */ 1149int 1150xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 1151 xmlNodePtr node2) { 1152 xmlDocPtr doc; 1153 int html = 0; 1154 1155 if (ctxt->doc != NULL) 1156 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE); 1157 1158 if (html) { 1159#ifdef LIBXML_HTML_ENABLED 1160 doc = htmlParseFile(filename, NULL); 1161#else 1162 printf("HTML support not compiled in\n"); 1163 doc = NULL; 1164#endif /* LIBXML_HTML_ENABLED */ 1165 } else { 1166 doc = xmlParseFile(filename); 1167 } 1168 if (doc != NULL) { 1169 if (ctxt->loaded == 1) { 1170 xmlFreeDoc(ctxt->doc); 1171 } 1172 ctxt->loaded = 1; 1173#ifdef LIBXML_XPATH_ENABLED 1174 xmlXPathFreeContext(ctxt->pctxt); 1175#endif /* LIBXML_XPATH_ENABLED */ 1176 xmlFree(ctxt->filename); 1177 ctxt->doc = doc; 1178 ctxt->node = (xmlNodePtr) doc; 1179#ifdef LIBXML_XPATH_ENABLED 1180 ctxt->pctxt = xmlXPathNewContext(doc); 1181#endif /* LIBXML_XPATH_ENABLED */ 1182 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename); 1183 } else 1184 return(-1); 1185 return(0); 1186} 1187 1188/** 1189 * xmlShellWrite: 1190 * @ctxt: the shell context 1191 * @filename: the file name 1192 * @node: a node in the tree 1193 * @node2: unused 1194 * 1195 * Implements the XML shell function "write" 1196 * Write the current node to the filename, it saves the serailization 1197 * of the subtree under the @node specified 1198 * 1199 * Returns 0 or -1 in case of error 1200 */ 1201int 1202xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 1203 xmlNodePtr node2) { 1204 if (node == NULL) 1205 return(-1); 1206 if ((filename == NULL) || (filename[0] == 0)) { 1207 xmlGenericError(xmlGenericErrorContext, 1208 "Write command requires a filename argument\n"); 1209 return(-1); 1210 } 1211#ifdef W_OK 1212 if (access((char *) filename, W_OK)) { 1213 xmlGenericError(xmlGenericErrorContext, 1214 "Cannot write to %s\n", filename); 1215 return(-1); 1216 } 1217#endif 1218 switch(node->type) { 1219 case XML_DOCUMENT_NODE: 1220 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { 1221 xmlGenericError(xmlGenericErrorContext, 1222 "Failed to write to %s\n", filename); 1223 return(-1); 1224 } 1225 break; 1226 case XML_HTML_DOCUMENT_NODE: 1227#ifdef LIBXML_HTML_ENABLED 1228 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 1229 xmlGenericError(xmlGenericErrorContext, 1230 "Failed to write to %s\n", filename); 1231 return(-1); 1232 } 1233#else 1234 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { 1235 xmlGenericError(xmlGenericErrorContext, 1236 "Failed to write to %s\n", filename); 1237 return(-1); 1238 } 1239#endif /* LIBXML_HTML_ENABLED */ 1240 break; 1241 default: { 1242 FILE *f; 1243 1244 f = fopen((char *) filename, "w"); 1245 if (f == NULL) { 1246 xmlGenericError(xmlGenericErrorContext, 1247 "Failed to write to %s\n", filename); 1248 return(-1); 1249 } 1250 xmlElemDump(f, ctxt->doc, node); 1251 fclose(f); 1252 } 1253 } 1254 return(0); 1255} 1256 1257/** 1258 * xmlShellSave: 1259 * @ctxt: the shell context 1260 * @filename: the file name (optionnal) 1261 * @node: unused 1262 * @node2: unused 1263 * 1264 * Implements the XML shell function "save" 1265 * Write the current document to the filename, or it's original name 1266 * 1267 * Returns 0 or -1 in case of error 1268 */ 1269int 1270xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 1271 xmlNodePtr node2) { 1272 if (ctxt->doc == NULL) 1273 return(-1); 1274 if ((filename == NULL) || (filename[0] == 0)) 1275 filename = ctxt->filename; 1276#ifdef W_OK 1277 if (access((char *) filename, W_OK)) { 1278 xmlGenericError(xmlGenericErrorContext, 1279 "Cannot save to %s\n", filename); 1280 return(-1); 1281 } 1282#endif 1283 switch(ctxt->doc->type) { 1284 case XML_DOCUMENT_NODE: 1285 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { 1286 xmlGenericError(xmlGenericErrorContext, 1287 "Failed to save to %s\n", filename); 1288 } 1289 break; 1290 case XML_HTML_DOCUMENT_NODE: 1291#ifdef LIBXML_HTML_ENABLED 1292 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 1293 xmlGenericError(xmlGenericErrorContext, 1294 "Failed to save to %s\n", filename); 1295 } 1296#else 1297 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { 1298 xmlGenericError(xmlGenericErrorContext, 1299 "Failed to save to %s\n", filename); 1300 } 1301#endif /* LIBXML_HTML_ENABLED */ 1302 break; 1303 default: 1304 xmlGenericError(xmlGenericErrorContext, 1305 "To save to subparts of a document use the 'write' command\n"); 1306 return(-1); 1307 1308 } 1309 return(0); 1310} 1311 1312/** 1313 * xmlShellValidate: 1314 * @ctxt: the shell context 1315 * @dtd: the DTD URI (optionnal) 1316 * @node: unused 1317 * @node2: unused 1318 * 1319 * Implements the XML shell function "validate" 1320 * Validate the document, if a DTD path is provided, then the validation 1321 * is done against the given DTD. 1322 * 1323 * Returns 0 or -1 in case of error 1324 */ 1325int 1326xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node, 1327 xmlNodePtr node2) { 1328 xmlValidCtxt vctxt; 1329 int res = -1; 1330 1331 vctxt.userData = stderr; 1332 vctxt.error = (xmlValidityErrorFunc) fprintf; 1333 vctxt.warning = (xmlValidityWarningFunc) fprintf; 1334 1335 if ((dtd == NULL) || (dtd[0] == 0)) { 1336 res = xmlValidateDocument(&vctxt, ctxt->doc); 1337 } else { 1338 xmlDtdPtr subset; 1339 1340 subset = xmlParseDTD(NULL, (xmlChar *) dtd); 1341 if (subset != NULL) { 1342 res = xmlValidateDtd(&vctxt, ctxt->doc, subset); 1343 1344 xmlFreeDtd(subset); 1345 } 1346 } 1347 return(res); 1348} 1349 1350/** 1351 * xmlShellDu: 1352 * @ctxt: the shell context 1353 * @arg: unused 1354 * @tree: a node defining a subtree 1355 * @node2: unused 1356 * 1357 * Implements the XML shell function "du" 1358 * show the structure of the subtree under node @tree 1359 * If @tree is null, the command works on the current node. 1360 * 1361 * Returns 0 or -1 in case of error 1362 */ 1363int 1364xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree, 1365 xmlNodePtr node2) { 1366 xmlNodePtr node; 1367 int indent = 0,i; 1368 1369 if (tree == NULL) return(-1); 1370 node = tree; 1371 while (node != NULL) { 1372 if ((node->type == XML_DOCUMENT_NODE) || 1373 (node->type == XML_HTML_DOCUMENT_NODE)) { 1374 printf("/\n"); 1375 } else if (node->type == XML_ELEMENT_NODE) { 1376 for (i = 0;i < indent;i++) 1377 printf(" "); 1378 printf("%s\n", node->name); 1379 } else { 1380 } 1381 1382 /* 1383 * Browse the full subtree, deep first 1384 */ 1385 1386 if ((node->type == XML_DOCUMENT_NODE) || 1387 (node->type == XML_HTML_DOCUMENT_NODE)) { 1388 node = ((xmlDocPtr) node)->children; 1389 } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { 1390 /* deep first */ 1391 node = node->children; 1392 indent++; 1393 } else if ((node != tree) && (node->next != NULL)) { 1394 /* then siblings */ 1395 node = node->next; 1396 } else if (node != tree) { 1397 /* go up to parents->next if needed */ 1398 while (node != tree) { 1399 if (node->parent != NULL) { 1400 node = node->parent; 1401 indent--; 1402 } 1403 if ((node != tree) && (node->next != NULL)) { 1404 node = node->next; 1405 break; 1406 } 1407 if (node->parent == NULL) { 1408 node = NULL; 1409 break; 1410 } 1411 if (node == tree) { 1412 node = NULL; 1413 break; 1414 } 1415 } 1416 /* exit condition */ 1417 if (node == tree) 1418 node = NULL; 1419 } else 1420 node = NULL; 1421 } 1422 return(0); 1423} 1424 1425/** 1426 * xmlShellPwd: 1427 * @ctxt: the shell context 1428 * @buffer: the output buffer 1429 * @tree: a node 1430 * @node2: unused 1431 * 1432 * Implements the XML shell function "pwd" 1433 * Show the full path from the root to the node, if needed building 1434 * thumblers when similar elements exists at a given ancestor level. 1435 * The output is compatible with XPath commands. 1436 * 1437 * Returns 0 or -1 in case of error 1438 */ 1439int 1440xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node, 1441 xmlNodePtr node2) { 1442 xmlNodePtr cur, tmp, next; 1443 char buf[500]; 1444 char sep; 1445 const char *name; 1446 int occur = 0; 1447 1448 buffer[0] = 0; 1449 if (node == NULL) return(-1); 1450 cur = node; 1451 do { 1452 name = ""; 1453 sep= '?'; 1454 occur = 0; 1455 if ((cur->type == XML_DOCUMENT_NODE) || 1456 (cur->type == XML_HTML_DOCUMENT_NODE)) { 1457 sep = '/'; 1458 next = NULL; 1459 } else if (cur->type == XML_ELEMENT_NODE) { 1460 sep = '/'; 1461 name = (const char *)cur->name; 1462 next = cur->parent; 1463 1464 /* 1465 * Thumbler index computation 1466 */ 1467 tmp = cur->prev; 1468 while (tmp != NULL) { 1469 if (xmlStrEqual(cur->name, tmp->name)) 1470 occur++; 1471 tmp = tmp->prev; 1472 } 1473 if (occur == 0) { 1474 tmp = cur->next; 1475 while (tmp != NULL) { 1476 if (xmlStrEqual(cur->name, tmp->name)) 1477 occur++; 1478 tmp = tmp->next; 1479 } 1480 if (occur != 0) occur = 1; 1481 } else 1482 occur++; 1483 } else if (cur->type == XML_ATTRIBUTE_NODE) { 1484 sep = '@'; 1485 name = (const char *) (((xmlAttrPtr) cur)->name); 1486 next = ((xmlAttrPtr) cur)->parent; 1487 } else { 1488 next = cur->parent; 1489 } 1490 if (occur == 0) 1491#ifdef HAVE_SNPRINTF 1492 snprintf(buf, sizeof(buf), "%c%s%s", sep, name, buffer); 1493#else 1494 sprintf(buf, "%c%s%s", sep, name, buffer); 1495#endif 1496 else 1497#ifdef HAVE_SNPRINTF 1498 snprintf(buf, sizeof(buf), "%c%s[%d]%s", 1499 sep, name, occur, buffer); 1500#else 1501 sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer); 1502#endif 1503 buf[sizeof(buf) - 1] = 0; 1504 /* 1505 * This test prevents buffer overflow, because this routine 1506 * is only called by xmlShell, in which the second argument is 1507 * 500 chars long. 1508 * It is a dirty hack before a cleaner solution is found. 1509 * Documentation should mention that the second argument must 1510 * be at least 500 chars long, and could be stripped if too long. 1511 */ 1512 if (strlen(buffer) + strlen(buf) > 499) 1513 break; 1514 strcpy(buffer, buf); 1515 cur = next; 1516 } while (cur != NULL); 1517 return(0); 1518} 1519 1520/** 1521 * xmlShell 1522 * @doc: the initial document 1523 * @filename: the output buffer 1524 * @input: the line reading function 1525 * @output: the output FILE* 1526 * 1527 * Implements the XML shell 1528 * This allow to load, validate, view, modify and save a document 1529 * using a environment similar to a UNIX commandline. 1530 */ 1531void 1532xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, 1533 FILE *output) { 1534 char prompt[500] = "/ > "; 1535 char *cmdline = NULL, *cur; 1536 int nbargs; 1537 char command[100]; 1538 char arg[400]; 1539 int i; 1540 xmlShellCtxtPtr ctxt; 1541 xmlXPathObjectPtr list; 1542 1543 if (doc == NULL) 1544 return; 1545 if (filename == NULL) 1546 return; 1547 if (input == NULL) 1548 return; 1549 if (output == NULL) 1550 return; 1551 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt)); 1552 if (ctxt == NULL) 1553 return; 1554 ctxt->loaded = 0; 1555 ctxt->doc = doc; 1556 ctxt->input = input; 1557 ctxt->output = output; 1558 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename); 1559 ctxt->node = (xmlNodePtr) ctxt->doc; 1560 1561#ifdef LIBXML_XPATH_ENABLED 1562 ctxt->pctxt = xmlXPathNewContext(ctxt->doc); 1563 if (ctxt->pctxt == NULL) { 1564 xmlFree(ctxt); 1565 return; 1566 } 1567#endif /* LIBXML_XPATH_ENABLED */ 1568 while (1) { 1569 if (ctxt->node == (xmlNodePtr) ctxt->doc) 1570 sprintf(prompt, "%s > ", "/"); 1571 else if (ctxt->node->name) 1572#ifdef HAVE_SNPRINTF 1573 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name); 1574#else 1575 sprintf(prompt, "%s > ", ctxt->node->name); 1576#endif 1577 else 1578 sprintf(prompt, "? > "); 1579 prompt[sizeof(prompt) - 1] = 0; 1580 1581 /* 1582 * Get a new command line 1583 */ 1584 cmdline = ctxt->input(prompt); 1585 if (cmdline == NULL) break; 1586 1587 /* 1588 * Parse the command itself 1589 */ 1590 cur = cmdline; 1591 while ((*cur == ' ') || (*cur == '\t')) cur++; 1592 i = 0; 1593 while ((*cur != ' ') && (*cur != '\t') && 1594 (*cur != '\n') && (*cur != '\r')) { 1595 if (*cur == 0) 1596 break; 1597 command[i++] = *cur++; 1598 } 1599 command[i] = 0; 1600 if (i == 0) continue; 1601 nbargs++; 1602 1603 /* 1604 * Parse the argument 1605 */ 1606 while ((*cur == ' ') || (*cur == '\t')) cur++; 1607 i = 0; 1608 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) { 1609 if (*cur == 0) 1610 break; 1611 arg[i++] = *cur++; 1612 } 1613 arg[i] = 0; 1614 if (i != 0) 1615 nbargs++; 1616 1617 /* 1618 * start interpreting the command 1619 */ 1620 if (!strcmp(command, "exit")) 1621 break; 1622 if (!strcmp(command, "quit")) 1623 break; 1624 if (!strcmp(command, "bye")) 1625 break; 1626 if (!strcmp(command, "validate")) { 1627 xmlShellValidate(ctxt, arg, NULL, NULL); 1628 } else if (!strcmp(command, "load")) { 1629 xmlShellLoad(ctxt, arg, NULL, NULL); 1630 } else if (!strcmp(command, "save")) { 1631 xmlShellSave(ctxt, arg, NULL, NULL); 1632 } else if (!strcmp(command, "write")) { 1633 xmlShellWrite(ctxt, arg, NULL, NULL); 1634 } else if (!strcmp(command, "free")) { 1635 if (arg[0] == 0) { 1636 xmlMemShow(stdout, 0); 1637 } else { 1638 int len = 0; 1639 sscanf(arg, "%d", &len); 1640 xmlMemShow(stdout, len); 1641 } 1642 } else if (!strcmp(command, "pwd")) { 1643 char dir[500]; 1644 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL)) 1645 printf("%s\n", dir); 1646 } else if (!strcmp(command, "du")) { 1647 xmlShellDu(ctxt, NULL, ctxt->node, NULL); 1648 } else if ((!strcmp(command, "ls")) || 1649 (!strcmp(command, "dir"))) { 1650 int dir = (!strcmp(command, "dir")); 1651 if (arg[0] == 0) { 1652 if (dir) 1653 xmlShellDir(ctxt, NULL, ctxt->node, NULL); 1654 else 1655 xmlShellList(ctxt, NULL, ctxt->node, NULL); 1656 } else { 1657 ctxt->pctxt->node = ctxt->node; 1658#ifdef LIBXML_XPATH_ENABLED 1659 ctxt->pctxt->node = ctxt->node; 1660 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 1661#else 1662 list = NULL; 1663#endif /* LIBXML_XPATH_ENABLED */ 1664 if (list != NULL) { 1665 switch (list->type) { 1666 case XPATH_UNDEFINED: 1667 xmlGenericError(xmlGenericErrorContext, 1668 "%s: no such node\n", arg); 1669 break; 1670 case XPATH_NODESET: { 1671 int i; 1672 1673 for (i = 0;i < list->nodesetval->nodeNr;i++) { 1674 if (dir) 1675 xmlShellDir(ctxt, NULL, 1676 list->nodesetval->nodeTab[i], NULL); 1677 else 1678 xmlShellList(ctxt, NULL, 1679 list->nodesetval->nodeTab[i], NULL); 1680 } 1681 break; 1682 } 1683 case XPATH_BOOLEAN: 1684 xmlGenericError(xmlGenericErrorContext, 1685 "%s is a Boolean\n", arg); 1686 break; 1687 case XPATH_NUMBER: 1688 xmlGenericError(xmlGenericErrorContext, 1689 "%s is a number\n", arg); 1690 break; 1691 case XPATH_STRING: 1692 xmlGenericError(xmlGenericErrorContext, 1693 "%s is a string\n", arg); 1694 break; 1695 case XPATH_POINT: 1696 xmlGenericError(xmlGenericErrorContext, 1697 "%s is a point\n", arg); 1698 break; 1699 case XPATH_RANGE: 1700 xmlGenericError(xmlGenericErrorContext, 1701 "%s is a range\n", arg); 1702 break; 1703 case XPATH_LOCATIONSET: 1704 xmlGenericError(xmlGenericErrorContext, 1705 "%s is a range\n", arg); 1706 break; 1707 case XPATH_USERS: 1708 xmlGenericError(xmlGenericErrorContext, 1709 "%s is user-defined\n", arg); 1710 break; 1711 } 1712 xmlXPathFreeNodeSetList(list); 1713 } else { 1714 xmlGenericError(xmlGenericErrorContext, 1715 "%s: no such node\n", arg); 1716 } 1717 ctxt->pctxt->node = NULL; 1718 } 1719 } else if (!strcmp(command, "cd")) { 1720 if (arg[0] == 0) { 1721 ctxt->node = (xmlNodePtr) ctxt->doc; 1722 } else { 1723#ifdef LIBXML_XPATH_ENABLED 1724 ctxt->pctxt->node = ctxt->node; 1725 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 1726#else 1727 list = NULL; 1728#endif /* LIBXML_XPATH_ENABLED */ 1729 if (list != NULL) { 1730 switch (list->type) { 1731 case XPATH_UNDEFINED: 1732 xmlGenericError(xmlGenericErrorContext, 1733 "%s: no such node\n", arg); 1734 break; 1735 case XPATH_NODESET: 1736 if (list->nodesetval->nodeNr == 1) { 1737 ctxt->node = list->nodesetval->nodeTab[0]; 1738 } else 1739 xmlGenericError(xmlGenericErrorContext, 1740 "%s is a %d Node Set\n", 1741 arg, list->nodesetval->nodeNr); 1742 break; 1743 case XPATH_BOOLEAN: 1744 xmlGenericError(xmlGenericErrorContext, 1745 "%s is a Boolean\n", arg); 1746 break; 1747 case XPATH_NUMBER: 1748 xmlGenericError(xmlGenericErrorContext, 1749 "%s is a number\n", arg); 1750 break; 1751 case XPATH_STRING: 1752 xmlGenericError(xmlGenericErrorContext, 1753 "%s is a string\n", arg); 1754 break; 1755 case XPATH_POINT: 1756 xmlGenericError(xmlGenericErrorContext, 1757 "%s is a point\n", arg); 1758 break; 1759 case XPATH_RANGE: 1760 xmlGenericError(xmlGenericErrorContext, 1761 "%s is a range\n", arg); 1762 break; 1763 case XPATH_LOCATIONSET: 1764 xmlGenericError(xmlGenericErrorContext, 1765 "%s is a range\n", arg); 1766 break; 1767 case XPATH_USERS: 1768 xmlGenericError(xmlGenericErrorContext, 1769 "%s is user-defined\n", arg); 1770 break; 1771 } 1772 xmlXPathFreeNodeSetList(list); 1773 } else { 1774 xmlGenericError(xmlGenericErrorContext, 1775 "%s: no such node\n", arg); 1776 } 1777 ctxt->pctxt->node = NULL; 1778 } 1779 } else if (!strcmp(command, "cat")) { 1780 if (arg[0] == 0) { 1781 xmlShellCat(ctxt, NULL, ctxt->node, NULL); 1782 } else { 1783 ctxt->pctxt->node = ctxt->node; 1784#ifdef LIBXML_XPATH_ENABLED 1785 ctxt->pctxt->node = ctxt->node; 1786 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 1787#else 1788 list = NULL; 1789#endif /* LIBXML_XPATH_ENABLED */ 1790 if (list != NULL) { 1791 switch (list->type) { 1792 case XPATH_UNDEFINED: 1793 xmlGenericError(xmlGenericErrorContext, 1794 "%s: no such node\n", arg); 1795 break; 1796 case XPATH_NODESET: { 1797 int i; 1798 1799 for (i = 0;i < list->nodesetval->nodeNr;i++) { 1800 if (i > 0) printf(" -------\n"); 1801 xmlShellCat(ctxt, NULL, 1802 list->nodesetval->nodeTab[i], NULL); 1803 } 1804 break; 1805 } 1806 case XPATH_BOOLEAN: 1807 xmlGenericError(xmlGenericErrorContext, 1808 "%s is a Boolean\n", arg); 1809 break; 1810 case XPATH_NUMBER: 1811 xmlGenericError(xmlGenericErrorContext, 1812 "%s is a number\n", arg); 1813 break; 1814 case XPATH_STRING: 1815 xmlGenericError(xmlGenericErrorContext, 1816 "%s is a string\n", arg); 1817 break; 1818 case XPATH_POINT: 1819 xmlGenericError(xmlGenericErrorContext, 1820 "%s is a point\n", arg); 1821 break; 1822 case XPATH_RANGE: 1823 xmlGenericError(xmlGenericErrorContext, 1824 "%s is a range\n", arg); 1825 break; 1826 case XPATH_LOCATIONSET: 1827 xmlGenericError(xmlGenericErrorContext, 1828 "%s is a range\n", arg); 1829 break; 1830 case XPATH_USERS: 1831 xmlGenericError(xmlGenericErrorContext, 1832 "%s is user-defined\n", arg); 1833 break; 1834 } 1835 xmlXPathFreeNodeSetList(list); 1836 } else { 1837 xmlGenericError(xmlGenericErrorContext, 1838 "%s: no such node\n", arg); 1839 } 1840 ctxt->pctxt->node = NULL; 1841 } 1842 } else { 1843 xmlGenericError(xmlGenericErrorContext, 1844 "Unknown command %s\n", command); 1845 } 1846 free(cmdline); /* not xmlFree here ! */ 1847 } 1848#ifdef LIBXML_XPATH_ENABLED 1849 xmlXPathFreeContext(ctxt->pctxt); 1850#endif /* LIBXML_XPATH_ENABLED */ 1851 if (ctxt->loaded) { 1852 xmlFreeDoc(ctxt->doc); 1853 } 1854 xmlFree(ctxt); 1855 if (cmdline != NULL) 1856 free(cmdline); /* not xmlFree here ! */ 1857} 1858 1859#endif /* LIBXML_DEBUG_ENABLED */ 1860