blob: 305654889f9f934f6dd32b4ba33f91e5a5224c2c [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
Daniel Veillard5e2dace2001-07-18 19:30:27 +000032/**
33 * xmlDebugDumpString:
34 * @output: the FILE * for the output
35 * @str: the string
36 *
37 * Dumps informations about the string, shorten it if necessary
38 */
39void
40xmlDebugDumpString(FILE * output, const xmlChar * str)
41{
Owen Taylor3473f882001-02-23 17:55:21 +000042 int i;
Daniel Veillard5e2dace2001-07-18 19:30:27 +000043
Owen Taylor3473f882001-02-23 17:55:21 +000044 if (str == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +000045 fprintf(output, "(NULL)");
46 return;
Owen Taylor3473f882001-02-23 17:55:21 +000047 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +000048 for (i = 0; i < 40; i++)
49 if (str[i] == 0)
50 return;
51 else if (IS_BLANK(str[i]))
52 fputc(' ', output);
53 else if (str[i] >= 0x80)
54 fprintf(output, "#%X", str[i]);
55 else
56 fputc(str[i], output);
Owen Taylor3473f882001-02-23 17:55:21 +000057 fprintf(output, "...");
58}
59
Daniel Veillard56a4cb82001-03-24 17:00:36 +000060static void
61xmlDebugDumpDtdNode(FILE *output, xmlDtdPtr dtd, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +000062 int i;
63 char shift[100];
64
65 for (i = 0;((i < depth) && (i < 25));i++)
66 shift[2 * i] = shift[2 * i + 1] = ' ';
67 shift[2 * i] = shift[2 * i + 1] = 0;
68
69 fprintf(output, shift);
70
71 if (dtd->type != XML_DTD_NODE) {
72 fprintf(output, "PBM: not a DTD\n");
73 return;
74 }
75 if (dtd->name != NULL)
76 fprintf(output, "DTD(%s)", dtd->name);
77 else
78 fprintf(output, "DTD");
79 if (dtd->ExternalID != NULL)
80 fprintf(output, ", PUBLIC %s", dtd->ExternalID);
81 if (dtd->SystemID != NULL)
82 fprintf(output, ", SYSTEM %s", dtd->SystemID);
83 fprintf(output, "\n");
84 /*
85 * Do a bit of checking
86 */
87 if (dtd->parent == NULL)
88 fprintf(output, "PBM: Dtd has no parent\n");
89 if (dtd->doc == NULL)
90 fprintf(output, "PBM: Dtd has no doc\n");
91 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
92 fprintf(output, "PBM: Dtd doc differs from parent's one\n");
93 if (dtd->prev == NULL) {
94 if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
95 fprintf(output, "PBM: Dtd has no prev and not first of list\n");
96 } else {
97 if (dtd->prev->next != (xmlNodePtr) dtd)
98 fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
99 }
100 if (dtd->next == NULL) {
101 if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
102 fprintf(output, "PBM: Dtd has no next and not last of list\n");
103 } else {
104 if (dtd->next->prev != (xmlNodePtr) dtd)
105 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
106 }
107}
108
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000109static void
110xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000111 int i;
112 char shift[100];
113
114 for (i = 0;((i < depth) && (i < 25));i++)
115 shift[2 * i] = shift[2 * i + 1] = ' ';
116 shift[2 * i] = shift[2 * i + 1] = 0;
117
118 fprintf(output, shift);
119
120 if (attr->type != XML_ATTRIBUTE_DECL) {
121 fprintf(output, "PBM: not a Attr\n");
122 return;
123 }
124 if (attr->name != NULL)
125 fprintf(output, "ATTRDECL(%s)", attr->name);
126 else
127 fprintf(output, "PBM ATTRDECL noname!!!");
128 if (attr->elem != NULL)
129 fprintf(output, " for %s", attr->elem);
130 else
131 fprintf(output, " PBM noelem!!!");
132 switch (attr->atype) {
133 case XML_ATTRIBUTE_CDATA:
134 fprintf(output, " CDATA");
135 break;
136 case XML_ATTRIBUTE_ID:
137 fprintf(output, " ID");
138 break;
139 case XML_ATTRIBUTE_IDREF:
140 fprintf(output, " IDREF");
141 break;
142 case XML_ATTRIBUTE_IDREFS:
143 fprintf(output, " IDREFS");
144 break;
145 case XML_ATTRIBUTE_ENTITY:
146 fprintf(output, " ENTITY");
147 break;
148 case XML_ATTRIBUTE_ENTITIES:
149 fprintf(output, " ENTITIES");
150 break;
151 case XML_ATTRIBUTE_NMTOKEN:
152 fprintf(output, " NMTOKEN");
153 break;
154 case XML_ATTRIBUTE_NMTOKENS:
155 fprintf(output, " NMTOKENS");
156 break;
157 case XML_ATTRIBUTE_ENUMERATION:
158 fprintf(output, " ENUMERATION");
159 break;
160 case XML_ATTRIBUTE_NOTATION:
161 fprintf(output, " NOTATION ");
162 break;
163 }
164 if (attr->tree != NULL) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000165 int indx;
Owen Taylor3473f882001-02-23 17:55:21 +0000166 xmlEnumerationPtr cur = attr->tree;
167
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000168 for (indx = 0;indx < 5; indx++) {
169 if (indx != 0)
Owen Taylor3473f882001-02-23 17:55:21 +0000170 fprintf(output, "|%s", cur->name);
171 else
172 fprintf(output, " (%s", cur->name);
173 cur = cur->next;
174 if (cur == NULL) break;
175 }
176 if (cur == NULL)
177 fprintf(output, ")");
178 else
179 fprintf(output, "...)");
180 }
181 switch (attr->def) {
182 case XML_ATTRIBUTE_NONE:
183 break;
184 case XML_ATTRIBUTE_REQUIRED:
185 fprintf(output, " REQUIRED");
186 break;
187 case XML_ATTRIBUTE_IMPLIED:
188 fprintf(output, " IMPLIED");
189 break;
190 case XML_ATTRIBUTE_FIXED:
191 fprintf(output, " FIXED");
192 break;
193 }
194 if (attr->defaultValue != NULL) {
195 fprintf(output, "\"");
196 xmlDebugDumpString(output, attr->defaultValue);
197 fprintf(output, "\"");
198 }
199 printf("\n");
200
201 /*
202 * Do a bit of checking
203 */
204 if (attr->parent == NULL)
205 fprintf(output, "PBM: Attr has no parent\n");
206 if (attr->doc == NULL)
207 fprintf(output, "PBM: Attr has no doc\n");
208 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
209 fprintf(output, "PBM: Attr doc differs from parent's one\n");
210 if (attr->prev == NULL) {
211 if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr))
212 fprintf(output, "PBM: Attr has no prev and not first of list\n");
213 } else {
214 if (attr->prev->next != (xmlNodePtr) attr)
215 fprintf(output, "PBM: Attr prev->next : back link wrong\n");
216 }
217 if (attr->next == NULL) {
218 if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr))
219 fprintf(output, "PBM: Attr has no next and not last of list\n");
220 } else {
221 if (attr->next->prev != (xmlNodePtr) attr)
222 fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
223 }
224}
225
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000226static void
227xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000228 int i;
229 char shift[100];
230
231 for (i = 0;((i < depth) && (i < 25));i++)
232 shift[2 * i] = shift[2 * i + 1] = ' ';
233 shift[2 * i] = shift[2 * i + 1] = 0;
234
235 fprintf(output, shift);
236
237 if (elem->type != XML_ELEMENT_DECL) {
238 fprintf(output, "PBM: not a Elem\n");
239 return;
240 }
241 if (elem->name != NULL) {
242 fprintf(output, "ELEMDECL(");
243 xmlDebugDumpString(output, elem->name);
244 fprintf(output, ")");
245 } else
246 fprintf(output, "PBM ELEMDECL noname!!!");
247 switch (elem->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000248 case XML_ELEMENT_TYPE_UNDEFINED:
249 fprintf(output, ", UNDEFINED");
250 break;
Owen Taylor3473f882001-02-23 17:55:21 +0000251 case XML_ELEMENT_TYPE_EMPTY:
252 fprintf(output, ", EMPTY");
253 break;
254 case XML_ELEMENT_TYPE_ANY:
255 fprintf(output, ", ANY");
256 break;
257 case XML_ELEMENT_TYPE_MIXED:
258 fprintf(output, ", MIXED ");
259 break;
260 case XML_ELEMENT_TYPE_ELEMENT:
261 fprintf(output, ", MIXED ");
262 break;
263 }
Daniel Veillard7db37732001-07-12 01:20:08 +0000264 if ((elem->type != XML_ELEMENT_NODE) &&
265 (elem->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000266 char buf[5001];
267
268 buf[0] = 0;
269 xmlSprintfElementContent(buf, elem->content, 1);
270 buf[5000] = 0;
271 fprintf(output, "%s", buf);
272 }
273 printf("\n");
274
275 /*
276 * Do a bit of checking
277 */
278 if (elem->parent == NULL)
279 fprintf(output, "PBM: Elem has no parent\n");
280 if (elem->doc == NULL)
281 fprintf(output, "PBM: Elem has no doc\n");
282 if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
283 fprintf(output, "PBM: Elem doc differs from parent's one\n");
284 if (elem->prev == NULL) {
285 if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem))
286 fprintf(output, "PBM: Elem has no prev and not first of list\n");
287 } else {
288 if (elem->prev->next != (xmlNodePtr) elem)
289 fprintf(output, "PBM: Elem prev->next : back link wrong\n");
290 }
291 if (elem->next == NULL) {
292 if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem))
293 fprintf(output, "PBM: Elem has no next and not last of list\n");
294 } else {
295 if (elem->next->prev != (xmlNodePtr) elem)
296 fprintf(output, "PBM: Elem next->prev : forward link wrong\n");
297 }
298}
299
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000300static void
301xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000302 int i;
303 char shift[100];
304
305 for (i = 0;((i < depth) && (i < 25));i++)
306 shift[2 * i] = shift[2 * i + 1] = ' ';
307 shift[2 * i] = shift[2 * i + 1] = 0;
308
309 fprintf(output, shift);
310
311 if (ent->type != XML_ENTITY_DECL) {
312 fprintf(output, "PBM: not a Entity decl\n");
313 return;
314 }
315 if (ent->name != NULL) {
316 fprintf(output, "ENTITYDECL(");
317 xmlDebugDumpString(output, ent->name);
318 fprintf(output, ")");
319 } else
320 fprintf(output, "PBM ENTITYDECL noname!!!");
321 switch (ent->etype) {
322 case XML_INTERNAL_GENERAL_ENTITY:
323 fprintf(output, ", internal\n");
324 break;
325 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
326 fprintf(output, ", external parsed\n");
327 break;
328 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
329 fprintf(output, ", unparsed\n");
330 break;
331 case XML_INTERNAL_PARAMETER_ENTITY:
332 fprintf(output, ", parameter\n");
333 break;
334 case XML_EXTERNAL_PARAMETER_ENTITY:
335 fprintf(output, ", external parameter\n");
336 break;
337 case XML_INTERNAL_PREDEFINED_ENTITY:
338 fprintf(output, ", predefined\n");
339 break;
340 }
341 if (ent->ExternalID) {
342 fprintf(output, shift);
343 fprintf(output, " ExternalID=%s\n", ent->ExternalID);
344 }
345 if (ent->SystemID) {
346 fprintf(output, shift);
347 fprintf(output, " SystemID=%s\n", ent->SystemID);
348 }
349 if (ent->URI != NULL) {
350 fprintf(output, shift);
351 fprintf(output, " URI=%s\n", ent->URI);
352 }
353 if (ent->content) {
354 fprintf(output, shift);
355 fprintf(output, " content=");
356 xmlDebugDumpString(output, ent->content);
357 fprintf(output, "\n");
358 }
359
360 /*
361 * Do a bit of checking
362 */
363 if (ent->parent == NULL)
364 fprintf(output, "PBM: Ent has no parent\n");
365 if (ent->doc == NULL)
366 fprintf(output, "PBM: Ent has no doc\n");
367 if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
368 fprintf(output, "PBM: Ent doc differs from parent's one\n");
369 if (ent->prev == NULL) {
370 if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent))
371 fprintf(output, "PBM: Ent has no prev and not first of list\n");
372 } else {
373 if (ent->prev->next != (xmlNodePtr) ent)
374 fprintf(output, "PBM: Ent prev->next : back link wrong\n");
375 }
376 if (ent->next == NULL) {
377 if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent))
378 fprintf(output, "PBM: Ent has no next and not last of list\n");
379 } else {
380 if (ent->next->prev != (xmlNodePtr) ent)
381 fprintf(output, "PBM: Ent next->prev : forward link wrong\n");
382 }
383}
384
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000385static void
386xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000387 int i;
388 char shift[100];
389
390 for (i = 0;((i < depth) && (i < 25));i++)
391 shift[2 * i] = shift[2 * i + 1] = ' ';
392 shift[2 * i] = shift[2 * i + 1] = 0;
393
394 fprintf(output, shift);
395 if (ns->type != XML_NAMESPACE_DECL) {
396 fprintf(output, "invalid namespace node %d\n", ns->type);
397 return;
398 }
399 if (ns->href == NULL) {
400 if (ns->prefix != NULL)
401 fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix);
402 else
403 fprintf(output, "incomplete default namespace href=NULL\n");
404 } else {
405 if (ns->prefix != NULL)
406 fprintf(output, "namespace %s href=", ns->prefix);
407 else
408 fprintf(output, "default namespace href=");
409
410 xmlDebugDumpString(output, ns->href);
411 fprintf(output, "\n");
412 }
413}
414
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000415static void
416xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000417 while (ns != NULL) {
418 xmlDebugDumpNamespace(output, ns, depth);
419 ns = ns->next;
420 }
421}
422
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000423static void
424xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000425 int i;
426 char shift[100];
427
428 for (i = 0;((i < depth) && (i < 25));i++)
429 shift[2 * i] = shift[2 * i + 1] = ' ';
430 shift[2 * i] = shift[2 * i + 1] = 0;
431
432 fprintf(output, shift);
433 switch (ent->etype) {
434 case XML_INTERNAL_GENERAL_ENTITY:
435 fprintf(output, "INTERNAL_GENERAL_ENTITY ");
436 break;
437 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
438 fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
439 break;
440 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
441 fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
442 break;
443 case XML_INTERNAL_PARAMETER_ENTITY:
444 fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
445 break;
446 case XML_EXTERNAL_PARAMETER_ENTITY:
447 fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
448 break;
449 default:
450 fprintf(output, "ENTITY_%d ! ", ent->etype);
451 }
452 fprintf(output, "%s\n", ent->name);
453 if (ent->ExternalID) {
454 fprintf(output, shift);
455 fprintf(output, "ExternalID=%s\n", ent->ExternalID);
456 }
457 if (ent->SystemID) {
458 fprintf(output, shift);
459 fprintf(output, "SystemID=%s\n", ent->SystemID);
460 }
461 if (ent->URI) {
462 fprintf(output, shift);
463 fprintf(output, "URI=%s\n", ent->URI);
464 }
465 if (ent->content) {
466 fprintf(output, shift);
467 fprintf(output, "content=");
468 xmlDebugDumpString(output, ent->content);
469 fprintf(output, "\n");
470 }
471}
472
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000473/**
474 * xmlDebugDumpAttr:
475 * @output: the FILE * for the output
476 * @attr: the attribute
477 * @depth: the indentation level.
478 *
479 * Dumps debug information for the attribute
480 */
481void
482xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000483 int i;
484 char shift[100];
485
486 for (i = 0;((i < depth) && (i < 25));i++)
487 shift[2 * i] = shift[2 * i + 1] = ' ';
488 shift[2 * i] = shift[2 * i + 1] = 0;
489
490 fprintf(output, shift);
491
492 fprintf(output, "ATTRIBUTE ");
493 xmlDebugDumpString(output, attr->name);
494 fprintf(output, "\n");
495 if (attr->children != NULL)
496 xmlDebugDumpNodeList(output, attr->children, depth + 1);
497
498 /*
499 * Do a bit of checking
500 */
501 if (attr->parent == NULL)
502 fprintf(output, "PBM: Attr has no parent\n");
503 if (attr->doc == NULL)
504 fprintf(output, "PBM: Attr has no doc\n");
505 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
506 fprintf(output, "PBM: Attr doc differs from parent's one\n");
507 if (attr->prev == NULL) {
508 if ((attr->parent != NULL) && (attr->parent->properties != attr))
509 fprintf(output, "PBM: Attr has no prev and not first of list\n");
510 } else {
511 if (attr->prev->next != attr)
512 fprintf(output, "PBM: Attr prev->next : back link wrong\n");
513 }
514 if (attr->next != NULL) {
515 if (attr->next->prev != attr)
516 fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
517 }
518}
519
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000520/**
521 * xmlDebugDumpAttrList:
522 * @output: the FILE * for the output
523 * @attr: the attribute list
524 * @depth: the indentation level.
525 *
526 * Dumps debug information for the attribute list
527 */
528void
529xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
530{
Owen Taylor3473f882001-02-23 17:55:21 +0000531 while (attr != NULL) {
532 xmlDebugDumpAttr(output, attr, depth);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000533 attr = attr->next;
Owen Taylor3473f882001-02-23 17:55:21 +0000534 }
535}
536
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000537/**
538 * xmlDebugDumpOneNode:
539 * @output: the FILE * for the output
540 * @node: the node
541 * @depth: the indentation level.
542 *
543 * Dumps debug information for the element node, it is not recursive
544 */
545void
546xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
547{
Owen Taylor3473f882001-02-23 17:55:21 +0000548 int i;
549 char shift[100];
550
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000551 for (i = 0; ((i < depth) && (i < 25)); i++)
Owen Taylor3473f882001-02-23 17:55:21 +0000552 shift[2 * i] = shift[2 * i + 1] = ' ';
553 shift[2 * i] = shift[2 * i + 1] = 0;
554
555 switch (node->type) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000556 case XML_ELEMENT_NODE:
557 fprintf(output, shift);
558 fprintf(output, "ELEMENT ");
559 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
560 xmlDebugDumpString(output, node->ns->prefix);
561 fprintf(output, ":");
562 }
563 xmlDebugDumpString(output, node->name);
564 fprintf(output, "\n");
565 break;
566 case XML_ATTRIBUTE_NODE:
567 fprintf(output, shift);
568 fprintf(output, "Error, ATTRIBUTE found here\n");
569 break;
570 case XML_TEXT_NODE:
571 fprintf(output, shift);
572 fprintf(output, "TEXT\n");
573 break;
574 case XML_CDATA_SECTION_NODE:
575 fprintf(output, shift);
576 fprintf(output, "CDATA_SECTION\n");
577 break;
578 case XML_ENTITY_REF_NODE:
579 fprintf(output, shift);
580 fprintf(output, "ENTITY_REF(%s)\n", node->name);
581 break;
582 case XML_ENTITY_NODE:
583 fprintf(output, shift);
584 fprintf(output, "ENTITY\n");
585 break;
586 case XML_PI_NODE:
587 fprintf(output, shift);
588 fprintf(output, "PI %s\n", node->name);
589 break;
590 case XML_COMMENT_NODE:
591 fprintf(output, shift);
592 fprintf(output, "COMMENT\n");
593 break;
594 case XML_DOCUMENT_NODE:
595 case XML_HTML_DOCUMENT_NODE:
596 fprintf(output, shift);
597 fprintf(output, "Error, DOCUMENT found here\n");
598 break;
599 case XML_DOCUMENT_TYPE_NODE:
600 fprintf(output, shift);
601 fprintf(output, "DOCUMENT_TYPE\n");
602 break;
603 case XML_DOCUMENT_FRAG_NODE:
604 fprintf(output, shift);
605 fprintf(output, "DOCUMENT_FRAG\n");
606 break;
607 case XML_NOTATION_NODE:
608 fprintf(output, shift);
609 fprintf(output, "NOTATION\n");
610 break;
611 case XML_DTD_NODE:
612 xmlDebugDumpDtdNode(output, (xmlDtdPtr) node, depth);
613 return;
614 case XML_ELEMENT_DECL:
615 xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
616 return;
617 case XML_ATTRIBUTE_DECL:
618 xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
619 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000620 case XML_ENTITY_DECL:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000621 xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
622 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000623 case XML_NAMESPACE_DECL:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000624 xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
625 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000626 case XML_XINCLUDE_START:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000627 fprintf(output, shift);
628 fprintf(output, "INCLUDE START\n");
629 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000630 case XML_XINCLUDE_END:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000631 fprintf(output, shift);
632 fprintf(output, "INCLUDE END\n");
633 return;
634 default:
635 fprintf(output, shift);
636 fprintf(output, "NODE_%d !!!\n", node->type);
637 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000638 }
639 if (node->doc == NULL) {
640 fprintf(output, shift);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000641 fprintf(output, "doc == NULL !!!\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000642 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000643 if (node->nsDef != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000644 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
645 if (node->properties != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000646 xmlDebugDumpAttrList(output, node->properties, depth + 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000647 if (node->type != XML_ENTITY_REF_NODE) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000648 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
649 shift[2 * i] = shift[2 * i + 1] = ' ';
650 shift[2 * i + 2] = shift[2 * i + 3] = 0;
651 fprintf(output, shift);
652 fprintf(output, "content=");
653#ifndef XML_USE_BUFFER_CONTENT
654 xmlDebugDumpString(output, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000655#else
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000656 xmlDebugDumpString(output, xmlBufferContent(node->content));
Owen Taylor3473f882001-02-23 17:55:21 +0000657#endif
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000658 fprintf(output, "\n");
659 }
Owen Taylor3473f882001-02-23 17:55:21 +0000660 } else {
661 xmlEntityPtr ent;
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000662
663 ent = xmlGetDocEntity(node->doc, node->name);
664 if (ent != NULL)
665 xmlDebugDumpEntity(output, ent, depth + 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000666 }
667 /*
668 * Do a bit of checking
669 */
670 if (node->parent == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000671 fprintf(output, "PBM: Node has no parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000672 if (node->doc == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000673 fprintf(output, "PBM: Node has no doc\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000674 if ((node->parent != NULL) && (node->doc != node->parent->doc))
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000675 fprintf(output, "PBM: Node doc differs from parent's one\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000676 if (node->prev == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000677 if ((node->parent != NULL) && (node->parent->children != node))
678 fprintf(output,
679 "PBM: Node has no prev and not first of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000680 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000681 if (node->prev->next != node)
682 fprintf(output, "PBM: Node prev->next : back link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000683 }
684 if (node->next == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000685 if ((node->parent != NULL) && (node->parent->last != node))
686 fprintf(output,
687 "PBM: Node has no next and not last of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000688 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000689 if (node->next->prev != node)
690 fprintf(output, "PBM: Node next->prev : forward link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000691 }
692}
693
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000694/**
695 * xmlDebugDumpNode:
696 * @output: the FILE * for the output
697 * @node: the node
698 * @depth: the indentation level.
699 *
700 * Dumps debug information for the element node, it is recursive
701 */
702void
703xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
704{
Owen Taylor3473f882001-02-23 17:55:21 +0000705 xmlDebugDumpOneNode(output, node, depth);
706 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000707 xmlDebugDumpNodeList(output, node->children, depth + 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000708}
709
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000710/**
711 * xmlDebugDumpNodeList:
712 * @output: the FILE * for the output
713 * @node: the node list
714 * @depth: the indentation level.
715 *
716 * Dumps debug information for the list of element node, it is recursive
717 */
718void
719xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
720{
Owen Taylor3473f882001-02-23 17:55:21 +0000721 while (node != NULL) {
722 xmlDebugDumpNode(output, node, depth);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000723 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +0000724 }
725}
726
727
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000728/**
729 * xmlDebugDumpDocumentHead:
730 * @output: the FILE * for the output
731 * @doc: the document
732 *
733 * Dumps debug information cncerning the document, not recursive
734 */
735void
736xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
737{
738 if (output == NULL)
739 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +0000740 if (doc == NULL) {
741 fprintf(output, "DOCUMENT == NULL !\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000742 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000743 }
744
745 switch (doc->type) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000746 case XML_ELEMENT_NODE:
747 fprintf(output, "Error, ELEMENT found here ");
748 break;
749 case XML_ATTRIBUTE_NODE:
750 fprintf(output, "Error, ATTRIBUTE found here\n");
751 break;
752 case XML_TEXT_NODE:
753 fprintf(output, "Error, TEXT\n");
754 break;
755 case XML_CDATA_SECTION_NODE:
756 fprintf(output, "Error, CDATA_SECTION\n");
757 break;
758 case XML_ENTITY_REF_NODE:
759 fprintf(output, "Error, ENTITY_REF\n");
760 break;
761 case XML_ENTITY_NODE:
762 fprintf(output, "Error, ENTITY\n");
763 break;
764 case XML_PI_NODE:
765 fprintf(output, "Error, PI\n");
766 break;
767 case XML_COMMENT_NODE:
768 fprintf(output, "Error, COMMENT\n");
769 break;
770 case XML_DOCUMENT_NODE:
771 fprintf(output, "DOCUMENT\n");
772 break;
773 case XML_HTML_DOCUMENT_NODE:
774 fprintf(output, "HTML DOCUMENT\n");
775 break;
776 case XML_DOCUMENT_TYPE_NODE:
777 fprintf(output, "Error, DOCUMENT_TYPE\n");
778 break;
779 case XML_DOCUMENT_FRAG_NODE:
780 fprintf(output, "Error, DOCUMENT_FRAG\n");
781 break;
782 case XML_NOTATION_NODE:
783 fprintf(output, "Error, NOTATION\n");
784 break;
785 default:
786 fprintf(output, "NODE_%d\n", doc->type);
Owen Taylor3473f882001-02-23 17:55:21 +0000787 }
788 if (doc->name != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000789 fprintf(output, "name=");
Owen Taylor3473f882001-02-23 17:55:21 +0000790 xmlDebugDumpString(output, BAD_CAST doc->name);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000791 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000792 }
793 if (doc->version != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000794 fprintf(output, "version=");
Owen Taylor3473f882001-02-23 17:55:21 +0000795 xmlDebugDumpString(output, doc->version);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000796 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000797 }
798 if (doc->encoding != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000799 fprintf(output, "encoding=");
Owen Taylor3473f882001-02-23 17:55:21 +0000800 xmlDebugDumpString(output, doc->encoding);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000801 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000802 }
803 if (doc->URL != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000804 fprintf(output, "URL=");
Owen Taylor3473f882001-02-23 17:55:21 +0000805 xmlDebugDumpString(output, doc->URL);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000806 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000807 }
808 if (doc->standalone)
809 fprintf(output, "standalone=true\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000810 if (doc->oldNs != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000811 xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
812}
813
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000814/**
815 * xmlDebugDumpDocument:
816 * @output: the FILE * for the output
817 * @doc: the document
818 *
819 * Dumps debug information for the document, it's recursive
820 */
821void
822xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
823{
824 if (output == NULL)
825 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +0000826 if (doc == NULL) {
827 fprintf(output, "DOCUMENT == NULL !\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000828 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000829 }
830 xmlDebugDumpDocumentHead(output, doc);
831 if (((doc->type == XML_DOCUMENT_NODE) ||
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000832 (doc->type == XML_HTML_DOCUMENT_NODE)) && (doc->children != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +0000833 xmlDebugDumpNodeList(output, doc->children, 1);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000834}
Owen Taylor3473f882001-02-23 17:55:21 +0000835
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000836/**
837 * xmlDebugDumpDTD:
838 * @output: the FILE * for the output
839 * @dtd: the DTD
840 *
841 * Dumps debug information for the DTD
842 */
843void
844xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
845{
Owen Taylor3473f882001-02-23 17:55:21 +0000846 if (dtd == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000847 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000848 if (dtd->type != XML_DTD_NODE) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000849 fprintf(output, "PBM: not a DTD\n");
850 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000851 }
852 if (dtd->name != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000853 fprintf(output, "DTD(%s)", dtd->name);
Owen Taylor3473f882001-02-23 17:55:21 +0000854 else
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000855 fprintf(output, "DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000856 if (dtd->ExternalID != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000857 fprintf(output, ", PUBLIC %s", dtd->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +0000858 if (dtd->SystemID != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000859 fprintf(output, ", SYSTEM %s", dtd->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +0000860 fprintf(output, "\n");
861 /*
862 * Do a bit of checking
863 */
864 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000865 fprintf(output, "PBM: Dtd doc differs from parent's one\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000866 if (dtd->prev == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000867 if ((dtd->parent != NULL)
868 && (dtd->parent->children != (xmlNodePtr) dtd))
869 fprintf(output,
870 "PBM: Dtd has no prev and not first of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000871 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000872 if (dtd->prev->next != (xmlNodePtr) dtd)
873 fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000874 }
875 if (dtd->next == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000876 if ((dtd->parent != NULL)
877 && (dtd->parent->last != (xmlNodePtr) dtd))
878 fprintf(output, "PBM: Dtd has no next and not last of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000879 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000880 if (dtd->next->prev != (xmlNodePtr) dtd)
881 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000882 }
883 if (dtd->children == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000884 fprintf(output, " DTD is empty\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000885 else
886 xmlDebugDumpNodeList(output, dtd->children, 1);
887}
888
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000889static void
890xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output) {
Owen Taylor3473f882001-02-23 17:55:21 +0000891 fprintf(output, "%s : ", cur->name);
892 switch (cur->etype) {
893 case XML_INTERNAL_GENERAL_ENTITY:
894 fprintf(output, "INTERNAL GENERAL, ");
895 break;
896 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
897 fprintf(output, "EXTERNAL PARSED, ");
898 break;
899 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
900 fprintf(output, "EXTERNAL UNPARSED, ");
901 break;
902 case XML_INTERNAL_PARAMETER_ENTITY:
903 fprintf(output, "INTERNAL PARAMETER, ");
904 break;
905 case XML_EXTERNAL_PARAMETER_ENTITY:
906 fprintf(output, "EXTERNAL PARAMETER, ");
907 break;
908 default:
909 fprintf(output, "UNKNOWN TYPE %d",
910 cur->etype);
911 }
912 if (cur->ExternalID != NULL)
913 fprintf(output, "ID \"%s\"", cur->ExternalID);
914 if (cur->SystemID != NULL)
915 fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
916 if (cur->orig != NULL)
917 fprintf(output, "\n orig \"%s\"", cur->orig);
Daniel Veillard7db37732001-07-12 01:20:08 +0000918 if ((cur->type != XML_ELEMENT_NODE) &&
919 (cur->content != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +0000920 fprintf(output, "\n content \"%s\"", cur->content);
921 fprintf(output, "\n");
922}
923
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000924/**
925 * xmlDebugDumpEntities:
926 * @output: the FILE * for the output
927 * @doc: the document
928 *
929 * Dumps debug information for all the entities in use by the document
930 */
931void
932xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
933{
934 if (output == NULL)
935 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +0000936 if (doc == NULL) {
937 fprintf(output, "DOCUMENT == NULL !\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000938 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000939 }
940
941 switch (doc->type) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000942 case XML_ELEMENT_NODE:
943 fprintf(output, "Error, ELEMENT found here ");
944 break;
945 case XML_ATTRIBUTE_NODE:
946 fprintf(output, "Error, ATTRIBUTE found here\n");
947 break;
948 case XML_TEXT_NODE:
949 fprintf(output, "Error, TEXT\n");
950 break;
951 case XML_CDATA_SECTION_NODE:
952 fprintf(output, "Error, CDATA_SECTION\n");
953 break;
954 case XML_ENTITY_REF_NODE:
955 fprintf(output, "Error, ENTITY_REF\n");
956 break;
957 case XML_ENTITY_NODE:
958 fprintf(output, "Error, ENTITY\n");
959 break;
960 case XML_PI_NODE:
961 fprintf(output, "Error, PI\n");
962 break;
963 case XML_COMMENT_NODE:
964 fprintf(output, "Error, COMMENT\n");
965 break;
966 case XML_DOCUMENT_NODE:
967 fprintf(output, "DOCUMENT\n");
968 break;
969 case XML_HTML_DOCUMENT_NODE:
970 fprintf(output, "HTML DOCUMENT\n");
971 break;
972 case XML_DOCUMENT_TYPE_NODE:
973 fprintf(output, "Error, DOCUMENT_TYPE\n");
974 break;
975 case XML_DOCUMENT_FRAG_NODE:
976 fprintf(output, "Error, DOCUMENT_FRAG\n");
977 break;
978 case XML_NOTATION_NODE:
979 fprintf(output, "Error, NOTATION\n");
980 break;
981 default:
982 fprintf(output, "NODE_%d\n", doc->type);
Owen Taylor3473f882001-02-23 17:55:21 +0000983 }
984 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000985 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
986 doc->intSubset->entities;
987
988 fprintf(output, "Entities in internal subset\n");
989 xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
990 output);
Owen Taylor3473f882001-02-23 17:55:21 +0000991 } else
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000992 fprintf(output, "No entities in internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000993 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000994 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
995 doc->extSubset->entities;
996
997 fprintf(output, "Entities in external subset\n");
998 xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
999 output);
Owen Taylor3473f882001-02-23 17:55:21 +00001000 } else
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001001 fprintf(output, "No entities in external subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001002}
1003
1004static int xmlLsCountNode(xmlNodePtr node) {
1005 int ret = 0;
1006 xmlNodePtr list = NULL;
1007
1008 switch (node->type) {
1009 case XML_ELEMENT_NODE:
1010 list = node->children;
1011 break;
1012 case XML_DOCUMENT_NODE:
1013 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00001014#ifdef LIBXML_DOCB_ENABLED
1015 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00001016#endif
1017 list = ((xmlDocPtr) node)->children;
1018 break;
1019 case XML_ATTRIBUTE_NODE:
1020 list = ((xmlAttrPtr) node)->children;
1021 break;
1022 case XML_TEXT_NODE:
1023 case XML_CDATA_SECTION_NODE:
1024 case XML_PI_NODE:
1025 case XML_COMMENT_NODE:
1026 if (node->content != NULL) {
1027#ifndef XML_USE_BUFFER_CONTENT
1028 ret = xmlStrlen(node->content);
1029#else
1030 ret = xmlBufferLength(node->content);
1031#endif
1032 }
1033 break;
1034 case XML_ENTITY_REF_NODE:
1035 case XML_DOCUMENT_TYPE_NODE:
1036 case XML_ENTITY_NODE:
1037 case XML_DOCUMENT_FRAG_NODE:
1038 case XML_NOTATION_NODE:
1039 case XML_DTD_NODE:
1040 case XML_ELEMENT_DECL:
1041 case XML_ATTRIBUTE_DECL:
1042 case XML_ENTITY_DECL:
1043 case XML_NAMESPACE_DECL:
1044 case XML_XINCLUDE_START:
1045 case XML_XINCLUDE_END:
1046 ret = 1;
1047 break;
1048 }
1049 for (;list != NULL;ret++)
1050 list = list->next;
1051 return(ret);
1052}
1053
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001054static void
1055xmlLsOneNode(FILE *output, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001056 switch (node->type) {
1057 case XML_ELEMENT_NODE:
1058 fprintf(output, "-");
1059 break;
1060 case XML_ATTRIBUTE_NODE:
1061 fprintf(output, "a");
1062 break;
1063 case XML_TEXT_NODE:
1064 fprintf(output, "t");
1065 break;
1066 case XML_CDATA_SECTION_NODE:
1067 fprintf(output, "c");
1068 break;
1069 case XML_ENTITY_REF_NODE:
1070 fprintf(output, "e");
1071 break;
1072 case XML_ENTITY_NODE:
1073 fprintf(output, "E");
1074 break;
1075 case XML_PI_NODE:
1076 fprintf(output, "p");
1077 break;
1078 case XML_COMMENT_NODE:
1079 fprintf(output, "c");
1080 break;
1081 case XML_DOCUMENT_NODE:
1082 fprintf(output, "d");
1083 break;
1084 case XML_HTML_DOCUMENT_NODE:
1085 fprintf(output, "h");
1086 break;
1087 case XML_DOCUMENT_TYPE_NODE:
1088 fprintf(output, "T");
1089 break;
1090 case XML_DOCUMENT_FRAG_NODE:
1091 fprintf(output, "F");
1092 break;
1093 case XML_NOTATION_NODE:
1094 fprintf(output, "N");
1095 break;
1096 default:
1097 fprintf(output, "?");
1098 }
1099 if (node->properties != NULL)
1100 fprintf(output, "a");
1101 else
1102 fprintf(output, "-");
1103 if (node->nsDef != NULL)
1104 fprintf(output, "n");
1105 else
1106 fprintf(output, "-");
1107
1108 fprintf(output, " %8d ", xmlLsCountNode(node));
1109
1110 switch (node->type) {
1111 case XML_ELEMENT_NODE:
1112 if (node->name != NULL)
1113 fprintf(output, "%s", node->name);
1114 break;
1115 case XML_ATTRIBUTE_NODE:
1116 if (node->name != NULL)
1117 fprintf(output, "%s", node->name);
1118 break;
1119 case XML_TEXT_NODE:
1120 if (node->content != NULL) {
1121#ifndef XML_USE_BUFFER_CONTENT
1122 xmlDebugDumpString(output, node->content);
1123#else
1124 xmlDebugDumpString(output, xmlBufferContent(node->content));
1125#endif
1126 }
1127 break;
1128 case XML_CDATA_SECTION_NODE:
1129 break;
1130 case XML_ENTITY_REF_NODE:
1131 if (node->name != NULL)
1132 fprintf(output, "%s", node->name);
1133 break;
1134 case XML_ENTITY_NODE:
1135 if (node->name != NULL)
1136 fprintf(output, "%s", node->name);
1137 break;
1138 case XML_PI_NODE:
1139 if (node->name != NULL)
1140 fprintf(output, "%s", node->name);
1141 break;
1142 case XML_COMMENT_NODE:
1143 break;
1144 case XML_DOCUMENT_NODE:
1145 break;
1146 case XML_HTML_DOCUMENT_NODE:
1147 break;
1148 case XML_DOCUMENT_TYPE_NODE:
1149 break;
1150 case XML_DOCUMENT_FRAG_NODE:
1151 break;
1152 case XML_NOTATION_NODE:
1153 break;
1154 default:
1155 if (node->name != NULL)
1156 fprintf(output, "%s", node->name);
1157 }
1158 fprintf(output, "\n");
1159}
1160
1161/****************************************************************
1162 * *
1163 * The XML shell related functions *
1164 * *
1165 ****************************************************************/
1166
1167/*
1168 * TODO: Improvement/cleanups for the XML shell
1169 * - allow to shell out an editor on a subpart
1170 * - cleanup function registrations (with help) and calling
1171 * - provide registration routines
1172 */
1173
1174/**
1175 * xmlShellList:
1176 * @ctxt: the shell context
1177 * @arg: unused
1178 * @node: a node
1179 * @node2: unused
1180 *
1181 * Implements the XML shell function "ls"
1182 * Does an Unix like listing of the given node (like a directory)
1183 *
1184 * Returns 0
1185 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001186static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001187xmlShellList(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED , char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1188 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001189 xmlNodePtr cur;
1190
1191 if ((node->type == XML_DOCUMENT_NODE) ||
1192 (node->type == XML_HTML_DOCUMENT_NODE)) {
1193 cur = ((xmlDocPtr) node)->children;
1194 } else if (node->children != NULL) {
1195 cur = node->children;
1196 } else {
1197 xmlLsOneNode(stdout, node);
1198 return(0);
1199 }
1200 while (cur != NULL) {
1201 xmlLsOneNode(stdout, cur);
1202 cur = cur->next;
1203 }
1204 return(0);
1205}
1206
1207/**
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001208 * xmlShellBase:
1209 * @ctxt: the shell context
1210 * @arg: unused
1211 * @node: a node
1212 * @node2: unused
1213 *
1214 * Implements the XML shell function "base"
1215 * dumps the current XML base of the node
1216 *
1217 * Returns 0
1218 */
1219static int
1220xmlShellBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1221 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
1222 xmlChar *base;
1223
1224 base = xmlNodeGetBase(node->doc, node);
1225
1226 if (base == NULL) {
1227 printf(" No base found !!!\n");
1228 } else {
1229 printf("%s\n", base);
1230 xmlFree(base);
1231 }
1232 return(0);
1233}
1234
1235/**
Owen Taylor3473f882001-02-23 17:55:21 +00001236 * xmlShellDir:
1237 * @ctxt: the shell context
1238 * @arg: unused
1239 * @node: a node
1240 * @node2: unused
1241 *
1242 * Implements the XML shell function "dir"
1243 * dumps informations about the node (namespace, attributes, content).
1244 *
1245 * Returns 0
1246 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001247static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001248xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1249 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001250 if ((node->type == XML_DOCUMENT_NODE) ||
1251 (node->type == XML_HTML_DOCUMENT_NODE)) {
1252 xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
1253 } else if (node->type == XML_ATTRIBUTE_NODE) {
1254 xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
1255 } else {
1256 xmlDebugDumpOneNode(stdout, node, 0);
1257 }
1258 return(0);
1259}
1260
1261/**
1262 * xmlShellCat:
1263 * @ctxt: the shell context
1264 * @arg: unused
1265 * @node: a node
1266 * @node2: unused
1267 *
1268 * Implements the XML shell function "cat"
1269 * dumps the serialization node content (XML or HTML).
1270 *
1271 * Returns 0
1272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001273static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001274xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1275 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001276 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1277#ifdef LIBXML_HTML_ENABLED
1278 if (node->type == XML_HTML_DOCUMENT_NODE)
1279 htmlDocDump(stdout, (htmlDocPtr) node);
1280 else
1281 htmlNodeDumpFile(stdout, ctxt->doc, node);
1282#else
1283 if (node->type == XML_DOCUMENT_NODE)
1284 xmlDocDump(stdout, (xmlDocPtr) node);
1285 else
1286 xmlElemDump(stdout, ctxt->doc, node);
1287#endif /* LIBXML_HTML_ENABLED */
1288 } else {
1289 if (node->type == XML_DOCUMENT_NODE)
1290 xmlDocDump(stdout, (xmlDocPtr) node);
1291 else
1292 xmlElemDump(stdout, ctxt->doc, node);
1293 }
1294 printf("\n");
1295 return(0);
1296}
1297
1298/**
1299 * xmlShellLoad:
1300 * @ctxt: the shell context
1301 * @filename: the file name
1302 * @node: unused
1303 * @node2: unused
1304 *
1305 * Implements the XML shell function "load"
1306 * loads a new document specified by the filename
1307 *
1308 * Returns 0 or -1 if loading failed
1309 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001310static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001311xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node ATTRIBUTE_UNUSED,
1312 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001313 xmlDocPtr doc;
1314 int html = 0;
1315
1316 if (ctxt->doc != NULL)
1317 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
1318
1319 if (html) {
1320#ifdef LIBXML_HTML_ENABLED
1321 doc = htmlParseFile(filename, NULL);
1322#else
1323 printf("HTML support not compiled in\n");
1324 doc = NULL;
1325#endif /* LIBXML_HTML_ENABLED */
1326 } else {
1327 doc = xmlParseFile(filename);
1328 }
1329 if (doc != NULL) {
1330 if (ctxt->loaded == 1) {
1331 xmlFreeDoc(ctxt->doc);
1332 }
1333 ctxt->loaded = 1;
1334#ifdef LIBXML_XPATH_ENABLED
1335 xmlXPathFreeContext(ctxt->pctxt);
1336#endif /* LIBXML_XPATH_ENABLED */
1337 xmlFree(ctxt->filename);
1338 ctxt->doc = doc;
1339 ctxt->node = (xmlNodePtr) doc;
1340#ifdef LIBXML_XPATH_ENABLED
1341 ctxt->pctxt = xmlXPathNewContext(doc);
1342#endif /* LIBXML_XPATH_ENABLED */
1343 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1344 } else
1345 return(-1);
1346 return(0);
1347}
1348
1349/**
1350 * xmlShellWrite:
1351 * @ctxt: the shell context
1352 * @filename: the file name
1353 * @node: a node in the tree
1354 * @node2: unused
1355 *
1356 * Implements the XML shell function "write"
1357 * Write the current node to the filename, it saves the serailization
1358 * of the subtree under the @node specified
1359 *
1360 * Returns 0 or -1 in case of error
1361 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001362static int
Owen Taylor3473f882001-02-23 17:55:21 +00001363xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001364 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001365 if (node == NULL)
1366 return(-1);
1367 if ((filename == NULL) || (filename[0] == 0)) {
1368 xmlGenericError(xmlGenericErrorContext,
1369 "Write command requires a filename argument\n");
1370 return(-1);
1371 }
1372#ifdef W_OK
1373 if (access((char *) filename, W_OK)) {
1374 xmlGenericError(xmlGenericErrorContext,
1375 "Cannot write to %s\n", filename);
1376 return(-1);
1377 }
1378#endif
1379 switch(node->type) {
1380 case XML_DOCUMENT_NODE:
1381 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1382 xmlGenericError(xmlGenericErrorContext,
1383 "Failed to write to %s\n", filename);
1384 return(-1);
1385 }
1386 break;
1387 case XML_HTML_DOCUMENT_NODE:
1388#ifdef LIBXML_HTML_ENABLED
1389 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1390 xmlGenericError(xmlGenericErrorContext,
1391 "Failed to write to %s\n", filename);
1392 return(-1);
1393 }
1394#else
1395 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1396 xmlGenericError(xmlGenericErrorContext,
1397 "Failed to write to %s\n", filename);
1398 return(-1);
1399 }
1400#endif /* LIBXML_HTML_ENABLED */
1401 break;
1402 default: {
1403 FILE *f;
1404
1405 f = fopen((char *) filename, "w");
1406 if (f == NULL) {
1407 xmlGenericError(xmlGenericErrorContext,
1408 "Failed to write to %s\n", filename);
1409 return(-1);
1410 }
1411 xmlElemDump(f, ctxt->doc, node);
1412 fclose(f);
1413 }
1414 }
1415 return(0);
1416}
1417
1418/**
1419 * xmlShellSave:
1420 * @ctxt: the shell context
1421 * @filename: the file name (optionnal)
1422 * @node: unused
1423 * @node2: unused
1424 *
1425 * Implements the XML shell function "save"
1426 * Write the current document to the filename, or it's original name
1427 *
1428 * Returns 0 or -1 in case of error
1429 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001430static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001431xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node ATTRIBUTE_UNUSED,
1432 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001433 if (ctxt->doc == NULL)
1434 return(-1);
1435 if ((filename == NULL) || (filename[0] == 0))
1436 filename = ctxt->filename;
1437#ifdef W_OK
1438 if (access((char *) filename, W_OK)) {
1439 xmlGenericError(xmlGenericErrorContext,
1440 "Cannot save to %s\n", filename);
1441 return(-1);
1442 }
1443#endif
1444 switch(ctxt->doc->type) {
1445 case XML_DOCUMENT_NODE:
1446 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1447 xmlGenericError(xmlGenericErrorContext,
1448 "Failed to save to %s\n", filename);
1449 }
1450 break;
1451 case XML_HTML_DOCUMENT_NODE:
1452#ifdef LIBXML_HTML_ENABLED
1453 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1454 xmlGenericError(xmlGenericErrorContext,
1455 "Failed to save to %s\n", filename);
1456 }
1457#else
1458 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1459 xmlGenericError(xmlGenericErrorContext,
1460 "Failed to save to %s\n", filename);
1461 }
1462#endif /* LIBXML_HTML_ENABLED */
1463 break;
1464 default:
1465 xmlGenericError(xmlGenericErrorContext,
1466 "To save to subparts of a document use the 'write' command\n");
1467 return(-1);
1468
1469 }
1470 return(0);
1471}
1472
1473/**
1474 * xmlShellValidate:
1475 * @ctxt: the shell context
1476 * @dtd: the DTD URI (optionnal)
1477 * @node: unused
1478 * @node2: unused
1479 *
1480 * Implements the XML shell function "validate"
1481 * Validate the document, if a DTD path is provided, then the validation
1482 * is done against the given DTD.
1483 *
1484 * Returns 0 or -1 in case of error
1485 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001486static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001487xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node ATTRIBUTE_UNUSED,
1488 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001489 xmlValidCtxt vctxt;
1490 int res = -1;
1491
1492 vctxt.userData = stderr;
1493 vctxt.error = (xmlValidityErrorFunc) fprintf;
1494 vctxt.warning = (xmlValidityWarningFunc) fprintf;
1495
1496 if ((dtd == NULL) || (dtd[0] == 0)) {
1497 res = xmlValidateDocument(&vctxt, ctxt->doc);
1498 } else {
1499 xmlDtdPtr subset;
1500
1501 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1502 if (subset != NULL) {
1503 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1504
1505 xmlFreeDtd(subset);
1506 }
1507 }
1508 return(res);
1509}
1510
1511/**
1512 * xmlShellDu:
1513 * @ctxt: the shell context
1514 * @arg: unused
1515 * @tree: a node defining a subtree
1516 * @node2: unused
1517 *
1518 * Implements the XML shell function "du"
1519 * show the structure of the subtree under node @tree
1520 * If @tree is null, the command works on the current node.
1521 *
1522 * Returns 0 or -1 in case of error
1523 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001524static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001525xmlShellDu(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
1526 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001527 xmlNodePtr node;
1528 int indent = 0,i;
1529
1530 if (tree == NULL) return(-1);
1531 node = tree;
1532 while (node != NULL) {
1533 if ((node->type == XML_DOCUMENT_NODE) ||
1534 (node->type == XML_HTML_DOCUMENT_NODE)) {
1535 printf("/\n");
1536 } else if (node->type == XML_ELEMENT_NODE) {
1537 for (i = 0;i < indent;i++)
1538 printf(" ");
1539 printf("%s\n", node->name);
1540 } else {
1541 }
1542
1543 /*
1544 * Browse the full subtree, deep first
1545 */
1546
1547 if ((node->type == XML_DOCUMENT_NODE) ||
1548 (node->type == XML_HTML_DOCUMENT_NODE)) {
1549 node = ((xmlDocPtr) node)->children;
1550 } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1551 /* deep first */
1552 node = node->children;
1553 indent++;
1554 } else if ((node != tree) && (node->next != NULL)) {
1555 /* then siblings */
1556 node = node->next;
1557 } else if (node != tree) {
1558 /* go up to parents->next if needed */
1559 while (node != tree) {
1560 if (node->parent != NULL) {
1561 node = node->parent;
1562 indent--;
1563 }
1564 if ((node != tree) && (node->next != NULL)) {
1565 node = node->next;
1566 break;
1567 }
1568 if (node->parent == NULL) {
1569 node = NULL;
1570 break;
1571 }
1572 if (node == tree) {
1573 node = NULL;
1574 break;
1575 }
1576 }
1577 /* exit condition */
1578 if (node == tree)
1579 node = NULL;
1580 } else
1581 node = NULL;
1582 }
1583 return(0);
1584}
1585
1586/**
1587 * xmlShellPwd:
1588 * @ctxt: the shell context
1589 * @buffer: the output buffer
1590 * @tree: a node
1591 * @node2: unused
1592 *
1593 * Implements the XML shell function "pwd"
1594 * Show the full path from the root to the node, if needed building
1595 * thumblers when similar elements exists at a given ancestor level.
1596 * The output is compatible with XPath commands.
1597 *
1598 * Returns 0 or -1 in case of error
1599 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001600static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001601xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer, xmlNodePtr node,
1602 xmlNodePtr node2 ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001603 xmlNodePtr cur, tmp, next;
1604 char buf[500];
1605 char sep;
1606 const char *name;
1607 int occur = 0;
1608
1609 buffer[0] = 0;
1610 if (node == NULL) return(-1);
1611 cur = node;
1612 do {
1613 name = "";
1614 sep= '?';
1615 occur = 0;
1616 if ((cur->type == XML_DOCUMENT_NODE) ||
1617 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1618 sep = '/';
1619 next = NULL;
1620 } else if (cur->type == XML_ELEMENT_NODE) {
1621 sep = '/';
1622 name = (const char *)cur->name;
1623 next = cur->parent;
1624
1625 /*
1626 * Thumbler index computation
1627 */
1628 tmp = cur->prev;
1629 while (tmp != NULL) {
1630 if (xmlStrEqual(cur->name, tmp->name))
1631 occur++;
1632 tmp = tmp->prev;
1633 }
1634 if (occur == 0) {
1635 tmp = cur->next;
1636 while (tmp != NULL) {
1637 if (xmlStrEqual(cur->name, tmp->name))
1638 occur++;
1639 tmp = tmp->next;
1640 }
1641 if (occur != 0) occur = 1;
1642 } else
1643 occur++;
1644 } else if (cur->type == XML_ATTRIBUTE_NODE) {
1645 sep = '@';
1646 name = (const char *) (((xmlAttrPtr) cur)->name);
1647 next = ((xmlAttrPtr) cur)->parent;
1648 } else {
1649 next = cur->parent;
1650 }
1651 if (occur == 0)
Owen Taylor3473f882001-02-23 17:55:21 +00001652 snprintf(buf, sizeof(buf), "%c%s%s", sep, name, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001653 else
Owen Taylor3473f882001-02-23 17:55:21 +00001654 snprintf(buf, sizeof(buf), "%c%s[%d]%s",
1655 sep, name, occur, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001656 buf[sizeof(buf) - 1] = 0;
1657 /*
1658 * This test prevents buffer overflow, because this routine
1659 * is only called by xmlShell, in which the second argument is
1660 * 500 chars long.
1661 * It is a dirty hack before a cleaner solution is found.
1662 * Documentation should mention that the second argument must
1663 * be at least 500 chars long, and could be stripped if too long.
1664 */
1665 if (strlen(buffer) + strlen(buf) > 499)
1666 break;
1667 strcpy(buffer, buf);
1668 cur = next;
1669 } while (cur != NULL);
1670 return(0);
1671}
1672
1673/**
1674 * xmlShell
1675 * @doc: the initial document
1676 * @filename: the output buffer
1677 * @input: the line reading function
1678 * @output: the output FILE*
1679 *
1680 * Implements the XML shell
1681 * This allow to load, validate, view, modify and save a document
1682 * using a environment similar to a UNIX commandline.
1683 */
1684void
1685xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1686 FILE *output) {
1687 char prompt[500] = "/ > ";
1688 char *cmdline = NULL, *cur;
1689 int nbargs;
1690 char command[100];
1691 char arg[400];
1692 int i;
1693 xmlShellCtxtPtr ctxt;
1694 xmlXPathObjectPtr list;
1695
1696 if (doc == NULL)
1697 return;
1698 if (filename == NULL)
1699 return;
1700 if (input == NULL)
1701 return;
1702 if (output == NULL)
1703 return;
1704 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1705 if (ctxt == NULL)
1706 return;
1707 ctxt->loaded = 0;
1708 ctxt->doc = doc;
1709 ctxt->input = input;
1710 ctxt->output = output;
1711 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1712 ctxt->node = (xmlNodePtr) ctxt->doc;
1713
1714#ifdef LIBXML_XPATH_ENABLED
1715 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1716 if (ctxt->pctxt == NULL) {
1717 xmlFree(ctxt);
1718 return;
1719 }
1720#endif /* LIBXML_XPATH_ENABLED */
1721 while (1) {
1722 if (ctxt->node == (xmlNodePtr) ctxt->doc)
1723 sprintf(prompt, "%s > ", "/");
1724 else if (ctxt->node->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001725 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001726 else
1727 sprintf(prompt, "? > ");
1728 prompt[sizeof(prompt) - 1] = 0;
1729
1730 /*
1731 * Get a new command line
1732 */
1733 cmdline = ctxt->input(prompt);
1734 if (cmdline == NULL) break;
1735
1736 /*
1737 * Parse the command itself
1738 */
1739 cur = cmdline;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001740 nbargs = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001741 while ((*cur == ' ') || (*cur == '\t')) cur++;
1742 i = 0;
1743 while ((*cur != ' ') && (*cur != '\t') &&
1744 (*cur != '\n') && (*cur != '\r')) {
1745 if (*cur == 0)
1746 break;
1747 command[i++] = *cur++;
1748 }
1749 command[i] = 0;
1750 if (i == 0) continue;
1751 nbargs++;
1752
1753 /*
1754 * Parse the argument
1755 */
1756 while ((*cur == ' ') || (*cur == '\t')) cur++;
1757 i = 0;
1758 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
1759 if (*cur == 0)
1760 break;
1761 arg[i++] = *cur++;
1762 }
1763 arg[i] = 0;
1764 if (i != 0)
1765 nbargs++;
1766
1767 /*
1768 * start interpreting the command
1769 */
1770 if (!strcmp(command, "exit"))
1771 break;
1772 if (!strcmp(command, "quit"))
1773 break;
1774 if (!strcmp(command, "bye"))
1775 break;
1776 if (!strcmp(command, "validate")) {
1777 xmlShellValidate(ctxt, arg, NULL, NULL);
1778 } else if (!strcmp(command, "load")) {
1779 xmlShellLoad(ctxt, arg, NULL, NULL);
1780 } else if (!strcmp(command, "save")) {
1781 xmlShellSave(ctxt, arg, NULL, NULL);
1782 } else if (!strcmp(command, "write")) {
1783 xmlShellWrite(ctxt, arg, NULL, NULL);
1784 } else if (!strcmp(command, "free")) {
1785 if (arg[0] == 0) {
1786 xmlMemShow(stdout, 0);
1787 } else {
1788 int len = 0;
1789 sscanf(arg, "%d", &len);
1790 xmlMemShow(stdout, len);
1791 }
1792 } else if (!strcmp(command, "pwd")) {
1793 char dir[500];
1794 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
1795 printf("%s\n", dir);
1796 } else if (!strcmp(command, "du")) {
1797 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001798 } else if (!strcmp(command, "base")) {
1799 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001800 } else if ((!strcmp(command, "ls")) ||
1801 (!strcmp(command, "dir"))) {
1802 int dir = (!strcmp(command, "dir"));
1803 if (arg[0] == 0) {
1804 if (dir)
1805 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
1806 else
1807 xmlShellList(ctxt, NULL, ctxt->node, NULL);
1808 } else {
1809 ctxt->pctxt->node = ctxt->node;
1810#ifdef LIBXML_XPATH_ENABLED
1811 ctxt->pctxt->node = ctxt->node;
1812 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1813#else
1814 list = NULL;
1815#endif /* LIBXML_XPATH_ENABLED */
1816 if (list != NULL) {
1817 switch (list->type) {
1818 case XPATH_UNDEFINED:
1819 xmlGenericError(xmlGenericErrorContext,
1820 "%s: no such node\n", arg);
1821 break;
1822 case XPATH_NODESET: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001823 int indx;
Owen Taylor3473f882001-02-23 17:55:21 +00001824
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001825 for (indx = 0;indx < list->nodesetval->nodeNr;
1826 indx++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001827 if (dir)
1828 xmlShellDir(ctxt, NULL,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001829 list->nodesetval->nodeTab[indx], NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001830 else
1831 xmlShellList(ctxt, NULL,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001832 list->nodesetval->nodeTab[indx], NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001833 }
1834 break;
1835 }
1836 case XPATH_BOOLEAN:
1837 xmlGenericError(xmlGenericErrorContext,
1838 "%s is a Boolean\n", arg);
1839 break;
1840 case XPATH_NUMBER:
1841 xmlGenericError(xmlGenericErrorContext,
1842 "%s is a number\n", arg);
1843 break;
1844 case XPATH_STRING:
1845 xmlGenericError(xmlGenericErrorContext,
1846 "%s is a string\n", arg);
1847 break;
1848 case XPATH_POINT:
1849 xmlGenericError(xmlGenericErrorContext,
1850 "%s is a point\n", arg);
1851 break;
1852 case XPATH_RANGE:
1853 xmlGenericError(xmlGenericErrorContext,
1854 "%s is a range\n", arg);
1855 break;
1856 case XPATH_LOCATIONSET:
1857 xmlGenericError(xmlGenericErrorContext,
1858 "%s is a range\n", arg);
1859 break;
1860 case XPATH_USERS:
1861 xmlGenericError(xmlGenericErrorContext,
1862 "%s is user-defined\n", arg);
1863 break;
1864 case XPATH_XSLT_TREE:
1865 xmlGenericError(xmlGenericErrorContext,
1866 "%s is an XSLT value tree\n", arg);
1867 break;
1868 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00001869#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001870 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00001871#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001872 } else {
1873 xmlGenericError(xmlGenericErrorContext,
1874 "%s: no such node\n", arg);
1875 }
1876 ctxt->pctxt->node = NULL;
1877 }
1878 } else if (!strcmp(command, "cd")) {
1879 if (arg[0] == 0) {
1880 ctxt->node = (xmlNodePtr) ctxt->doc;
1881 } else {
1882#ifdef LIBXML_XPATH_ENABLED
1883 ctxt->pctxt->node = ctxt->node;
1884 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1885#else
1886 list = NULL;
1887#endif /* LIBXML_XPATH_ENABLED */
1888 if (list != NULL) {
1889 switch (list->type) {
1890 case XPATH_UNDEFINED:
1891 xmlGenericError(xmlGenericErrorContext,
1892 "%s: no such node\n", arg);
1893 break;
1894 case XPATH_NODESET:
1895 if (list->nodesetval->nodeNr == 1) {
1896 ctxt->node = list->nodesetval->nodeTab[0];
1897 } else
1898 xmlGenericError(xmlGenericErrorContext,
1899 "%s is a %d Node Set\n",
1900 arg, list->nodesetval->nodeNr);
1901 break;
1902 case XPATH_BOOLEAN:
1903 xmlGenericError(xmlGenericErrorContext,
1904 "%s is a Boolean\n", arg);
1905 break;
1906 case XPATH_NUMBER:
1907 xmlGenericError(xmlGenericErrorContext,
1908 "%s is a number\n", arg);
1909 break;
1910 case XPATH_STRING:
1911 xmlGenericError(xmlGenericErrorContext,
1912 "%s is a string\n", arg);
1913 break;
1914 case XPATH_POINT:
1915 xmlGenericError(xmlGenericErrorContext,
1916 "%s is a point\n", arg);
1917 break;
1918 case XPATH_RANGE:
1919 xmlGenericError(xmlGenericErrorContext,
1920 "%s is a range\n", arg);
1921 break;
1922 case XPATH_LOCATIONSET:
1923 xmlGenericError(xmlGenericErrorContext,
1924 "%s is a range\n", arg);
1925 break;
1926 case XPATH_USERS:
1927 xmlGenericError(xmlGenericErrorContext,
1928 "%s is user-defined\n", arg);
1929 break;
1930 case XPATH_XSLT_TREE:
1931 xmlGenericError(xmlGenericErrorContext,
1932 "%s is an XSLT value tree\n", arg);
1933 break;
1934 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00001935#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001936 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00001937#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001938 } else {
1939 xmlGenericError(xmlGenericErrorContext,
1940 "%s: no such node\n", arg);
1941 }
1942 ctxt->pctxt->node = NULL;
1943 }
1944 } else if (!strcmp(command, "cat")) {
1945 if (arg[0] == 0) {
1946 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
1947 } else {
1948 ctxt->pctxt->node = ctxt->node;
1949#ifdef LIBXML_XPATH_ENABLED
1950 ctxt->pctxt->node = ctxt->node;
1951 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1952#else
1953 list = NULL;
1954#endif /* LIBXML_XPATH_ENABLED */
1955 if (list != NULL) {
1956 switch (list->type) {
1957 case XPATH_UNDEFINED:
1958 xmlGenericError(xmlGenericErrorContext,
1959 "%s: no such node\n", arg);
1960 break;
1961 case XPATH_NODESET: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001962 int indx;
Owen Taylor3473f882001-02-23 17:55:21 +00001963
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001964 for (indx = 0;indx < list->nodesetval->nodeNr;
1965 indx++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001966 if (i > 0) printf(" -------\n");
1967 xmlShellCat(ctxt, NULL,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001968 list->nodesetval->nodeTab[indx], NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001969 }
1970 break;
1971 }
1972 case XPATH_BOOLEAN:
1973 xmlGenericError(xmlGenericErrorContext,
1974 "%s is a Boolean\n", arg);
1975 break;
1976 case XPATH_NUMBER:
1977 xmlGenericError(xmlGenericErrorContext,
1978 "%s is a number\n", arg);
1979 break;
1980 case XPATH_STRING:
1981 xmlGenericError(xmlGenericErrorContext,
1982 "%s is a string\n", arg);
1983 break;
1984 case XPATH_POINT:
1985 xmlGenericError(xmlGenericErrorContext,
1986 "%s is a point\n", arg);
1987 break;
1988 case XPATH_RANGE:
1989 xmlGenericError(xmlGenericErrorContext,
1990 "%s is a range\n", arg);
1991 break;
1992 case XPATH_LOCATIONSET:
1993 xmlGenericError(xmlGenericErrorContext,
1994 "%s is a range\n", arg);
1995 break;
1996 case XPATH_USERS:
1997 xmlGenericError(xmlGenericErrorContext,
1998 "%s is user-defined\n", arg);
1999 break;
2000 case XPATH_XSLT_TREE:
2001 xmlGenericError(xmlGenericErrorContext,
2002 "%s is an XSLT value tree\n", arg);
2003 break;
2004 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00002005#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002006 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00002007#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002008 } else {
2009 xmlGenericError(xmlGenericErrorContext,
2010 "%s: no such node\n", arg);
2011 }
2012 ctxt->pctxt->node = NULL;
2013 }
2014 } else {
2015 xmlGenericError(xmlGenericErrorContext,
2016 "Unknown command %s\n", command);
2017 }
2018 free(cmdline); /* not xmlFree here ! */
2019 }
2020#ifdef LIBXML_XPATH_ENABLED
2021 xmlXPathFreeContext(ctxt->pctxt);
2022#endif /* LIBXML_XPATH_ENABLED */
2023 if (ctxt->loaded) {
2024 xmlFreeDoc(ctxt->doc);
2025 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002026 if (ctxt->filename != NULL)
2027 xmlFree(ctxt->filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002028 xmlFree(ctxt);
2029 if (cmdline != NULL)
2030 free(cmdline); /* not xmlFree here ! */
2031}
2032
2033#endif /* LIBXML_DEBUG_ENABLED */