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