blob: 65d703d68a64ec6af544b1e92196637db4c428f7 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
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_NAMESPACE_DECL) {
381 fprintf(output, "invalid namespace node %d\n", ns->type);
382 return;
383 }
384 if (ns->href == NULL) {
385 if (ns->prefix != NULL)
386 fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix);
387 else
388 fprintf(output, "incomplete default namespace href=NULL\n");
389 } else {
390 if (ns->prefix != NULL)
391 fprintf(output, "namespace %s href=", ns->prefix);
392 else
393 fprintf(output, "default namespace href=");
394
395 xmlDebugDumpString(output, ns->href);
396 fprintf(output, "\n");
397 }
398}
399
400void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
401 while (ns != NULL) {
402 xmlDebugDumpNamespace(output, ns, depth);
403 ns = ns->next;
404 }
405}
406
407void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, 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 switch (ent->etype) {
417 case XML_INTERNAL_GENERAL_ENTITY:
418 fprintf(output, "INTERNAL_GENERAL_ENTITY ");
419 break;
420 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
421 fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
422 break;
423 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
424 fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
425 break;
426 case XML_INTERNAL_PARAMETER_ENTITY:
427 fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
428 break;
429 case XML_EXTERNAL_PARAMETER_ENTITY:
430 fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
431 break;
432 default:
433 fprintf(output, "ENTITY_%d ! ", ent->etype);
434 }
435 fprintf(output, "%s\n", ent->name);
436 if (ent->ExternalID) {
437 fprintf(output, shift);
438 fprintf(output, "ExternalID=%s\n", ent->ExternalID);
439 }
440 if (ent->SystemID) {
441 fprintf(output, shift);
442 fprintf(output, "SystemID=%s\n", ent->SystemID);
443 }
444 if (ent->URI) {
445 fprintf(output, shift);
446 fprintf(output, "URI=%s\n", ent->URI);
447 }
448 if (ent->content) {
449 fprintf(output, shift);
450 fprintf(output, "content=");
451 xmlDebugDumpString(output, ent->content);
452 fprintf(output, "\n");
453 }
454}
455
456void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
457 int i;
458 char shift[100];
459
460 for (i = 0;((i < depth) && (i < 25));i++)
461 shift[2 * i] = shift[2 * i + 1] = ' ';
462 shift[2 * i] = shift[2 * i + 1] = 0;
463
464 fprintf(output, shift);
465
466 fprintf(output, "ATTRIBUTE ");
467 xmlDebugDumpString(output, attr->name);
468 fprintf(output, "\n");
469 if (attr->children != NULL)
470 xmlDebugDumpNodeList(output, attr->children, depth + 1);
471
472 /*
473 * Do a bit of checking
474 */
475 if (attr->parent == NULL)
476 fprintf(output, "PBM: Attr has no parent\n");
477 if (attr->doc == NULL)
478 fprintf(output, "PBM: Attr has no doc\n");
479 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
480 fprintf(output, "PBM: Attr doc differs from parent's one\n");
481 if (attr->prev == NULL) {
482 if ((attr->parent != NULL) && (attr->parent->properties != attr))
483 fprintf(output, "PBM: Attr has no prev and not first of list\n");
484 } else {
485 if (attr->prev->next != attr)
486 fprintf(output, "PBM: Attr prev->next : back link wrong\n");
487 }
488 if (attr->next != NULL) {
489 if (attr->next->prev != attr)
490 fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
491 }
492}
493
494void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) {
495 while (attr != NULL) {
496 xmlDebugDumpAttr(output, attr, depth);
497 attr = attr->next;
498 }
499}
500
501void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) {
502 int i;
503 char shift[100];
504
505 for (i = 0;((i < depth) && (i < 25));i++)
506 shift[2 * i] = shift[2 * i + 1] = ' ';
507 shift[2 * i] = shift[2 * i + 1] = 0;
508
509 switch (node->type) {
510 case XML_ELEMENT_NODE:
511 fprintf(output, shift);
512 fprintf(output, "ELEMENT ");
513 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
514 xmlDebugDumpString(output, node->ns->prefix);
515 fprintf(output, ":");
516 }
517 xmlDebugDumpString(output, node->name);
518 fprintf(output, "\n");
519 break;
520 case XML_ATTRIBUTE_NODE:
521 fprintf(output, shift);
522 fprintf(output, "Error, ATTRIBUTE found here\n");
523 break;
524 case XML_TEXT_NODE:
525 fprintf(output, shift);
526 fprintf(output, "TEXT\n");
527 break;
528 case XML_CDATA_SECTION_NODE:
529 fprintf(output, shift);
530 fprintf(output, "CDATA_SECTION\n");
531 break;
532 case XML_ENTITY_REF_NODE:
533 fprintf(output, shift);
534 fprintf(output, "ENTITY_REF(%s)\n", node->name);
535 break;
536 case XML_ENTITY_NODE:
537 fprintf(output, shift);
538 fprintf(output, "ENTITY\n");
539 break;
540 case XML_PI_NODE:
541 fprintf(output, shift);
542 fprintf(output, "PI %s\n", node->name);
543 break;
544 case XML_COMMENT_NODE:
545 fprintf(output, shift);
546 fprintf(output, "COMMENT\n");
547 break;
548 case XML_DOCUMENT_NODE:
549 case XML_HTML_DOCUMENT_NODE:
550 fprintf(output, shift);
551 fprintf(output, "Error, DOCUMENT found here\n");
552 break;
553 case XML_DOCUMENT_TYPE_NODE:
554 fprintf(output, shift);
555 fprintf(output, "DOCUMENT_TYPE\n");
556 break;
557 case XML_DOCUMENT_FRAG_NODE:
558 fprintf(output, shift);
559 fprintf(output, "DOCUMENT_FRAG\n");
560 break;
561 case XML_NOTATION_NODE:
562 fprintf(output, shift);
563 fprintf(output, "NOTATION\n");
564 break;
565 case XML_DTD_NODE:
566 xmlDebugDumpDtd(output, (xmlDtdPtr) node, depth);
567 return;
568 case XML_ELEMENT_DECL:
569 xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
570 return;
571 case XML_ATTRIBUTE_DECL:
572 xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
573 return;
574 case XML_ENTITY_DECL:
575 xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
576 return;
577 case XML_NAMESPACE_DECL:
578 xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
579 return;
580 case XML_XINCLUDE_START:
581 fprintf(output, shift);
582 fprintf(output, "INCLUDE START\n");
583 return;
584 case XML_XINCLUDE_END:
585 fprintf(output, shift);
586 fprintf(output, "INCLUDE END\n");
587 return;
588 default:
589 fprintf(output, shift);
590 fprintf(output, "NODE_%d !!!\n", node->type);
591 return;
592 }
593 if (node->doc == NULL) {
594 fprintf(output, shift);
595 fprintf(output, "doc == NULL !!!\n");
596 }
597 if (node->nsDef != NULL)
598 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
599 if (node->properties != NULL)
600 xmlDebugDumpAttrList(output, node->properties, depth + 1);
601 if (node->type != XML_ENTITY_REF_NODE) {
602 if (node->content != NULL) {
603 shift[2 * i] = shift[2 * i + 1] = ' ' ;
604 shift[2 * i + 2] = shift[2 * i + 3] = 0 ;
605 fprintf(output, shift);
606 fprintf(output, "content=");
607#ifndef XML_USE_BUFFER_CONTENT
608 xmlDebugDumpString(output, node->content);
609#else
610 xmlDebugDumpString(output, xmlBufferContent(node->content));
611#endif
612 fprintf(output, "\n");
613 }
614 } else {
615 xmlEntityPtr ent;
616 ent = xmlGetDocEntity(node->doc, node->name);
617 if (ent != NULL)
618 xmlDebugDumpEntity(output, ent, depth + 1);
619 }
620 /*
621 * Do a bit of checking
622 */
623 if (node->parent == NULL)
624 fprintf(output, "PBM: Node has no parent\n");
625 if (node->doc == NULL)
626 fprintf(output, "PBM: Node has no doc\n");
627 if ((node->parent != NULL) && (node->doc != node->parent->doc))
628 fprintf(output, "PBM: Node doc differs from parent's one\n");
629 if (node->prev == NULL) {
630 if ((node->parent != NULL) && (node->parent->children != node))
631 fprintf(output, "PBM: Node has no prev and not first of list\n");
632 } else {
633 if (node->prev->next != node)
634 fprintf(output, "PBM: Node prev->next : back link wrong\n");
635 }
636 if (node->next == NULL) {
637 if ((node->parent != NULL) && (node->parent->last != node))
638 fprintf(output, "PBM: Node has no next and not last of list\n");
639 } else {
640 if (node->next->prev != node)
641 fprintf(output, "PBM: Node next->prev : forward link wrong\n");
642 }
643}
644
645void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
646 xmlDebugDumpOneNode(output, node, depth);
647 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
648 xmlDebugDumpNodeList(output, node->children, depth + 1);
649}
650
651void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
652 while (node != NULL) {
653 xmlDebugDumpNode(output, node, depth);
654 node = node->next;
655 }
656}
657
658
659void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
660 if (output == NULL) output = stdout;
661 if (doc == NULL) {
662 fprintf(output, "DOCUMENT == NULL !\n");
663 return;
664 }
665
666 switch (doc->type) {
667 case XML_ELEMENT_NODE:
668 fprintf(output, "Error, ELEMENT found here ");
669 break;
670 case XML_ATTRIBUTE_NODE:
671 fprintf(output, "Error, ATTRIBUTE found here\n");
672 break;
673 case XML_TEXT_NODE:
674 fprintf(output, "Error, TEXT\n");
675 break;
676 case XML_CDATA_SECTION_NODE:
677 fprintf(output, "Error, CDATA_SECTION\n");
678 break;
679 case XML_ENTITY_REF_NODE:
680 fprintf(output, "Error, ENTITY_REF\n");
681 break;
682 case XML_ENTITY_NODE:
683 fprintf(output, "Error, ENTITY\n");
684 break;
685 case XML_PI_NODE:
686 fprintf(output, "Error, PI\n");
687 break;
688 case XML_COMMENT_NODE:
689 fprintf(output, "Error, COMMENT\n");
690 break;
691 case XML_DOCUMENT_NODE:
692 fprintf(output, "DOCUMENT\n");
693 break;
694 case XML_HTML_DOCUMENT_NODE:
695 fprintf(output, "HTML DOCUMENT\n");
696 break;
697 case XML_DOCUMENT_TYPE_NODE:
698 fprintf(output, "Error, DOCUMENT_TYPE\n");
699 break;
700 case XML_DOCUMENT_FRAG_NODE:
701 fprintf(output, "Error, DOCUMENT_FRAG\n");
702 break;
703 case XML_NOTATION_NODE:
704 fprintf(output, "Error, NOTATION\n");
705 break;
706 default:
707 fprintf(output, "NODE_%d\n", doc->type);
708 }
709 if (doc->name != NULL) {
710 fprintf(output, "name=");
711 xmlDebugDumpString(output, BAD_CAST doc->name);
712 fprintf(output, "\n");
713 }
714 if (doc->version != NULL) {
715 fprintf(output, "version=");
716 xmlDebugDumpString(output, doc->version);
717 fprintf(output, "\n");
718 }
719 if (doc->encoding != NULL) {
720 fprintf(output, "encoding=");
721 xmlDebugDumpString(output, doc->encoding);
722 fprintf(output, "\n");
723 }
724 if (doc->URL != NULL) {
725 fprintf(output, "URL=");
726 xmlDebugDumpString(output, doc->URL);
727 fprintf(output, "\n");
728 }
729 if (doc->standalone)
730 fprintf(output, "standalone=true\n");
731 if (doc->oldNs != NULL)
732 xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
733}
734
735void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
736 if (output == NULL) output = stdout;
737 if (doc == NULL) {
738 fprintf(output, "DOCUMENT == NULL !\n");
739 return;
740 }
741 xmlDebugDumpDocumentHead(output, doc);
742 if (((doc->type == XML_DOCUMENT_NODE) ||
743 (doc->type == XML_HTML_DOCUMENT_NODE)) &&
744 (doc->children != NULL))
745 xmlDebugDumpNodeList(output, doc->children, 1);
746}
747
748void xmlDebugDumpDTD(FILE *output, xmlDtdPtr dtd) {
749 if (dtd == NULL)
750 return;
751 if (dtd->type != XML_DTD_NODE) {
752 fprintf(output, "PBM: not a DTD\n");
753 return;
754 }
755 if (dtd->name != NULL)
756 fprintf(output, "DTD(%s)", dtd->name);
757 else
758 fprintf(output, "DTD");
759 if (dtd->ExternalID != NULL)
760 fprintf(output, ", PUBLIC %s", dtd->ExternalID);
761 if (dtd->SystemID != NULL)
762 fprintf(output, ", SYSTEM %s", dtd->SystemID);
763 fprintf(output, "\n");
764 /*
765 * Do a bit of checking
766 */
767 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
768 fprintf(output, "PBM: Dtd doc differs from parent's one\n");
769 if (dtd->prev == NULL) {
770 if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
771 fprintf(output, "PBM: Dtd has no prev and not first of list\n");
772 } else {
773 if (dtd->prev->next != (xmlNodePtr) dtd)
774 fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
775 }
776 if (dtd->next == NULL) {
777 if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
778 fprintf(output, "PBM: Dtd has no next and not last of list\n");
779 } else {
780 if (dtd->next->prev != (xmlNodePtr) dtd)
781 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
782 }
783 if (dtd->children == NULL)
784 fprintf(output, " DTD is empty\n");
785 else
786 xmlDebugDumpNodeList(output, dtd->children, 1);
787}
788
789void xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output,
790 const xmlChar *name) {
791 fprintf(output, "%s : ", cur->name);
792 switch (cur->etype) {
793 case XML_INTERNAL_GENERAL_ENTITY:
794 fprintf(output, "INTERNAL GENERAL, ");
795 break;
796 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
797 fprintf(output, "EXTERNAL PARSED, ");
798 break;
799 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
800 fprintf(output, "EXTERNAL UNPARSED, ");
801 break;
802 case XML_INTERNAL_PARAMETER_ENTITY:
803 fprintf(output, "INTERNAL PARAMETER, ");
804 break;
805 case XML_EXTERNAL_PARAMETER_ENTITY:
806 fprintf(output, "EXTERNAL PARAMETER, ");
807 break;
808 default:
809 fprintf(output, "UNKNOWN TYPE %d",
810 cur->etype);
811 }
812 if (cur->ExternalID != NULL)
813 fprintf(output, "ID \"%s\"", cur->ExternalID);
814 if (cur->SystemID != NULL)
815 fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
816 if (cur->orig != NULL)
817 fprintf(output, "\n orig \"%s\"", cur->orig);
818 if (cur->content != NULL)
819 fprintf(output, "\n content \"%s\"", cur->content);
820 fprintf(output, "\n");
821}
822
823void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
824 if (output == NULL) output = stdout;
825 if (doc == NULL) {
826 fprintf(output, "DOCUMENT == NULL !\n");
827 return;
828 }
829
830 switch (doc->type) {
831 case XML_ELEMENT_NODE:
832 fprintf(output, "Error, ELEMENT found here ");
833 break;
834 case XML_ATTRIBUTE_NODE:
835 fprintf(output, "Error, ATTRIBUTE found here\n");
836 break;
837 case XML_TEXT_NODE:
838 fprintf(output, "Error, TEXT\n");
839 break;
840 case XML_CDATA_SECTION_NODE:
841 fprintf(output, "Error, CDATA_SECTION\n");
842 break;
843 case XML_ENTITY_REF_NODE:
844 fprintf(output, "Error, ENTITY_REF\n");
845 break;
846 case XML_ENTITY_NODE:
847 fprintf(output, "Error, ENTITY\n");
848 break;
849 case XML_PI_NODE:
850 fprintf(output, "Error, PI\n");
851 break;
852 case XML_COMMENT_NODE:
853 fprintf(output, "Error, COMMENT\n");
854 break;
855 case XML_DOCUMENT_NODE:
856 fprintf(output, "DOCUMENT\n");
857 break;
858 case XML_HTML_DOCUMENT_NODE:
859 fprintf(output, "HTML DOCUMENT\n");
860 break;
861 case XML_DOCUMENT_TYPE_NODE:
862 fprintf(output, "Error, DOCUMENT_TYPE\n");
863 break;
864 case XML_DOCUMENT_FRAG_NODE:
865 fprintf(output, "Error, DOCUMENT_FRAG\n");
866 break;
867 case XML_NOTATION_NODE:
868 fprintf(output, "Error, NOTATION\n");
869 break;
870 default:
871 fprintf(output, "NODE_%d\n", doc->type);
872 }
873 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
874 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
875 doc->intSubset->entities;
876 fprintf(output, "Entities in internal subset\n");
877 xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output);
878 } else
879 fprintf(output, "No entities in internal subset\n");
880 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
881 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
882 doc->extSubset->entities;
883 fprintf(output, "Entities in external subset\n");
884 xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output);
885 } else
886 fprintf(output, "No entities in external subset\n");
887}
888
889static int xmlLsCountNode(xmlNodePtr node) {
890 int ret = 0;
891 xmlNodePtr list = NULL;
892
893 switch (node->type) {
894 case XML_ELEMENT_NODE:
895 list = node->children;
896 break;
897 case XML_DOCUMENT_NODE:
898 case XML_HTML_DOCUMENT_NODE:
899#ifdef LIBXML_SGML_ENABLED
900 case XML_SGML_DOCUMENT_NODE:
901#endif
902 list = ((xmlDocPtr) node)->children;
903 break;
904 case XML_ATTRIBUTE_NODE:
905 list = ((xmlAttrPtr) node)->children;
906 break;
907 case XML_TEXT_NODE:
908 case XML_CDATA_SECTION_NODE:
909 case XML_PI_NODE:
910 case XML_COMMENT_NODE:
911 if (node->content != NULL) {
912#ifndef XML_USE_BUFFER_CONTENT
913 ret = xmlStrlen(node->content);
914#else
915 ret = xmlBufferLength(node->content);
916#endif
917 }
918 break;
919 case XML_ENTITY_REF_NODE:
920 case XML_DOCUMENT_TYPE_NODE:
921 case XML_ENTITY_NODE:
922 case XML_DOCUMENT_FRAG_NODE:
923 case XML_NOTATION_NODE:
924 case XML_DTD_NODE:
925 case XML_ELEMENT_DECL:
926 case XML_ATTRIBUTE_DECL:
927 case XML_ENTITY_DECL:
928 case XML_NAMESPACE_DECL:
929 case XML_XINCLUDE_START:
930 case XML_XINCLUDE_END:
931 ret = 1;
932 break;
933 }
934 for (;list != NULL;ret++)
935 list = list->next;
936 return(ret);
937}
938
939void xmlLsOneNode(FILE *output, xmlNodePtr node) {
940 switch (node->type) {
941 case XML_ELEMENT_NODE:
942 fprintf(output, "-");
943 break;
944 case XML_ATTRIBUTE_NODE:
945 fprintf(output, "a");
946 break;
947 case XML_TEXT_NODE:
948 fprintf(output, "t");
949 break;
950 case XML_CDATA_SECTION_NODE:
951 fprintf(output, "c");
952 break;
953 case XML_ENTITY_REF_NODE:
954 fprintf(output, "e");
955 break;
956 case XML_ENTITY_NODE:
957 fprintf(output, "E");
958 break;
959 case XML_PI_NODE:
960 fprintf(output, "p");
961 break;
962 case XML_COMMENT_NODE:
963 fprintf(output, "c");
964 break;
965 case XML_DOCUMENT_NODE:
966 fprintf(output, "d");
967 break;
968 case XML_HTML_DOCUMENT_NODE:
969 fprintf(output, "h");
970 break;
971 case XML_DOCUMENT_TYPE_NODE:
972 fprintf(output, "T");
973 break;
974 case XML_DOCUMENT_FRAG_NODE:
975 fprintf(output, "F");
976 break;
977 case XML_NOTATION_NODE:
978 fprintf(output, "N");
979 break;
980 default:
981 fprintf(output, "?");
982 }
983 if (node->properties != NULL)
984 fprintf(output, "a");
985 else
986 fprintf(output, "-");
987 if (node->nsDef != NULL)
988 fprintf(output, "n");
989 else
990 fprintf(output, "-");
991
992 fprintf(output, " %8d ", xmlLsCountNode(node));
993
994 switch (node->type) {
995 case XML_ELEMENT_NODE:
996 if (node->name != NULL)
997 fprintf(output, "%s", node->name);
998 break;
999 case XML_ATTRIBUTE_NODE:
1000 if (node->name != NULL)
1001 fprintf(output, "%s", node->name);
1002 break;
1003 case XML_TEXT_NODE:
1004 if (node->content != NULL) {
1005#ifndef XML_USE_BUFFER_CONTENT
1006 xmlDebugDumpString(output, node->content);
1007#else
1008 xmlDebugDumpString(output, xmlBufferContent(node->content));
1009#endif
1010 }
1011 break;
1012 case XML_CDATA_SECTION_NODE:
1013 break;
1014 case XML_ENTITY_REF_NODE:
1015 if (node->name != NULL)
1016 fprintf(output, "%s", node->name);
1017 break;
1018 case XML_ENTITY_NODE:
1019 if (node->name != NULL)
1020 fprintf(output, "%s", node->name);
1021 break;
1022 case XML_PI_NODE:
1023 if (node->name != NULL)
1024 fprintf(output, "%s", node->name);
1025 break;
1026 case XML_COMMENT_NODE:
1027 break;
1028 case XML_DOCUMENT_NODE:
1029 break;
1030 case XML_HTML_DOCUMENT_NODE:
1031 break;
1032 case XML_DOCUMENT_TYPE_NODE:
1033 break;
1034 case XML_DOCUMENT_FRAG_NODE:
1035 break;
1036 case XML_NOTATION_NODE:
1037 break;
1038 default:
1039 if (node->name != NULL)
1040 fprintf(output, "%s", node->name);
1041 }
1042 fprintf(output, "\n");
1043}
1044
1045/****************************************************************
1046 * *
1047 * The XML shell related functions *
1048 * *
1049 ****************************************************************/
1050
1051/*
1052 * TODO: Improvement/cleanups for the XML shell
1053 * - allow to shell out an editor on a subpart
1054 * - cleanup function registrations (with help) and calling
1055 * - provide registration routines
1056 */
1057
1058/**
1059 * xmlShellList:
1060 * @ctxt: the shell context
1061 * @arg: unused
1062 * @node: a node
1063 * @node2: unused
1064 *
1065 * Implements the XML shell function "ls"
1066 * Does an Unix like listing of the given node (like a directory)
1067 *
1068 * Returns 0
1069 */
1070int
1071xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1072 xmlNodePtr node2) {
1073 xmlNodePtr cur;
1074
1075 if ((node->type == XML_DOCUMENT_NODE) ||
1076 (node->type == XML_HTML_DOCUMENT_NODE)) {
1077 cur = ((xmlDocPtr) node)->children;
1078 } else if (node->children != NULL) {
1079 cur = node->children;
1080 } else {
1081 xmlLsOneNode(stdout, node);
1082 return(0);
1083 }
1084 while (cur != NULL) {
1085 xmlLsOneNode(stdout, cur);
1086 cur = cur->next;
1087 }
1088 return(0);
1089}
1090
1091/**
1092 * xmlShellDir:
1093 * @ctxt: the shell context
1094 * @arg: unused
1095 * @node: a node
1096 * @node2: unused
1097 *
1098 * Implements the XML shell function "dir"
1099 * dumps informations about the node (namespace, attributes, content).
1100 *
1101 * Returns 0
1102 */
1103int
1104xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1105 xmlNodePtr node2) {
1106 if ((node->type == XML_DOCUMENT_NODE) ||
1107 (node->type == XML_HTML_DOCUMENT_NODE)) {
1108 xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
1109 } else if (node->type == XML_ATTRIBUTE_NODE) {
1110 xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
1111 } else {
1112 xmlDebugDumpOneNode(stdout, node, 0);
1113 }
1114 return(0);
1115}
1116
1117/**
1118 * xmlShellCat:
1119 * @ctxt: the shell context
1120 * @arg: unused
1121 * @node: a node
1122 * @node2: unused
1123 *
1124 * Implements the XML shell function "cat"
1125 * dumps the serialization node content (XML or HTML).
1126 *
1127 * Returns 0
1128 */
1129int
1130xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1131 xmlNodePtr node2) {
1132 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1133#ifdef LIBXML_HTML_ENABLED
1134 if (node->type == XML_HTML_DOCUMENT_NODE)
1135 htmlDocDump(stdout, (htmlDocPtr) node);
1136 else
1137 htmlNodeDumpFile(stdout, ctxt->doc, node);
1138#else
1139 if (node->type == XML_DOCUMENT_NODE)
1140 xmlDocDump(stdout, (xmlDocPtr) node);
1141 else
1142 xmlElemDump(stdout, ctxt->doc, node);
1143#endif /* LIBXML_HTML_ENABLED */
1144 } else {
1145 if (node->type == XML_DOCUMENT_NODE)
1146 xmlDocDump(stdout, (xmlDocPtr) node);
1147 else
1148 xmlElemDump(stdout, ctxt->doc, node);
1149 }
1150 printf("\n");
1151 return(0);
1152}
1153
1154/**
1155 * xmlShellLoad:
1156 * @ctxt: the shell context
1157 * @filename: the file name
1158 * @node: unused
1159 * @node2: unused
1160 *
1161 * Implements the XML shell function "load"
1162 * loads a new document specified by the filename
1163 *
1164 * Returns 0 or -1 if loading failed
1165 */
1166int
1167xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1168 xmlNodePtr node2) {
1169 xmlDocPtr doc;
1170 int html = 0;
1171
1172 if (ctxt->doc != NULL)
1173 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
1174
1175 if (html) {
1176#ifdef LIBXML_HTML_ENABLED
1177 doc = htmlParseFile(filename, NULL);
1178#else
1179 printf("HTML support not compiled in\n");
1180 doc = NULL;
1181#endif /* LIBXML_HTML_ENABLED */
1182 } else {
1183 doc = xmlParseFile(filename);
1184 }
1185 if (doc != NULL) {
1186 if (ctxt->loaded == 1) {
1187 xmlFreeDoc(ctxt->doc);
1188 }
1189 ctxt->loaded = 1;
1190#ifdef LIBXML_XPATH_ENABLED
1191 xmlXPathFreeContext(ctxt->pctxt);
1192#endif /* LIBXML_XPATH_ENABLED */
1193 xmlFree(ctxt->filename);
1194 ctxt->doc = doc;
1195 ctxt->node = (xmlNodePtr) doc;
1196#ifdef LIBXML_XPATH_ENABLED
1197 ctxt->pctxt = xmlXPathNewContext(doc);
1198#endif /* LIBXML_XPATH_ENABLED */
1199 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1200 } else
1201 return(-1);
1202 return(0);
1203}
1204
1205/**
1206 * xmlShellWrite:
1207 * @ctxt: the shell context
1208 * @filename: the file name
1209 * @node: a node in the tree
1210 * @node2: unused
1211 *
1212 * Implements the XML shell function "write"
1213 * Write the current node to the filename, it saves the serailization
1214 * of the subtree under the @node specified
1215 *
1216 * Returns 0 or -1 in case of error
1217 */
1218int
1219xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1220 xmlNodePtr node2) {
1221 if (node == NULL)
1222 return(-1);
1223 if ((filename == NULL) || (filename[0] == 0)) {
1224 xmlGenericError(xmlGenericErrorContext,
1225 "Write command requires a filename argument\n");
1226 return(-1);
1227 }
1228#ifdef W_OK
1229 if (access((char *) filename, W_OK)) {
1230 xmlGenericError(xmlGenericErrorContext,
1231 "Cannot write to %s\n", filename);
1232 return(-1);
1233 }
1234#endif
1235 switch(node->type) {
1236 case XML_DOCUMENT_NODE:
1237 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1238 xmlGenericError(xmlGenericErrorContext,
1239 "Failed to write to %s\n", filename);
1240 return(-1);
1241 }
1242 break;
1243 case XML_HTML_DOCUMENT_NODE:
1244#ifdef LIBXML_HTML_ENABLED
1245 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1246 xmlGenericError(xmlGenericErrorContext,
1247 "Failed to write to %s\n", filename);
1248 return(-1);
1249 }
1250#else
1251 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1252 xmlGenericError(xmlGenericErrorContext,
1253 "Failed to write to %s\n", filename);
1254 return(-1);
1255 }
1256#endif /* LIBXML_HTML_ENABLED */
1257 break;
1258 default: {
1259 FILE *f;
1260
1261 f = fopen((char *) filename, "w");
1262 if (f == NULL) {
1263 xmlGenericError(xmlGenericErrorContext,
1264 "Failed to write to %s\n", filename);
1265 return(-1);
1266 }
1267 xmlElemDump(f, ctxt->doc, node);
1268 fclose(f);
1269 }
1270 }
1271 return(0);
1272}
1273
1274/**
1275 * xmlShellSave:
1276 * @ctxt: the shell context
1277 * @filename: the file name (optionnal)
1278 * @node: unused
1279 * @node2: unused
1280 *
1281 * Implements the XML shell function "save"
1282 * Write the current document to the filename, or it's original name
1283 *
1284 * Returns 0 or -1 in case of error
1285 */
1286int
1287xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1288 xmlNodePtr node2) {
1289 if (ctxt->doc == NULL)
1290 return(-1);
1291 if ((filename == NULL) || (filename[0] == 0))
1292 filename = ctxt->filename;
1293#ifdef W_OK
1294 if (access((char *) filename, W_OK)) {
1295 xmlGenericError(xmlGenericErrorContext,
1296 "Cannot save to %s\n", filename);
1297 return(-1);
1298 }
1299#endif
1300 switch(ctxt->doc->type) {
1301 case XML_DOCUMENT_NODE:
1302 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1303 xmlGenericError(xmlGenericErrorContext,
1304 "Failed to save to %s\n", filename);
1305 }
1306 break;
1307 case XML_HTML_DOCUMENT_NODE:
1308#ifdef LIBXML_HTML_ENABLED
1309 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1310 xmlGenericError(xmlGenericErrorContext,
1311 "Failed to save to %s\n", filename);
1312 }
1313#else
1314 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1315 xmlGenericError(xmlGenericErrorContext,
1316 "Failed to save to %s\n", filename);
1317 }
1318#endif /* LIBXML_HTML_ENABLED */
1319 break;
1320 default:
1321 xmlGenericError(xmlGenericErrorContext,
1322 "To save to subparts of a document use the 'write' command\n");
1323 return(-1);
1324
1325 }
1326 return(0);
1327}
1328
1329/**
1330 * xmlShellValidate:
1331 * @ctxt: the shell context
1332 * @dtd: the DTD URI (optionnal)
1333 * @node: unused
1334 * @node2: unused
1335 *
1336 * Implements the XML shell function "validate"
1337 * Validate the document, if a DTD path is provided, then the validation
1338 * is done against the given DTD.
1339 *
1340 * Returns 0 or -1 in case of error
1341 */
1342int
1343xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
1344 xmlNodePtr node2) {
1345 xmlValidCtxt vctxt;
1346 int res = -1;
1347
1348 vctxt.userData = stderr;
1349 vctxt.error = (xmlValidityErrorFunc) fprintf;
1350 vctxt.warning = (xmlValidityWarningFunc) fprintf;
1351
1352 if ((dtd == NULL) || (dtd[0] == 0)) {
1353 res = xmlValidateDocument(&vctxt, ctxt->doc);
1354 } else {
1355 xmlDtdPtr subset;
1356
1357 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1358 if (subset != NULL) {
1359 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1360
1361 xmlFreeDtd(subset);
1362 }
1363 }
1364 return(res);
1365}
1366
1367/**
1368 * xmlShellDu:
1369 * @ctxt: the shell context
1370 * @arg: unused
1371 * @tree: a node defining a subtree
1372 * @node2: unused
1373 *
1374 * Implements the XML shell function "du"
1375 * show the structure of the subtree under node @tree
1376 * If @tree is null, the command works on the current node.
1377 *
1378 * Returns 0 or -1 in case of error
1379 */
1380int
1381xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
1382 xmlNodePtr node2) {
1383 xmlNodePtr node;
1384 int indent = 0,i;
1385
1386 if (tree == NULL) return(-1);
1387 node = tree;
1388 while (node != NULL) {
1389 if ((node->type == XML_DOCUMENT_NODE) ||
1390 (node->type == XML_HTML_DOCUMENT_NODE)) {
1391 printf("/\n");
1392 } else if (node->type == XML_ELEMENT_NODE) {
1393 for (i = 0;i < indent;i++)
1394 printf(" ");
1395 printf("%s\n", node->name);
1396 } else {
1397 }
1398
1399 /*
1400 * Browse the full subtree, deep first
1401 */
1402
1403 if ((node->type == XML_DOCUMENT_NODE) ||
1404 (node->type == XML_HTML_DOCUMENT_NODE)) {
1405 node = ((xmlDocPtr) node)->children;
1406 } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1407 /* deep first */
1408 node = node->children;
1409 indent++;
1410 } else if ((node != tree) && (node->next != NULL)) {
1411 /* then siblings */
1412 node = node->next;
1413 } else if (node != tree) {
1414 /* go up to parents->next if needed */
1415 while (node != tree) {
1416 if (node->parent != NULL) {
1417 node = node->parent;
1418 indent--;
1419 }
1420 if ((node != tree) && (node->next != NULL)) {
1421 node = node->next;
1422 break;
1423 }
1424 if (node->parent == NULL) {
1425 node = NULL;
1426 break;
1427 }
1428 if (node == tree) {
1429 node = NULL;
1430 break;
1431 }
1432 }
1433 /* exit condition */
1434 if (node == tree)
1435 node = NULL;
1436 } else
1437 node = NULL;
1438 }
1439 return(0);
1440}
1441
1442/**
1443 * xmlShellPwd:
1444 * @ctxt: the shell context
1445 * @buffer: the output buffer
1446 * @tree: a node
1447 * @node2: unused
1448 *
1449 * Implements the XML shell function "pwd"
1450 * Show the full path from the root to the node, if needed building
1451 * thumblers when similar elements exists at a given ancestor level.
1452 * The output is compatible with XPath commands.
1453 *
1454 * Returns 0 or -1 in case of error
1455 */
1456int
1457xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
1458 xmlNodePtr node2) {
1459 xmlNodePtr cur, tmp, next;
1460 char buf[500];
1461 char sep;
1462 const char *name;
1463 int occur = 0;
1464
1465 buffer[0] = 0;
1466 if (node == NULL) return(-1);
1467 cur = node;
1468 do {
1469 name = "";
1470 sep= '?';
1471 occur = 0;
1472 if ((cur->type == XML_DOCUMENT_NODE) ||
1473 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1474 sep = '/';
1475 next = NULL;
1476 } else if (cur->type == XML_ELEMENT_NODE) {
1477 sep = '/';
1478 name = (const char *)cur->name;
1479 next = cur->parent;
1480
1481 /*
1482 * Thumbler index computation
1483 */
1484 tmp = cur->prev;
1485 while (tmp != NULL) {
1486 if (xmlStrEqual(cur->name, tmp->name))
1487 occur++;
1488 tmp = tmp->prev;
1489 }
1490 if (occur == 0) {
1491 tmp = cur->next;
1492 while (tmp != NULL) {
1493 if (xmlStrEqual(cur->name, tmp->name))
1494 occur++;
1495 tmp = tmp->next;
1496 }
1497 if (occur != 0) occur = 1;
1498 } else
1499 occur++;
1500 } else if (cur->type == XML_ATTRIBUTE_NODE) {
1501 sep = '@';
1502 name = (const char *) (((xmlAttrPtr) cur)->name);
1503 next = ((xmlAttrPtr) cur)->parent;
1504 } else {
1505 next = cur->parent;
1506 }
1507 if (occur == 0)
1508#ifdef HAVE_SNPRINTF
1509 snprintf(buf, sizeof(buf), "%c%s%s", sep, name, buffer);
1510#else
1511 sprintf(buf, "%c%s%s", sep, name, buffer);
1512#endif
1513 else
1514#ifdef HAVE_SNPRINTF
1515 snprintf(buf, sizeof(buf), "%c%s[%d]%s",
1516 sep, name, occur, buffer);
1517#else
1518 sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
1519#endif
1520 buf[sizeof(buf) - 1] = 0;
1521 /*
1522 * This test prevents buffer overflow, because this routine
1523 * is only called by xmlShell, in which the second argument is
1524 * 500 chars long.
1525 * It is a dirty hack before a cleaner solution is found.
1526 * Documentation should mention that the second argument must
1527 * be at least 500 chars long, and could be stripped if too long.
1528 */
1529 if (strlen(buffer) + strlen(buf) > 499)
1530 break;
1531 strcpy(buffer, buf);
1532 cur = next;
1533 } while (cur != NULL);
1534 return(0);
1535}
1536
1537/**
1538 * xmlShell
1539 * @doc: the initial document
1540 * @filename: the output buffer
1541 * @input: the line reading function
1542 * @output: the output FILE*
1543 *
1544 * Implements the XML shell
1545 * This allow to load, validate, view, modify and save a document
1546 * using a environment similar to a UNIX commandline.
1547 */
1548void
1549xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1550 FILE *output) {
1551 char prompt[500] = "/ > ";
1552 char *cmdline = NULL, *cur;
1553 int nbargs;
1554 char command[100];
1555 char arg[400];
1556 int i;
1557 xmlShellCtxtPtr ctxt;
1558 xmlXPathObjectPtr list;
1559
1560 if (doc == NULL)
1561 return;
1562 if (filename == NULL)
1563 return;
1564 if (input == NULL)
1565 return;
1566 if (output == NULL)
1567 return;
1568 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1569 if (ctxt == NULL)
1570 return;
1571 ctxt->loaded = 0;
1572 ctxt->doc = doc;
1573 ctxt->input = input;
1574 ctxt->output = output;
1575 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1576 ctxt->node = (xmlNodePtr) ctxt->doc;
1577
1578#ifdef LIBXML_XPATH_ENABLED
1579 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1580 if (ctxt->pctxt == NULL) {
1581 xmlFree(ctxt);
1582 return;
1583 }
1584#endif /* LIBXML_XPATH_ENABLED */
1585 while (1) {
1586 if (ctxt->node == (xmlNodePtr) ctxt->doc)
1587 sprintf(prompt, "%s > ", "/");
1588 else if (ctxt->node->name)
1589#ifdef HAVE_SNPRINTF
1590 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
1591#else
1592 sprintf(prompt, "%s > ", ctxt->node->name);
1593#endif
1594 else
1595 sprintf(prompt, "? > ");
1596 prompt[sizeof(prompt) - 1] = 0;
1597
1598 /*
1599 * Get a new command line
1600 */
1601 cmdline = ctxt->input(prompt);
1602 if (cmdline == NULL) break;
1603
1604 /*
1605 * Parse the command itself
1606 */
1607 cur = cmdline;
1608 while ((*cur == ' ') || (*cur == '\t')) cur++;
1609 i = 0;
1610 while ((*cur != ' ') && (*cur != '\t') &&
1611 (*cur != '\n') && (*cur != '\r')) {
1612 if (*cur == 0)
1613 break;
1614 command[i++] = *cur++;
1615 }
1616 command[i] = 0;
1617 if (i == 0) continue;
1618 nbargs++;
1619
1620 /*
1621 * Parse the argument
1622 */
1623 while ((*cur == ' ') || (*cur == '\t')) cur++;
1624 i = 0;
1625 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
1626 if (*cur == 0)
1627 break;
1628 arg[i++] = *cur++;
1629 }
1630 arg[i] = 0;
1631 if (i != 0)
1632 nbargs++;
1633
1634 /*
1635 * start interpreting the command
1636 */
1637 if (!strcmp(command, "exit"))
1638 break;
1639 if (!strcmp(command, "quit"))
1640 break;
1641 if (!strcmp(command, "bye"))
1642 break;
1643 if (!strcmp(command, "validate")) {
1644 xmlShellValidate(ctxt, arg, NULL, NULL);
1645 } else if (!strcmp(command, "load")) {
1646 xmlShellLoad(ctxt, arg, NULL, NULL);
1647 } else if (!strcmp(command, "save")) {
1648 xmlShellSave(ctxt, arg, NULL, NULL);
1649 } else if (!strcmp(command, "write")) {
1650 xmlShellWrite(ctxt, arg, NULL, NULL);
1651 } else if (!strcmp(command, "free")) {
1652 if (arg[0] == 0) {
1653 xmlMemShow(stdout, 0);
1654 } else {
1655 int len = 0;
1656 sscanf(arg, "%d", &len);
1657 xmlMemShow(stdout, len);
1658 }
1659 } else if (!strcmp(command, "pwd")) {
1660 char dir[500];
1661 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
1662 printf("%s\n", dir);
1663 } else if (!strcmp(command, "du")) {
1664 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
1665 } else if ((!strcmp(command, "ls")) ||
1666 (!strcmp(command, "dir"))) {
1667 int dir = (!strcmp(command, "dir"));
1668 if (arg[0] == 0) {
1669 if (dir)
1670 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
1671 else
1672 xmlShellList(ctxt, NULL, ctxt->node, NULL);
1673 } else {
1674 ctxt->pctxt->node = ctxt->node;
1675#ifdef LIBXML_XPATH_ENABLED
1676 ctxt->pctxt->node = ctxt->node;
1677 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1678#else
1679 list = NULL;
1680#endif /* LIBXML_XPATH_ENABLED */
1681 if (list != NULL) {
1682 switch (list->type) {
1683 case XPATH_UNDEFINED:
1684 xmlGenericError(xmlGenericErrorContext,
1685 "%s: no such node\n", arg);
1686 break;
1687 case XPATH_NODESET: {
1688 int i;
1689
1690 for (i = 0;i < list->nodesetval->nodeNr;i++) {
1691 if (dir)
1692 xmlShellDir(ctxt, NULL,
1693 list->nodesetval->nodeTab[i], NULL);
1694 else
1695 xmlShellList(ctxt, NULL,
1696 list->nodesetval->nodeTab[i], NULL);
1697 }
1698 break;
1699 }
1700 case XPATH_BOOLEAN:
1701 xmlGenericError(xmlGenericErrorContext,
1702 "%s is a Boolean\n", arg);
1703 break;
1704 case XPATH_NUMBER:
1705 xmlGenericError(xmlGenericErrorContext,
1706 "%s is a number\n", arg);
1707 break;
1708 case XPATH_STRING:
1709 xmlGenericError(xmlGenericErrorContext,
1710 "%s is a string\n", arg);
1711 break;
1712 case XPATH_POINT:
1713 xmlGenericError(xmlGenericErrorContext,
1714 "%s is a point\n", arg);
1715 break;
1716 case XPATH_RANGE:
1717 xmlGenericError(xmlGenericErrorContext,
1718 "%s is a range\n", arg);
1719 break;
1720 case XPATH_LOCATIONSET:
1721 xmlGenericError(xmlGenericErrorContext,
1722 "%s is a range\n", arg);
1723 break;
1724 case XPATH_USERS:
1725 xmlGenericError(xmlGenericErrorContext,
1726 "%s is user-defined\n", arg);
1727 break;
1728 case XPATH_XSLT_TREE:
1729 xmlGenericError(xmlGenericErrorContext,
1730 "%s is an XSLT value tree\n", arg);
1731 break;
1732 }
1733 xmlXPathFreeNodeSetList(list);
1734 } else {
1735 xmlGenericError(xmlGenericErrorContext,
1736 "%s: no such node\n", arg);
1737 }
1738 ctxt->pctxt->node = NULL;
1739 }
1740 } else if (!strcmp(command, "cd")) {
1741 if (arg[0] == 0) {
1742 ctxt->node = (xmlNodePtr) ctxt->doc;
1743 } else {
1744#ifdef LIBXML_XPATH_ENABLED
1745 ctxt->pctxt->node = ctxt->node;
1746 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1747#else
1748 list = NULL;
1749#endif /* LIBXML_XPATH_ENABLED */
1750 if (list != NULL) {
1751 switch (list->type) {
1752 case XPATH_UNDEFINED:
1753 xmlGenericError(xmlGenericErrorContext,
1754 "%s: no such node\n", arg);
1755 break;
1756 case XPATH_NODESET:
1757 if (list->nodesetval->nodeNr == 1) {
1758 ctxt->node = list->nodesetval->nodeTab[0];
1759 } else
1760 xmlGenericError(xmlGenericErrorContext,
1761 "%s is a %d Node Set\n",
1762 arg, list->nodesetval->nodeNr);
1763 break;
1764 case XPATH_BOOLEAN:
1765 xmlGenericError(xmlGenericErrorContext,
1766 "%s is a Boolean\n", arg);
1767 break;
1768 case XPATH_NUMBER:
1769 xmlGenericError(xmlGenericErrorContext,
1770 "%s is a number\n", arg);
1771 break;
1772 case XPATH_STRING:
1773 xmlGenericError(xmlGenericErrorContext,
1774 "%s is a string\n", arg);
1775 break;
1776 case XPATH_POINT:
1777 xmlGenericError(xmlGenericErrorContext,
1778 "%s is a point\n", arg);
1779 break;
1780 case XPATH_RANGE:
1781 xmlGenericError(xmlGenericErrorContext,
1782 "%s is a range\n", arg);
1783 break;
1784 case XPATH_LOCATIONSET:
1785 xmlGenericError(xmlGenericErrorContext,
1786 "%s is a range\n", arg);
1787 break;
1788 case XPATH_USERS:
1789 xmlGenericError(xmlGenericErrorContext,
1790 "%s is user-defined\n", arg);
1791 break;
1792 case XPATH_XSLT_TREE:
1793 xmlGenericError(xmlGenericErrorContext,
1794 "%s is an XSLT value tree\n", arg);
1795 break;
1796 }
1797 xmlXPathFreeNodeSetList(list);
1798 } else {
1799 xmlGenericError(xmlGenericErrorContext,
1800 "%s: no such node\n", arg);
1801 }
1802 ctxt->pctxt->node = NULL;
1803 }
1804 } else if (!strcmp(command, "cat")) {
1805 if (arg[0] == 0) {
1806 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
1807 } else {
1808 ctxt->pctxt->node = ctxt->node;
1809#ifdef LIBXML_XPATH_ENABLED
1810 ctxt->pctxt->node = ctxt->node;
1811 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1812#else
1813 list = NULL;
1814#endif /* LIBXML_XPATH_ENABLED */
1815 if (list != NULL) {
1816 switch (list->type) {
1817 case XPATH_UNDEFINED:
1818 xmlGenericError(xmlGenericErrorContext,
1819 "%s: no such node\n", arg);
1820 break;
1821 case XPATH_NODESET: {
1822 int i;
1823
1824 for (i = 0;i < list->nodesetval->nodeNr;i++) {
1825 if (i > 0) printf(" -------\n");
1826 xmlShellCat(ctxt, NULL,
1827 list->nodesetval->nodeTab[i], NULL);
1828 }
1829 break;
1830 }
1831 case XPATH_BOOLEAN:
1832 xmlGenericError(xmlGenericErrorContext,
1833 "%s is a Boolean\n", arg);
1834 break;
1835 case XPATH_NUMBER:
1836 xmlGenericError(xmlGenericErrorContext,
1837 "%s is a number\n", arg);
1838 break;
1839 case XPATH_STRING:
1840 xmlGenericError(xmlGenericErrorContext,
1841 "%s is a string\n", arg);
1842 break;
1843 case XPATH_POINT:
1844 xmlGenericError(xmlGenericErrorContext,
1845 "%s is a point\n", arg);
1846 break;
1847 case XPATH_RANGE:
1848 xmlGenericError(xmlGenericErrorContext,
1849 "%s is a range\n", arg);
1850 break;
1851 case XPATH_LOCATIONSET:
1852 xmlGenericError(xmlGenericErrorContext,
1853 "%s is a range\n", arg);
1854 break;
1855 case XPATH_USERS:
1856 xmlGenericError(xmlGenericErrorContext,
1857 "%s is user-defined\n", arg);
1858 break;
1859 case XPATH_XSLT_TREE:
1860 xmlGenericError(xmlGenericErrorContext,
1861 "%s is an XSLT value tree\n", arg);
1862 break;
1863 }
1864 xmlXPathFreeNodeSetList(list);
1865 } else {
1866 xmlGenericError(xmlGenericErrorContext,
1867 "%s: no such node\n", arg);
1868 }
1869 ctxt->pctxt->node = NULL;
1870 }
1871 } else {
1872 xmlGenericError(xmlGenericErrorContext,
1873 "Unknown command %s\n", command);
1874 }
1875 free(cmdline); /* not xmlFree here ! */
1876 }
1877#ifdef LIBXML_XPATH_ENABLED
1878 xmlXPathFreeContext(ctxt->pctxt);
1879#endif /* LIBXML_XPATH_ENABLED */
1880 if (ctxt->loaded) {
1881 xmlFreeDoc(ctxt->doc);
1882 }
1883 xmlFree(ctxt);
1884 if (cmdline != NULL)
1885 free(cmdline); /* not xmlFree here ! */
1886}
1887
1888#endif /* LIBXML_DEBUG_ENABLED */