debugXML.c revision dbfd641b78b5a98e790459e13d126e2784a7adeb
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#include <stdio.h> 16#ifdef HAVE_STDLIB_H 17#include <stdlib.h> 18#endif 19#include "xmlmemory.h" 20#include "tree.h" 21#include "parser.h" 22#include "debugXML.h" 23#include "HTMLtree.h" 24#include "HTMLparser.h" 25 26#define IS_BLANK(c) \ 27 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' ')) 28 29void xmlDebugDumpString(FILE *output, const xmlChar *str) { 30 int i; 31 for (i = 0;i < 40;i++) 32 if (str[i] == 0) return; 33 else if (IS_BLANK(str[i])) fputc(' ', output); 34 else fputc(str[i], output); 35 fprintf(output, "..."); 36} 37 38void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) { 39 int i; 40 char shift[100]; 41 42 for (i = 0;((i < depth) && (i < 25));i++) 43 shift[2 * i] = shift[2 * i + 1] = ' '; 44 shift[2 * i] = shift[2 * i + 1] = 0; 45 46 fprintf(output, shift); 47 if (ns->type == XML_GLOBAL_NAMESPACE) 48 fprintf(output, "old "); 49 if (ns->prefix != NULL) 50 fprintf(output, "namespace %s href=", ns->prefix); 51 else 52 fprintf(output, "default namespace href="); 53 54 xmlDebugDumpString(output, ns->href); 55 fprintf(output, "\n"); 56} 57 58void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) { 59 while (ns != NULL) { 60 xmlDebugDumpNamespace(output, ns, depth); 61 ns = ns->next; 62 } 63} 64 65void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, 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 switch (ent->type) { 75 case XML_INTERNAL_GENERAL_ENTITY: 76 fprintf(output, "INTERNAL_GENERAL_ENTITY "); 77 break; 78 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 79 fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY "); 80 break; 81 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 82 fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY "); 83 break; 84 case XML_INTERNAL_PARAMETER_ENTITY: 85 fprintf(output, "INTERNAL_PARAMETER_ENTITY "); 86 break; 87 case XML_EXTERNAL_PARAMETER_ENTITY: 88 fprintf(output, "EXTERNAL_PARAMETER_ENTITY "); 89 break; 90 default: 91 fprintf(output, "ENTITY_%d ! ", ent->type); 92 } 93 fprintf(output, "%s\n", ent->name); 94 if (ent->ExternalID) { 95 fprintf(output, shift); 96 fprintf(output, "ExternalID=%s\n", ent->ExternalID); 97 } 98 if (ent->SystemID) { 99 fprintf(output, shift); 100 fprintf(output, "SystemID=%s\n", ent->SystemID); 101 } 102 if (ent->content) { 103 fprintf(output, shift); 104 fprintf(output, "content="); 105 xmlDebugDumpString(output, ent->content); 106 fprintf(output, "\n"); 107 } 108} 109 110void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) { 111 int i; 112 char shift[100]; 113 114 for (i = 0;((i < depth) && (i < 25));i++) 115 shift[2 * i] = shift[2 * i + 1] = ' '; 116 shift[2 * i] = shift[2 * i + 1] = 0; 117 118 fprintf(output, shift); 119 fprintf(output, "ATTRIBUTE %s\n", attr->name); 120 if (attr->val != NULL) 121 xmlDebugDumpNodeList(output, attr->val, depth + 1); 122} 123 124void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) { 125 while (attr != NULL) { 126 xmlDebugDumpAttr(output, attr, depth); 127 attr = attr->next; 128 } 129} 130 131void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) { 132 int i; 133 char shift[100]; 134 135 for (i = 0;((i < depth) && (i < 25));i++) 136 shift[2 * i] = shift[2 * i + 1] = ' '; 137 shift[2 * i] = shift[2 * i + 1] = 0; 138 139 fprintf(output, shift); 140 switch (node->type) { 141 case XML_ELEMENT_NODE: 142 fprintf(output, "ELEMENT "); 143 if (node->ns != NULL) 144 fprintf(output, "%s:%s\n", node->ns->prefix, node->name); 145 else 146 fprintf(output, "%s\n", node->name); 147 break; 148 case XML_ATTRIBUTE_NODE: 149 fprintf(output, "Error, ATTRIBUTE found here\n"); 150 break; 151 case XML_TEXT_NODE: 152 fprintf(output, "TEXT\n"); 153 break; 154 case XML_CDATA_SECTION_NODE: 155 fprintf(output, "CDATA_SECTION\n"); 156 break; 157 case XML_ENTITY_REF_NODE: 158 fprintf(output, "ENTITY_REF\n"); 159 break; 160 case XML_ENTITY_NODE: 161 fprintf(output, "ENTITY\n"); 162 break; 163 case XML_PI_NODE: 164 fprintf(output, "PI %s\n", node->name); 165 break; 166 case XML_COMMENT_NODE: 167 fprintf(output, "COMMENT\n"); 168 break; 169 case XML_DOCUMENT_NODE: 170 case XML_HTML_DOCUMENT_NODE: 171 fprintf(output, "Error, DOCUMENT found here\n"); 172 break; 173 case XML_DOCUMENT_TYPE_NODE: 174 fprintf(output, "DOCUMENT_TYPE\n"); 175 break; 176 case XML_DOCUMENT_FRAG_NODE: 177 fprintf(output, "DOCUMENT_FRAG\n"); 178 break; 179 case XML_NOTATION_NODE: 180 fprintf(output, "NOTATION\n"); 181 break; 182 default: 183 fprintf(output, "NODE_%d\n", node->type); 184 } 185 if (node->doc == NULL) { 186 fprintf(output, shift); 187 fprintf(output, "doc == NULL !!!\n"); 188 } 189 if (node->nsDef != NULL) 190 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1); 191 if (node->properties != NULL) 192 xmlDebugDumpAttrList(output, node->properties, depth + 1); 193 if (node->type != XML_ENTITY_REF_NODE) { 194 if (node->content != NULL) { 195 fprintf(output, shift); 196 fprintf(output, "content="); 197#ifndef XML_USE_BUFFER_CONTENT 198 xmlDebugDumpString(output, node->content); 199#else 200 xmlDebugDumpString(output, xmlBufferContent(node->content)); 201#endif 202 fprintf(output, "\n"); 203 } 204 } else { 205 xmlEntityPtr ent; 206 ent = xmlGetDocEntity(node->doc, node->name); 207 if (ent != NULL) 208 xmlDebugDumpEntity(output, ent, depth + 1); 209 } 210} 211 212void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) { 213 xmlDebugDumpOneNode(output, node, depth); 214 if (node->childs != NULL) 215 xmlDebugDumpNodeList(output, node->childs, depth + 1); 216} 217 218void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) { 219 while (node != NULL) { 220 xmlDebugDumpNode(output, node, depth); 221 node = node->next; 222 } 223} 224 225 226void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) { 227 if (output == NULL) output = stdout; 228 if (doc == NULL) { 229 fprintf(output, "DOCUMENT == NULL !\n"); 230 return; 231 } 232 233 switch (doc->type) { 234 case XML_ELEMENT_NODE: 235 fprintf(output, "Error, ELEMENT found here "); 236 break; 237 case XML_ATTRIBUTE_NODE: 238 fprintf(output, "Error, ATTRIBUTE found here\n"); 239 break; 240 case XML_TEXT_NODE: 241 fprintf(output, "Error, TEXT\n"); 242 break; 243 case XML_CDATA_SECTION_NODE: 244 fprintf(output, "Error, CDATA_SECTION\n"); 245 break; 246 case XML_ENTITY_REF_NODE: 247 fprintf(output, "Error, ENTITY_REF\n"); 248 break; 249 case XML_ENTITY_NODE: 250 fprintf(output, "Error, ENTITY\n"); 251 break; 252 case XML_PI_NODE: 253 fprintf(output, "Error, PI\n"); 254 break; 255 case XML_COMMENT_NODE: 256 fprintf(output, "Error, COMMENT\n"); 257 break; 258 case XML_DOCUMENT_NODE: 259 fprintf(output, "DOCUMENT\n"); 260 break; 261 case XML_HTML_DOCUMENT_NODE: 262 fprintf(output, "HTML DOCUMENT\n"); 263 break; 264 case XML_DOCUMENT_TYPE_NODE: 265 fprintf(output, "Error, DOCUMENT_TYPE\n"); 266 break; 267 case XML_DOCUMENT_FRAG_NODE: 268 fprintf(output, "Error, DOCUMENT_FRAG\n"); 269 break; 270 case XML_NOTATION_NODE: 271 fprintf(output, "Error, NOTATION\n"); 272 break; 273 default: 274 fprintf(output, "NODE_%d\n", doc->type); 275 } 276 if (doc->name != NULL) { 277 fprintf(output, "name="); 278 xmlDebugDumpString(output, BAD_CAST doc->name); 279 fprintf(output, "\n"); 280 } 281 if (doc->version != NULL) { 282 fprintf(output, "version="); 283 xmlDebugDumpString(output, doc->version); 284 fprintf(output, "\n"); 285 } 286 if (doc->encoding != NULL) { 287 fprintf(output, "encoding="); 288 xmlDebugDumpString(output, doc->encoding); 289 fprintf(output, "\n"); 290 } 291 if (doc->standalone) 292 fprintf(output, "standalone=true\n"); 293 if (doc->oldNs != NULL) 294 xmlDebugDumpNamespaceList(output, doc->oldNs, 0); 295} 296 297void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) { 298 if (output == NULL) output = stdout; 299 if (doc == NULL) { 300 fprintf(output, "DOCUMENT == NULL !\n"); 301 return; 302 } 303 xmlDebugDumpDocumentHead(output, doc); 304 if (((doc->type == XML_DOCUMENT_NODE) || 305 (doc->type == XML_HTML_DOCUMENT_NODE)) && 306 (doc->root != NULL)) 307 xmlDebugDumpNodeList(output, doc->root, 1); 308} 309 310void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) { 311 int i; 312 xmlEntityPtr cur; 313 314 if (output == NULL) output = stdout; 315 if (doc == NULL) { 316 fprintf(output, "DOCUMENT == NULL !\n"); 317 return; 318 } 319 320 switch (doc->type) { 321 case XML_ELEMENT_NODE: 322 fprintf(output, "Error, ELEMENT found here "); 323 break; 324 case XML_ATTRIBUTE_NODE: 325 fprintf(output, "Error, ATTRIBUTE found here\n"); 326 break; 327 case XML_TEXT_NODE: 328 fprintf(output, "Error, TEXT\n"); 329 break; 330 case XML_CDATA_SECTION_NODE: 331 fprintf(output, "Error, CDATA_SECTION\n"); 332 break; 333 case XML_ENTITY_REF_NODE: 334 fprintf(output, "Error, ENTITY_REF\n"); 335 break; 336 case XML_ENTITY_NODE: 337 fprintf(output, "Error, ENTITY\n"); 338 break; 339 case XML_PI_NODE: 340 fprintf(output, "Error, PI\n"); 341 break; 342 case XML_COMMENT_NODE: 343 fprintf(output, "Error, COMMENT\n"); 344 break; 345 case XML_DOCUMENT_NODE: 346 fprintf(output, "DOCUMENT\n"); 347 break; 348 case XML_HTML_DOCUMENT_NODE: 349 fprintf(output, "HTML DOCUMENT\n"); 350 break; 351 case XML_DOCUMENT_TYPE_NODE: 352 fprintf(output, "Error, DOCUMENT_TYPE\n"); 353 break; 354 case XML_DOCUMENT_FRAG_NODE: 355 fprintf(output, "Error, DOCUMENT_FRAG\n"); 356 break; 357 case XML_NOTATION_NODE: 358 fprintf(output, "Error, NOTATION\n"); 359 break; 360 default: 361 fprintf(output, "NODE_%d\n", doc->type); 362 } 363 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) { 364 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 365 doc->intSubset->entities; 366 fprintf(output, "Entities in internal subset\n"); 367 for (i = 0;i < table->nb_entities;i++) { 368 cur = &table->table[i]; 369 fprintf(output, "%d : %s : ", i, cur->name); 370 switch (cur->type) { 371 case XML_INTERNAL_GENERAL_ENTITY: 372 fprintf(output, "INTERNAL GENERAL"); 373 break; 374 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 375 fprintf(output, "EXTERNAL PARSED"); 376 break; 377 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 378 fprintf(output, "EXTERNAL UNPARSED"); 379 break; 380 case XML_INTERNAL_PARAMETER_ENTITY: 381 fprintf(output, "INTERNAL PARAMETER"); 382 break; 383 case XML_EXTERNAL_PARAMETER_ENTITY: 384 fprintf(output, "EXTERNAL PARAMETER"); 385 break; 386 default: 387 fprintf(output, "UNKNOWN TYPE %d", 388 cur->type); 389 } 390 if (cur->ExternalID != NULL) 391 fprintf(output, "ID \"%s\"", cur->ExternalID); 392 if (cur->SystemID != NULL) 393 fprintf(output, "SYSTEM \"%s\"", cur->SystemID); 394 if (cur->orig != NULL) 395 fprintf(output, "\n orig \"%s\"", cur->orig); 396 if (cur->content != NULL) 397 fprintf(output, "\n content \"%s\"", cur->content); 398 fprintf(output, "\n"); 399 } 400 } else 401 fprintf(output, "No entities in internal subset\n"); 402 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) { 403 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 404 doc->extSubset->entities; 405 fprintf(output, "Entities in external subset\n"); 406 for (i = 0;i < table->nb_entities;i++) { 407 cur = &table->table[i]; 408 fprintf(output, "%d : %s : ", i, cur->name); 409 switch (cur->type) { 410 case XML_INTERNAL_GENERAL_ENTITY: 411 fprintf(output, "INTERNAL GENERAL"); 412 break; 413 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 414 fprintf(output, "EXTERNAL PARSED"); 415 break; 416 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 417 fprintf(output, "EXTERNAL UNPARSED"); 418 break; 419 case XML_INTERNAL_PARAMETER_ENTITY: 420 fprintf(output, "INTERNAL PARAMETER"); 421 break; 422 case XML_EXTERNAL_PARAMETER_ENTITY: 423 fprintf(output, "EXTERNAL PARAMETER"); 424 break; 425 default: 426 fprintf(output, "UNKNOWN TYPE %d", 427 cur->type); 428 } 429 if (cur->ExternalID != NULL) 430 fprintf(output, "ID \"%s\"", cur->ExternalID); 431 if (cur->SystemID != NULL) 432 fprintf(output, "SYSTEM \"%s\"", cur->SystemID); 433 if (cur->orig != NULL) 434 fprintf(output, "\n orig \"%s\"", cur->orig); 435 if (cur->content != NULL) 436 fprintf(output, "\n content \"%s\"", cur->content); 437 fprintf(output, "\n"); 438 } 439 } else 440 fprintf(output, "No entities in external subset\n"); 441} 442 443static int xmlLsCountNode(xmlNodePtr node) { 444 int ret = 0; 445 xmlNodePtr list = NULL; 446 447 switch (node->type) { 448 case XML_ELEMENT_NODE: 449 list = node->childs; 450 break; 451 case XML_DOCUMENT_NODE: 452 case XML_HTML_DOCUMENT_NODE: 453 list = ((xmlDocPtr) node)->root; 454 break; 455 case XML_ATTRIBUTE_NODE: 456 list = ((xmlAttrPtr) node)->val; 457 break; 458 case XML_TEXT_NODE: 459 case XML_CDATA_SECTION_NODE: 460 case XML_PI_NODE: 461 case XML_COMMENT_NODE: 462 if (node->content != NULL) { 463#ifndef XML_USE_BUFFER_CONTENT 464 ret = xmlStrlen(node->content); 465#else 466 ret = xmlBufferLength(node->content); 467#endif 468 } 469 break; 470 case XML_ENTITY_REF_NODE: 471 case XML_DOCUMENT_TYPE_NODE: 472 case XML_ENTITY_NODE: 473 case XML_DOCUMENT_FRAG_NODE: 474 case XML_NOTATION_NODE: 475 ret = 1; 476 break; 477 } 478 for (;list != NULL;ret++) 479 list = list->next; 480 return(ret); 481} 482 483void xmlLsOneNode(FILE *output, xmlNodePtr node) { 484 switch (node->type) { 485 case XML_ELEMENT_NODE: 486 fprintf(output, "-"); 487 break; 488 case XML_ATTRIBUTE_NODE: 489 fprintf(output, "a"); 490 break; 491 case XML_TEXT_NODE: 492 fprintf(output, "t"); 493 break; 494 case XML_CDATA_SECTION_NODE: 495 fprintf(output, "c"); 496 break; 497 case XML_ENTITY_REF_NODE: 498 fprintf(output, "e"); 499 break; 500 case XML_ENTITY_NODE: 501 fprintf(output, "E"); 502 break; 503 case XML_PI_NODE: 504 fprintf(output, "p"); 505 break; 506 case XML_COMMENT_NODE: 507 fprintf(output, "c"); 508 break; 509 case XML_DOCUMENT_NODE: 510 fprintf(output, "d"); 511 break; 512 case XML_HTML_DOCUMENT_NODE: 513 fprintf(output, "h"); 514 break; 515 case XML_DOCUMENT_TYPE_NODE: 516 fprintf(output, "T"); 517 break; 518 case XML_DOCUMENT_FRAG_NODE: 519 fprintf(output, "F"); 520 break; 521 case XML_NOTATION_NODE: 522 fprintf(output, "N"); 523 break; 524 default: 525 fprintf(output, "?"); 526 } 527 if (node->properties != NULL) 528 fprintf(output, "a"); 529 else 530 fprintf(output, "-"); 531 if (node->nsDef != NULL) 532 fprintf(output, "n"); 533 else 534 fprintf(output, "-"); 535 536 fprintf(output, " %8d ", xmlLsCountNode(node)); 537 538 switch (node->type) { 539 case XML_ELEMENT_NODE: 540 if (node->name != NULL) 541 fprintf(output, "%s", node->name); 542 break; 543 case XML_ATTRIBUTE_NODE: 544 if (node->name != NULL) 545 fprintf(output, "%s", node->name); 546 break; 547 case XML_TEXT_NODE: 548 if (node->content != NULL) { 549#ifndef XML_USE_BUFFER_CONTENT 550 xmlDebugDumpString(output, node->content); 551#else 552 xmlDebugDumpString(output, xmlBufferContent(node->content)); 553#endif 554 } 555 break; 556 case XML_CDATA_SECTION_NODE: 557 break; 558 case XML_ENTITY_REF_NODE: 559 if (node->name != NULL) 560 fprintf(output, "%s", node->name); 561 break; 562 case XML_ENTITY_NODE: 563 if (node->name != NULL) 564 fprintf(output, "%s", node->name); 565 break; 566 case XML_PI_NODE: 567 if (node->name != NULL) 568 fprintf(output, "%s", node->name); 569 break; 570 case XML_COMMENT_NODE: 571 break; 572 case XML_DOCUMENT_NODE: 573 break; 574 case XML_HTML_DOCUMENT_NODE: 575 break; 576 case XML_DOCUMENT_TYPE_NODE: 577 break; 578 case XML_DOCUMENT_FRAG_NODE: 579 break; 580 case XML_NOTATION_NODE: 581 break; 582 default: 583 if (node->name != NULL) 584 fprintf(output, "%s", node->name); 585 } 586 fprintf(output, "\n"); 587} 588 589/**************************************************************** 590 * * 591 * The XML shell related functions * 592 * * 593 ****************************************************************/ 594 595/* 596 * TODO: Improvement/cleanups for the XML shell 597 * - allow to shell out an editor on a subpart 598 * - cleanup function registrations (with help) and calling 599 * - provide registration routines 600 */ 601 602/** 603 * xmlShellList: 604 * @ctxt: the shell context 605 * @arg: unused 606 * @node: a node 607 * @node2: unused 608 * 609 * Implements the XML shell function "ls" 610 * Does an Unix like listing of the given node (like a directory) 611 * 612 * Returns 0 613 */ 614int 615xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, 616 xmlNodePtr node2) { 617 xmlNodePtr cur; 618 619 if ((node->type == XML_DOCUMENT_NODE) || 620 (node->type == XML_HTML_DOCUMENT_NODE)) { 621 cur = ((xmlDocPtr) node)->root; 622 } else if (node->childs != NULL) { 623 cur = node->childs; 624 } else { 625 xmlLsOneNode(stdout, node); 626 return(0); 627 } 628 while (cur != NULL) { 629 xmlLsOneNode(stdout, cur); 630 cur = cur->next; 631 } 632 return(0); 633} 634 635/** 636 * xmlShellDir: 637 * @ctxt: the shell context 638 * @arg: unused 639 * @node: a node 640 * @node2: unused 641 * 642 * Implements the XML shell function "dir" 643 * dumps informations about the node (namespace, attributes, content). 644 * 645 * Returns 0 646 */ 647int 648xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, 649 xmlNodePtr node2) { 650 if ((node->type == XML_DOCUMENT_NODE) || 651 (node->type == XML_HTML_DOCUMENT_NODE)) { 652 xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node); 653 } else if (node->type == XML_ATTRIBUTE_NODE) { 654 xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0); 655 } else { 656 xmlDebugDumpOneNode(stdout, node, 0); 657 } 658 return(0); 659} 660 661/** 662 * xmlShellCat: 663 * @ctxt: the shell context 664 * @arg: unused 665 * @node: a node 666 * @node2: unused 667 * 668 * Implements the XML shell function "cat" 669 * dumps the serialization node content (XML or HTML). 670 * 671 * Returns 0 672 */ 673int 674xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node, 675 xmlNodePtr node2) { 676 xmlElemDump(stdout, ctxt->doc, node); 677 printf("\n"); 678 return(0); 679} 680 681/** 682 * xmlShellLoad: 683 * @ctxt: the shell context 684 * @filename: the file name 685 * @node: unused 686 * @node2: unused 687 * 688 * Implements the XML shell function "load" 689 * loads a new document specified by the filename 690 * 691 * Returns 0 or -1 if loading failed 692 */ 693int 694xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 695 xmlNodePtr node2) { 696 xmlDocPtr doc; 697 int html = 0; 698 699 if (ctxt->doc != NULL) 700 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE); 701 702 if (html) { 703 doc = htmlParseFile(filename, NULL); 704 } else { 705 doc = xmlParseFile(filename); 706 } 707 if (doc != NULL) { 708 if (ctxt->loaded == 1) { 709 xmlFreeDoc(ctxt->doc); 710 } 711 ctxt->loaded = 1; 712 xmlXPathFreeContext(ctxt->pctxt); 713 xmlFree(ctxt->filename); 714 ctxt->doc = doc; 715 ctxt->node = (xmlNodePtr) doc; 716 ctxt->pctxt = xmlXPathNewContext(doc); 717 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename); 718 } else 719 return(-1); 720 return(0); 721} 722 723/** 724 * xmlShellWrite: 725 * @ctxt: the shell context 726 * @filename: the file name 727 * @node: a node in the tree 728 * @node2: unused 729 * 730 * Implements the XML shell function "write" 731 * Write the current node to the filename, it saves the serailization 732 * of the subtree under the @node specified 733 * 734 * Returns 0 or -1 in case of error 735 */ 736int 737xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 738 xmlNodePtr node2) { 739 if (node == NULL) 740 return(-1); 741 if ((filename == NULL) || (filename[0] == 0)) { 742 fprintf(stderr, "Write command requires a filename argument\n"); 743 return(-1); 744 } 745#ifdef W_OK 746 if (access((char *) filename, W_OK)) { 747 fprintf(stderr, "Cannot write to %s\n", filename); 748 return(-1); 749 } 750#endif 751 switch(node->type) { 752 case XML_DOCUMENT_NODE: 753 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { 754 fprintf(stderr, "Failed to write to %s\n", filename); 755 return(-1); 756 } 757 break; 758 case XML_HTML_DOCUMENT_NODE: 759 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 760 fprintf(stderr, "Failed to write to %s\n", filename); 761 return(-1); 762 } 763 break; 764 default: { 765 FILE *f; 766 767 f = fopen((char *) filename, "w"); 768 if (f == NULL) { 769 fprintf(stderr, "Failed to write to %s\n", filename); 770 return(-1); 771 } 772 xmlElemDump(f, ctxt->doc, node); 773 fclose(f); 774 } 775 } 776 return(0); 777} 778 779/** 780 * xmlShellSave: 781 * @ctxt: the shell context 782 * @filename: the file name (optionnal) 783 * @node: unused 784 * @node2: unused 785 * 786 * Implements the XML shell function "save" 787 * Write the current document to the filename, or it's original name 788 * 789 * Returns 0 or -1 in case of error 790 */ 791int 792xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, 793 xmlNodePtr node2) { 794 if (ctxt->doc == NULL) 795 return(-1); 796 if ((filename == NULL) || (filename[0] == 0)) 797 filename = ctxt->filename; 798#ifdef W_OK 799 if (access((char *) filename, W_OK)) { 800 fprintf(stderr, "Cannot save to %s\n", filename); 801 return(-1); 802 } 803#endif 804 switch(ctxt->doc->type) { 805 case XML_DOCUMENT_NODE: 806 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { 807 fprintf(stderr, "Failed to save to %s\n", filename); 808 } 809 break; 810 case XML_HTML_DOCUMENT_NODE: 811 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { 812 fprintf(stderr, "Failed to save to %s\n", filename); 813 } 814 break; 815 default: 816 fprintf(stderr, 817 "To save to subparts of a document use the 'write' command\n"); 818 return(-1); 819 820 } 821 return(0); 822} 823 824/** 825 * xmlShellValidate: 826 * @ctxt: the shell context 827 * @dtd: the DTD URI (optionnal) 828 * @node: unused 829 * @node2: unused 830 * 831 * Implements the XML shell function "validate" 832 * Validate the document, if a DTD path is provided, then the validation 833 * is done against the given DTD. 834 * 835 * Returns 0 or -1 in case of error 836 */ 837int 838xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node, 839 xmlNodePtr node2) { 840 xmlValidCtxt vctxt; 841 int res = -1; 842 843 vctxt.userData = stderr; 844 vctxt.error = (xmlValidityErrorFunc) fprintf; 845 vctxt.warning = (xmlValidityWarningFunc) fprintf; 846 847 if ((dtd == NULL) || (dtd[0] == 0)) { 848 res = xmlValidateDocument(&vctxt, ctxt->doc); 849 } else { 850 xmlDtdPtr subset; 851 852 subset = xmlParseDTD(NULL, (xmlChar *) dtd); 853 if (subset != NULL) { 854 res = xmlValidateDtd(&vctxt, ctxt->doc, subset); 855 856 xmlFreeDtd(subset); 857 } 858 } 859 return(res); 860} 861 862/** 863 * xmlShellDu: 864 * @ctxt: the shell context 865 * @arg: unused 866 * @tree: a node defining a subtree 867 * @node2: unused 868 * 869 * Implements the XML shell function "du" 870 * show the structure of the subtree under node @tree 871 * If @tree is null, the command works on the current node. 872 * 873 * Returns 0 or -1 in case of error 874 */ 875int 876xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree, 877 xmlNodePtr node2) { 878 xmlNodePtr node; 879 int indent = 0,i; 880 881 if (tree == NULL) return(-1); 882 node = tree; 883 while (node != NULL) { 884 if ((node->type == XML_DOCUMENT_NODE) || 885 (node->type == XML_HTML_DOCUMENT_NODE)) { 886 printf("/\n"); 887 } else if (node->type == XML_ELEMENT_NODE) { 888 for (i = 0;i < indent;i++) 889 printf(" "); 890 printf("%s\n", node->name); 891 } else { 892 } 893 894 /* 895 * Browse the full subtree, deep first 896 */ 897 898 if ((node->type == XML_DOCUMENT_NODE) || 899 (node->type == XML_HTML_DOCUMENT_NODE)) { 900 node = ((xmlDocPtr) node)->root; 901 } else if (node->childs != NULL) { 902 /* deep first */ 903 node = node->childs; 904 indent++; 905 } else if ((node != tree) && (node->next != NULL)) { 906 /* then siblings */ 907 node = node->next; 908 } else if (node != tree) { 909 /* go up to parents->next if needed */ 910 while (node != tree) { 911 if (node->parent != NULL) { 912 node = node->parent; 913 indent--; 914 } 915 if ((node != tree) && (node->next != NULL)) { 916 node = node->next; 917 break; 918 } 919 if (node->parent == NULL) { 920 node = NULL; 921 break; 922 } 923 if (node == tree) { 924 node = NULL; 925 break; 926 } 927 } 928 /* exit condition */ 929 if (node == tree) 930 node = NULL; 931 } else 932 node = NULL; 933 } 934 return(0); 935} 936 937/** 938 * xmlShellPwd: 939 * @ctxt: the shell context 940 * @buffer: the output buffer 941 * @tree: a node 942 * @node2: unused 943 * 944 * Implements the XML shell function "pwd" 945 * Show the full path from the root to the node, if needed building 946 * thumblers when similar elements exists at a given ancestor level. 947 * The output is compatible with XPath commands. 948 * 949 * Returns 0 or -1 in case of error 950 */ 951int 952xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node, 953 xmlNodePtr node2) { 954 xmlNodePtr cur, tmp, next; 955 char buf[500]; 956 char sep; 957 const char *name; 958 int occur = 0; 959 960 buffer[0] = 0; 961 if (node == NULL) return(-1); 962 cur = node; 963 do { 964 name = ""; 965 sep= '?'; 966 occur = 0; 967 if ((cur->type == XML_DOCUMENT_NODE) || 968 (cur->type == XML_HTML_DOCUMENT_NODE)) { 969 sep = '/'; 970 next = NULL; 971 } else if (cur->type == XML_ELEMENT_NODE) { 972 sep = '/'; 973 name = (const char *)cur->name; 974 next = cur->parent; 975 976 /* 977 * Thumbler index computation 978 */ 979 tmp = cur->prev; 980 while (tmp != NULL) { 981 if (!xmlStrcmp(cur->name, tmp->name)) 982 occur++; 983 tmp = tmp->prev; 984 } 985 if (occur == 0) { 986 tmp = cur->next; 987 while (tmp != NULL) { 988 if (!xmlStrcmp(cur->name, tmp->name)) 989 occur++; 990 tmp = tmp->next; 991 } 992 if (occur != 0) occur = 1; 993 } else 994 occur++; 995 } else if (cur->type == XML_ATTRIBUTE_NODE) { 996 sep = '@'; 997 name = (const char *) (((xmlAttrPtr) cur)->name); 998 next = ((xmlAttrPtr) cur)->node; 999 } else { 1000 next = cur->parent; 1001 } 1002 if (occur == 0) 1003 sprintf(buf, "%c%s%s", sep, name, buffer); 1004 else 1005 sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer); 1006 strcpy(buffer, buf); 1007 cur = next; 1008 } while (cur != NULL); 1009 return(0); 1010} 1011 1012/** 1013 * xmlShell 1014 * @doc: the initial document 1015 * @filename: the output buffer 1016 * @input: the line reading function 1017 * @output: the output FILE* 1018 * 1019 * Implements the XML shell 1020 * This allow to load, validate, view, modify and save a document 1021 * using a environment similar to a UNIX commandline. 1022 */ 1023void 1024xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, 1025 FILE *output) { 1026 char prompt[500] = "/ > "; 1027 char *cmdline = NULL; 1028 int nbargs; 1029 char command[100]; 1030 char arg[400]; 1031 xmlShellCtxtPtr ctxt; 1032 xmlXPathObjectPtr list; 1033 1034 if (doc == NULL) 1035 return; 1036 if (filename == NULL) 1037 return; 1038 if (input == NULL) 1039 return; 1040 if (output == NULL) 1041 return; 1042 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt)); 1043 if (ctxt == NULL) 1044 return; 1045 ctxt->loaded = 0; 1046 ctxt->doc = doc; 1047 ctxt->input = input; 1048 ctxt->output = output; 1049 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename); 1050 ctxt->node = (xmlNodePtr) ctxt->doc; 1051 1052 ctxt->pctxt = xmlXPathNewContext(ctxt->doc); 1053 if (ctxt->pctxt == NULL) { 1054 xmlFree(ctxt); 1055 return; 1056 } 1057 while (1) { 1058 if (ctxt->node == (xmlNodePtr) ctxt->doc) 1059 sprintf(prompt, "%s > ", "/"); 1060 else if (ctxt->node->name) 1061 sprintf(prompt, "%s > ", ctxt->node->name); 1062 else 1063 sprintf(prompt, "? > "); 1064 1065 cmdline = ctxt->input(prompt); 1066 if (cmdline == NULL) break; 1067 1068 command[0] = 0; 1069 arg[0] = 0; 1070 nbargs = sscanf(cmdline, "%s %s", command, arg); 1071 1072 if (command[0] == 0) continue; 1073 if (!strcmp(command, "exit")) 1074 break; 1075 if (!strcmp(command, "quit")) 1076 break; 1077 if (!strcmp(command, "bye")) 1078 break; 1079 if (!strcmp(command, "validate")) { 1080 xmlShellValidate(ctxt, arg, NULL, NULL); 1081 } else if (!strcmp(command, "load")) { 1082 xmlShellLoad(ctxt, arg, NULL, NULL); 1083 } else if (!strcmp(command, "save")) { 1084 xmlShellSave(ctxt, arg, NULL, NULL); 1085 } else if (!strcmp(command, "write")) { 1086 xmlShellWrite(ctxt, arg, NULL, NULL); 1087 } else if (!strcmp(command, "free")) { 1088 if (arg[0] == 0) { 1089 xmlMemShow(stdout, 0); 1090 } else { 1091 int len = 0; 1092 sscanf(arg, "%d", &len); 1093 xmlMemShow(stdout, len); 1094 } 1095 } else if (!strcmp(command, "pwd")) { 1096 char dir[500]; 1097 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL)) 1098 printf("%s\n", dir); 1099 } else if (!strcmp(command, "du")) { 1100 xmlShellDu(ctxt, NULL, ctxt->node, NULL); 1101 } else if ((!strcmp(command, "ls")) || 1102 (!strcmp(command, "dir"))) { 1103 int dir = (!strcmp(command, "dir")); 1104 if (arg[0] == 0) { 1105 if (dir) 1106 xmlShellDir(ctxt, NULL, ctxt->node, NULL); 1107 else 1108 xmlShellList(ctxt, NULL, ctxt->node, NULL); 1109 } else { 1110 ctxt->pctxt->node = ctxt->node; 1111 if (ctxt->pctxt->nodelist != NULL) 1112 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist); 1113 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node); 1114 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 1115 if (list != NULL) { 1116 switch (list->type) { 1117 case XPATH_UNDEFINED: 1118 fprintf(stderr, "%s: no such node\n", arg); 1119 break; 1120 case XPATH_NODESET: { 1121 int i; 1122 1123 for (i = 0;i < list->nodesetval->nodeNr;i++) { 1124 if (dir) 1125 xmlShellDir(ctxt, NULL, 1126 list->nodesetval->nodeTab[i], NULL); 1127 else 1128 xmlShellList(ctxt, NULL, 1129 list->nodesetval->nodeTab[i], NULL); 1130 } 1131 break; 1132 } 1133 case XPATH_BOOLEAN: 1134 fprintf(stderr, "%s is a Boolean\n", arg); 1135 break; 1136 case XPATH_NUMBER: 1137 fprintf(stderr, "%s is a number\n", arg); 1138 break; 1139 case XPATH_STRING: 1140 fprintf(stderr, "%s is a string\n", arg); 1141 break; 1142 } 1143 xmlXPathFreeNodeSetList(list); 1144 } else { 1145 fprintf(stderr, "%s: no such node\n", arg); 1146 } 1147 if (ctxt->pctxt->nodelist != NULL) 1148 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist); 1149 ctxt->pctxt->nodelist = NULL; 1150 } 1151 } else if (!strcmp(command, "cd")) { 1152 if (arg[0] == 0) { 1153 ctxt->node = (xmlNodePtr) ctxt->doc; 1154 } else { 1155 ctxt->pctxt->node = ctxt->node; 1156 if (ctxt->pctxt->nodelist != NULL) 1157 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist); 1158 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node); 1159 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 1160 if (list != NULL) { 1161 switch (list->type) { 1162 case XPATH_UNDEFINED: 1163 fprintf(stderr, "%s: no such node\n", arg); 1164 break; 1165 case XPATH_NODESET: 1166 if (list->nodesetval->nodeNr == 1) { 1167 ctxt->node = list->nodesetval->nodeTab[0]; 1168 } else 1169 fprintf(stderr, "%s is a %d Node Set\n", 1170 arg, list->nodesetval->nodeNr); 1171 break; 1172 case XPATH_BOOLEAN: 1173 fprintf(stderr, "%s is a Boolean\n", arg); 1174 break; 1175 case XPATH_NUMBER: 1176 fprintf(stderr, "%s is a number\n", arg); 1177 break; 1178 case XPATH_STRING: 1179 fprintf(stderr, "%s is a string\n", arg); 1180 break; 1181 } 1182 xmlXPathFreeNodeSetList(list); 1183 } else { 1184 fprintf(stderr, "%s: no such node\n", arg); 1185 } 1186 if (ctxt->pctxt->nodelist != NULL) 1187 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist); 1188 ctxt->pctxt->nodelist = NULL; 1189 } 1190 } else if (!strcmp(command, "cat")) { 1191 if (arg[0] == 0) { 1192 xmlShellCat(ctxt, NULL, ctxt->node, NULL); 1193 } else { 1194 ctxt->pctxt->node = ctxt->node; 1195 if (ctxt->pctxt->nodelist != NULL) 1196 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist); 1197 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node); 1198 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); 1199 if (list != NULL) { 1200 switch (list->type) { 1201 case XPATH_UNDEFINED: 1202 fprintf(stderr, "%s: no such node\n", arg); 1203 break; 1204 case XPATH_NODESET: { 1205 int i; 1206 1207 for (i = 0;i < list->nodesetval->nodeNr;i++) { 1208 if (i > 0) printf(" -------\n"); 1209 xmlShellCat(ctxt, NULL, 1210 list->nodesetval->nodeTab[i], NULL); 1211 } 1212 break; 1213 } 1214 case XPATH_BOOLEAN: 1215 fprintf(stderr, "%s is a Boolean\n", arg); 1216 break; 1217 case XPATH_NUMBER: 1218 fprintf(stderr, "%s is a number\n", arg); 1219 break; 1220 case XPATH_STRING: 1221 fprintf(stderr, "%s is a string\n", arg); 1222 break; 1223 } 1224 xmlXPathFreeNodeSetList(list); 1225 } else { 1226 fprintf(stderr, "%s: no such node\n", arg); 1227 } 1228 if (ctxt->pctxt->nodelist != NULL) 1229 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist); 1230 ctxt->pctxt->nodelist = NULL; 1231 } 1232 } else { 1233 fprintf(stderr, "Unknown command %s\n", command); 1234 } 1235 free(cmdline); /* not xmlFree here ! */ 1236 } 1237 xmlXPathFreeContext(ctxt->pctxt); 1238 if (ctxt->loaded) { 1239 xmlFreeDoc(ctxt->doc); 1240 } 1241 xmlFree(ctxt); 1242 if (cmdline != NULL) 1243 free(cmdline); /* not xmlFree here ! */ 1244} 1245 1246