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