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