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