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