blob: 19804414933b4b55ad3e794be209ce4d5a5eb5f2 [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
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012#ifdef LIBXML_DEBUG_ENABLED
13
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18#ifdef HAVE_STRING_H
19#include <string.h>
20#endif
21#include <libxml/xmlmemory.h>
22#include <libxml/tree.h>
23#include <libxml/parser.h>
Daniel Veillard567e1b42001-08-01 15:53:47 +000024#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000025#include <libxml/valid.h>
26#include <libxml/debugXML.h>
27#include <libxml/HTMLtree.h>
28#include <libxml/HTMLparser.h>
29#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000030#include <libxml/globals.h>
Daniel Veillard0ba59232002-02-10 13:20:39 +000031#include <libxml/xpathInternals.h>
Igor Zlatkovicc06bb622003-04-27 15:59:00 +000032#include <libxml/uri.h>
Daniel Veillard522bc602004-02-21 11:53:09 +000033#ifdef LIBXML_SCHEMAS_ENABLED
34#include <libxml/relaxng.h>
35#endif
Owen Taylor3473f882001-02-23 17:55:21 +000036
Daniel Veillard22cdb842004-10-04 14:09:17 +000037typedef struct _xmlDebugCtxt xmlDebugCtxt;
38typedef xmlDebugCtxt *xmlDebugCtxtPtr;
39struct _xmlDebugCtxt {
40 FILE *output; /* the output file */
41 char shift[101]; /* used for indenting */
42 int depth; /* current depth */
43 xmlDocPtr doc; /* current document */
44 int check; /* do just checkings */
45};
46
47static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
48
49static void
50xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
51{
52 int i;
53
54 ctxt->depth = 0;
55 ctxt->check = 0;
56 ctxt->output = stdout;
57 for (i = 0; i < 100; i++)
58 ctxt->shift[i] = ' ';
59 ctxt->shift[100] = 0;
60}
61
62static void
63xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
64{
65 if (ctxt->check)
66 return;
67 if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
68 if (ctxt->depth < 50)
69 fprintf(ctxt->output, &ctxt->shift[100 - 2 * ctxt->depth]);
70 else
71 fprintf(ctxt->output, ctxt->shift);
72 }
73}
74
75static void
76xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
77{
78 int i;
79
80 if (ctxt->check)
81 return;
82 /* TODO: check UTF8 content of the string */
83 if (str == NULL) {
84 fprintf(ctxt->output, "(NULL)");
85 return;
86 }
87 for (i = 0; i < 40; i++)
88 if (str[i] == 0)
89 return;
90 else if (IS_BLANK_CH(str[i]))
91 fputc(' ', ctxt->output);
92 else if (str[i] >= 0x80)
93 fprintf(ctxt->output, "#%X", str[i]);
94 else
95 fputc(str[i], ctxt->output);
96 fprintf(ctxt->output, "...");
97}
98
99static void
100xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
101{
102 xmlCtxtDumpSpaces(ctxt);
103
104 if (dtd == NULL) {
105 if (!ctxt->check)
106 fprintf(ctxt->output, "DTD node is NULL\n");
107 return;
108 }
109
110 if (dtd->type != XML_DTD_NODE) {
111 fprintf(ctxt->output, "PBM: not a DTD\n");
112 return;
113 }
114 if (!ctxt->check) {
115 if (dtd->name != NULL)
116 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
117 else
118 fprintf(ctxt->output, "DTD");
119 if (dtd->ExternalID != NULL)
120 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
121 if (dtd->SystemID != NULL)
122 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
123 fprintf(ctxt->output, "\n");
124 }
125 /*
126 * Do a bit of checking
127 */
128 if (dtd->parent == NULL)
129 fprintf(ctxt->output, "PBM: DTD has no parent\n");
130 if (dtd->doc == NULL)
131 fprintf(ctxt->output, "PBM: DTD has no doc\n");
132 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
133 fprintf(ctxt->output, "PBM: DTD doc differs from parent's one\n");
134 if (dtd->prev == NULL) {
135 if ((dtd->parent != NULL)
136 && (dtd->parent->children != (xmlNodePtr) dtd))
137 fprintf(ctxt->output,
138 "PBM: DTD has no prev and not first of list\n");
139 } else {
140 if (dtd->prev->next != (xmlNodePtr) dtd)
141 fprintf(ctxt->output,
142 "PBM: DTD prev->next : back link wrong\n");
143 }
144 if (dtd->next == NULL) {
145 if ((dtd->parent != NULL)
146 && (dtd->parent->last != (xmlNodePtr) dtd))
147 fprintf(ctxt->output,
148 "PBM: DTD has no next and not last of list\n");
149 } else {
150 if (dtd->next->prev != (xmlNodePtr) dtd)
151 fprintf(ctxt->output,
152 "PBM: DTD next->prev : forward link wrong\n");
153 }
154}
155
156static void
157xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
158{
159 xmlCtxtDumpSpaces(ctxt);
160
161 if (attr == NULL) {
162 if (!ctxt->check)
163 fprintf(ctxt->output, "Attribute declaration is NULL\n");
164 return;
165 }
166 if (attr->type != XML_ATTRIBUTE_DECL) {
167 fprintf(ctxt->output, "PBM: not a Attr\n");
168 return;
169 }
170 if (attr->name != NULL) {
171 if (!ctxt->check)
172 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
173 } else
174 fprintf(ctxt->output, "PBM ATTRDECL noname!!!");
175 if (attr->elem != NULL) {
176 if (!ctxt->check)
177 fprintf(ctxt->output, " for %s", (char *) attr->elem);
178 } else
179 fprintf(ctxt->output, " PBM noelem!!!");
180 if (!ctxt->check) {
181 switch (attr->atype) {
182 case XML_ATTRIBUTE_CDATA:
183 fprintf(ctxt->output, " CDATA");
184 break;
185 case XML_ATTRIBUTE_ID:
186 fprintf(ctxt->output, " ID");
187 break;
188 case XML_ATTRIBUTE_IDREF:
189 fprintf(ctxt->output, " IDREF");
190 break;
191 case XML_ATTRIBUTE_IDREFS:
192 fprintf(ctxt->output, " IDREFS");
193 break;
194 case XML_ATTRIBUTE_ENTITY:
195 fprintf(ctxt->output, " ENTITY");
196 break;
197 case XML_ATTRIBUTE_ENTITIES:
198 fprintf(ctxt->output, " ENTITIES");
199 break;
200 case XML_ATTRIBUTE_NMTOKEN:
201 fprintf(ctxt->output, " NMTOKEN");
202 break;
203 case XML_ATTRIBUTE_NMTOKENS:
204 fprintf(ctxt->output, " NMTOKENS");
205 break;
206 case XML_ATTRIBUTE_ENUMERATION:
207 fprintf(ctxt->output, " ENUMERATION");
208 break;
209 case XML_ATTRIBUTE_NOTATION:
210 fprintf(ctxt->output, " NOTATION ");
211 break;
212 }
213 if (attr->tree != NULL) {
214 int indx;
215 xmlEnumerationPtr cur = attr->tree;
216
217 for (indx = 0; indx < 5; indx++) {
218 if (indx != 0)
219 fprintf(ctxt->output, "|%s", (char *) cur->name);
220 else
221 fprintf(ctxt->output, " (%s", (char *) cur->name);
222 cur = cur->next;
223 if (cur == NULL)
224 break;
225 }
226 if (cur == NULL)
227 fprintf(ctxt->output, ")");
228 else
229 fprintf(ctxt->output, "...)");
230 }
231 switch (attr->def) {
232 case XML_ATTRIBUTE_NONE:
233 break;
234 case XML_ATTRIBUTE_REQUIRED:
235 fprintf(ctxt->output, " REQUIRED");
236 break;
237 case XML_ATTRIBUTE_IMPLIED:
238 fprintf(ctxt->output, " IMPLIED");
239 break;
240 case XML_ATTRIBUTE_FIXED:
241 fprintf(ctxt->output, " FIXED");
242 break;
243 }
244 if (attr->defaultValue != NULL) {
245 fprintf(ctxt->output, "\"");
246 xmlCtxtDumpString(ctxt, attr->defaultValue);
247 fprintf(ctxt->output, "\"");
248 }
249 fprintf(ctxt->output, "\n");
250 }
251
252 /*
253 * Do a bit of checking
254 */
255 if (attr->parent == NULL)
256 fprintf(ctxt->output, "PBM: Attr has no parent\n");
257 if (attr->doc == NULL)
258 fprintf(ctxt->output, "PBM: Attr has no doc\n");
259 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
260 fprintf(ctxt->output, "PBM: Attr doc differs from parent's one\n");
261 if (attr->prev == NULL) {
262 if ((attr->parent != NULL)
263 && (attr->parent->children != (xmlNodePtr) attr))
264 fprintf(ctxt->output,
265 "PBM: Attr has no prev and not first of list\n");
266 } else {
267 if (attr->prev->next != (xmlNodePtr) attr)
268 fprintf(ctxt->output,
269 "PBM: Attr prev->next : back link wrong\n");
270 }
271 if (attr->next == NULL) {
272 if ((attr->parent != NULL)
273 && (attr->parent->last != (xmlNodePtr) attr))
274 fprintf(ctxt->output,
275 "PBM: Attr has no next and not last of list\n");
276 } else {
277 if (attr->next->prev != (xmlNodePtr) attr)
278 fprintf(ctxt->output,
279 "PBM: Attr next->prev : forward link wrong\n");
280 }
281}
282
283static void
284xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
285{
286 xmlCtxtDumpSpaces(ctxt);
287
288 if (elem == NULL) {
289 if (!ctxt->check)
290 fprintf(ctxt->output, "Element declaration is NULL\n");
291 return;
292 }
293 if (elem->type != XML_ELEMENT_DECL) {
294 fprintf(ctxt->output, "PBM: not a Elem\n");
295 return;
296 }
297 if (elem->name != NULL) {
298 if (!ctxt->check) {
299 fprintf(ctxt->output, "ELEMDECL(");
300 xmlCtxtDumpString(ctxt, elem->name);
301 fprintf(ctxt->output, ")");
302 }
303 } else
304 fprintf(ctxt->output, "PBM ELEMDECL noname!!!");
305 if (!ctxt->check) {
306 switch (elem->etype) {
307 case XML_ELEMENT_TYPE_UNDEFINED:
308 fprintf(ctxt->output, ", UNDEFINED");
309 break;
310 case XML_ELEMENT_TYPE_EMPTY:
311 fprintf(ctxt->output, ", EMPTY");
312 break;
313 case XML_ELEMENT_TYPE_ANY:
314 fprintf(ctxt->output, ", ANY");
315 break;
316 case XML_ELEMENT_TYPE_MIXED:
317 fprintf(ctxt->output, ", MIXED ");
318 break;
319 case XML_ELEMENT_TYPE_ELEMENT:
320 fprintf(ctxt->output, ", MIXED ");
321 break;
322 }
323 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
324 char buf[5001];
325
326 buf[0] = 0;
327 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
328 buf[5000] = 0;
329 fprintf(ctxt->output, "%s", buf);
330 }
331 fprintf(ctxt->output, "\n");
332 }
333
334 /*
335 * Do a bit of checking
336 */
337 if (elem->parent == NULL)
338 fprintf(ctxt->output, "PBM: Elem has no parent\n");
339 if (elem->doc == NULL)
340 fprintf(ctxt->output, "PBM: Elem has no doc\n");
341 if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
342 fprintf(ctxt->output, "PBM: Elem doc differs from parent's one\n");
343 if (elem->prev == NULL) {
344 if ((elem->parent != NULL)
345 && (elem->parent->children != (xmlNodePtr) elem))
346 fprintf(ctxt->output,
347 "PBM: Elem has no prev and not first of list\n");
348 } else {
349 if (elem->prev->next != (xmlNodePtr) elem)
350 fprintf(ctxt->output,
351 "PBM: Elem prev->next : back link wrong\n");
352 }
353 if (elem->next == NULL) {
354 if ((elem->parent != NULL)
355 && (elem->parent->last != (xmlNodePtr) elem))
356 fprintf(ctxt->output,
357 "PBM: Elem has no next and not last of list\n");
358 } else {
359 if (elem->next->prev != (xmlNodePtr) elem)
360 fprintf(ctxt->output,
361 "PBM: Elem next->prev : forward link wrong\n");
362 }
363}
364
365static void
366xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
367{
368 xmlCtxtDumpSpaces(ctxt);
369
370 if (ent == NULL) {
371 if (!ctxt->check)
372 fprintf(ctxt->output, "Entity declaration is NULL\n");
373 return;
374 }
375 if (ent->type != XML_ENTITY_DECL) {
376 fprintf(ctxt->output, "PBM: not a Entity decl\n");
377 return;
378 }
379 if (ent->name != NULL) {
380 if (!ctxt->check) {
381 fprintf(ctxt->output, "ENTITYDECL(");
382 xmlCtxtDumpString(ctxt, ent->name);
383 fprintf(ctxt->output, ")");
384 }
385 } else
386 fprintf(ctxt->output, "PBM ENTITYDECL noname!!!");
387 if (!ctxt->check) {
388 switch (ent->etype) {
389 case XML_INTERNAL_GENERAL_ENTITY:
390 fprintf(ctxt->output, ", internal\n");
391 break;
392 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
393 fprintf(ctxt->output, ", external parsed\n");
394 break;
395 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
396 fprintf(ctxt->output, ", unparsed\n");
397 break;
398 case XML_INTERNAL_PARAMETER_ENTITY:
399 fprintf(ctxt->output, ", parameter\n");
400 break;
401 case XML_EXTERNAL_PARAMETER_ENTITY:
402 fprintf(ctxt->output, ", external parameter\n");
403 break;
404 case XML_INTERNAL_PREDEFINED_ENTITY:
405 fprintf(ctxt->output, ", predefined\n");
406 break;
407 }
408 if (ent->ExternalID) {
409 xmlCtxtDumpSpaces(ctxt);
410 fprintf(ctxt->output, " ExternalID=%s\n",
411 (char *) ent->ExternalID);
412 }
413 if (ent->SystemID) {
414 xmlCtxtDumpSpaces(ctxt);
415 fprintf(ctxt->output, " SystemID=%s\n",
416 (char *) ent->SystemID);
417 }
418 if (ent->URI != NULL) {
419 xmlCtxtDumpSpaces(ctxt);
420 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
421 }
422 if (ent->content) {
423 xmlCtxtDumpSpaces(ctxt);
424 fprintf(ctxt->output, " content=");
425 xmlCtxtDumpString(ctxt, ent->content);
426 fprintf(ctxt->output, "\n");
427 }
428 }
429
430 /*
431 * Do a bit of checking
432 */
433 if (ent->parent == NULL)
434 fprintf(ctxt->output, "PBM: Ent has no parent\n");
435 if (ent->doc == NULL)
436 fprintf(ctxt->output, "PBM: Ent has no doc\n");
437 if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
438 fprintf(ctxt->output, "PBM: Ent doc differs from parent's one\n");
439 if (ent->prev == NULL) {
440 if ((ent->parent != NULL)
441 && (ent->parent->children != (xmlNodePtr) ent))
442 fprintf(ctxt->output,
443 "PBM: Ent has no prev and not first of list\n");
444 } else {
445 if (ent->prev->next != (xmlNodePtr) ent)
446 fprintf(ctxt->output,
447 "PBM: Ent prev->next : back link wrong\n");
448 }
449 if (ent->next == NULL) {
450 if ((ent->parent != NULL)
451 && (ent->parent->last != (xmlNodePtr) ent))
452 fprintf(ctxt->output,
453 "PBM: Ent has no next and not last of list\n");
454 } else {
455 if (ent->next->prev != (xmlNodePtr) ent)
456 fprintf(ctxt->output,
457 "PBM: Ent next->prev : forward link wrong\n");
458 }
459}
460
461static void
462xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
463{
464 xmlCtxtDumpSpaces(ctxt);
465
466 if (ns == NULL) {
467 if (!ctxt->check)
468 fprintf(ctxt->output, "namespace node is NULL\n");
469 return;
470 }
471 if (ns->type != XML_NAMESPACE_DECL) {
472 fprintf(ctxt->output, "invalid namespace type %d\n", ns->type);
473 return;
474 }
475 if (ns->href == NULL) {
476 if (ns->prefix != NULL)
477 fprintf(ctxt->output,
478 "PBM: incomplete namespace %s href=NULL\n",
479 (char *) ns->prefix);
480 else
481 fprintf(ctxt->output,
482 "PBM: incomplete default namespace href=NULL\n");
483 } else {
484 if (!ctxt->check) {
485 if (ns->prefix != NULL)
486 fprintf(ctxt->output, "namespace %s href=",
487 (char *) ns->prefix);
488 else
489 fprintf(ctxt->output, "default namespace href=");
490
491 xmlCtxtDumpString(ctxt, ns->href);
492 fprintf(ctxt->output, "\n");
493 }
494 }
495}
496
497static void
498xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
499{
500 while (ns != NULL) {
501 xmlCtxtDumpNamespace(ctxt, ns);
502 ns = ns->next;
503 }
504}
505
506static void
507xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
508{
509 xmlCtxtDumpSpaces(ctxt);
510
511 if (ent == NULL) {
512 if (!ctxt->check)
513 fprintf(ctxt->output, "Entity is NULL\n");
514 return;
515 }
516 if (!ctxt->check) {
517 switch (ent->etype) {
518 case XML_INTERNAL_GENERAL_ENTITY:
519 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
520 break;
521 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
522 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
523 break;
524 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
525 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
526 break;
527 case XML_INTERNAL_PARAMETER_ENTITY:
528 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
529 break;
530 case XML_EXTERNAL_PARAMETER_ENTITY:
531 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
532 break;
533 default:
534 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
535 }
536 fprintf(ctxt->output, "%s\n", ent->name);
537 if (ent->ExternalID) {
538 xmlCtxtDumpSpaces(ctxt);
539 fprintf(ctxt->output, "ExternalID=%s\n",
540 (char *) ent->ExternalID);
541 }
542 if (ent->SystemID) {
543 xmlCtxtDumpSpaces(ctxt);
544 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
545 }
546 if (ent->URI) {
547 xmlCtxtDumpSpaces(ctxt);
548 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
549 }
550 if (ent->content) {
551 xmlCtxtDumpSpaces(ctxt);
552 fprintf(ctxt->output, "content=");
553 xmlCtxtDumpString(ctxt, ent->content);
554 fprintf(ctxt->output, "\n");
555 }
556 }
557}
558
559/**
560 * xmlCtxtDumpAttr:
561 * @output: the FILE * for the output
562 * @attr: the attribute
563 * @depth: the indentation level.
564 *
565 * Dumps debug information for the attribute
566 */
567static void
568xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
569{
570 xmlCtxtDumpSpaces(ctxt);
571
572 if (attr == NULL) {
573 if (!ctxt->check)
574 fprintf(ctxt->output, "Attr is NULL");
575 return;
576 }
577 if (!ctxt->check) {
578 fprintf(ctxt->output, "ATTRIBUTE ");
579 xmlCtxtDumpString(ctxt, attr->name);
580 fprintf(ctxt->output, "\n");
581 if (attr->children != NULL) {
582 ctxt->depth++;
583 xmlCtxtDumpNodeList(ctxt, attr->children);
584 ctxt->depth--;
585 }
586 }
587
588 /*
589 * Do a bit of checking
590 */
591 if (attr->parent == NULL)
592 fprintf(ctxt->output, "PBM: Attr has no parent\n");
593 if (attr->doc == NULL)
594 fprintf(ctxt->output, "PBM: Attr has no doc\n");
595 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
596 fprintf(ctxt->output, "PBM: Attr doc differs from parent's one\n");
597 if (attr->prev == NULL) {
598 if ((attr->parent != NULL) && (attr->parent->properties != attr))
599 fprintf(ctxt->output,
600 "PBM: Attr has no prev and not first of list\n");
601 } else {
602 if (attr->prev->next != attr)
603 fprintf(ctxt->output,
604 "PBM: Attr prev->next : back link wrong\n");
605 }
606 if (attr->next != NULL) {
607 if (attr->next->prev != attr)
608 fprintf(ctxt->output,
609 "PBM: Attr next->prev : forward link wrong\n");
610 }
611}
612
613/**
614 * xmlCtxtDumpAttrList:
615 * @output: the FILE * for the output
616 * @attr: the attribute list
617 * @depth: the indentation level.
618 *
619 * Dumps debug information for the attribute list
620 */
621static void
622xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
623{
624 while (attr != NULL) {
625 xmlCtxtDumpAttr(ctxt, attr);
626 attr = attr->next;
627 }
628}
629
630/**
631 * xmlCtxtDumpOneNode:
632 * @output: the FILE * for the output
633 * @node: the node
634 * @depth: the indentation level.
635 *
636 * Dumps debug information for the element node, it is not recursive
637 */
638static void
639xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
640{
641 if (node == NULL) {
642 if (!ctxt->check) {
643 xmlCtxtDumpSpaces(ctxt);
644 fprintf(ctxt->output, "node is NULL\n");
645 }
646 return;
647 }
648 switch (node->type) {
649 case XML_ELEMENT_NODE:
650 if (!ctxt->check) {
651 xmlCtxtDumpSpaces(ctxt);
652 fprintf(ctxt->output, "ELEMENT ");
653 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
654 xmlCtxtDumpString(ctxt, node->ns->prefix);
655 fprintf(ctxt->output, ":");
656 }
657 xmlCtxtDumpString(ctxt, node->name);
658 fprintf(ctxt->output, "\n");
659 }
660 break;
661 case XML_ATTRIBUTE_NODE:
662 if (!ctxt->check)
663 xmlCtxtDumpSpaces(ctxt);
664 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
665 break;
666 case XML_TEXT_NODE:
667 if (!ctxt->check) {
668 xmlCtxtDumpSpaces(ctxt);
669 if (node->name == (const xmlChar *) xmlStringTextNoenc)
670 fprintf(ctxt->output, "TEXT no enc\n");
671 else
672 fprintf(ctxt->output, "TEXT\n");
673 }
674 break;
675 case XML_CDATA_SECTION_NODE:
676 if (!ctxt->check) {
677 xmlCtxtDumpSpaces(ctxt);
678 fprintf(ctxt->output, "CDATA_SECTION\n");
679 }
680 break;
681 case XML_ENTITY_REF_NODE:
682 if (!ctxt->check) {
683 xmlCtxtDumpSpaces(ctxt);
684 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
685 (char *) node->name);
686 }
687 break;
688 case XML_ENTITY_NODE:
689 if (!ctxt->check) {
690 xmlCtxtDumpSpaces(ctxt);
691 fprintf(ctxt->output, "ENTITY\n");
692 }
693 break;
694 case XML_PI_NODE:
695 if (!ctxt->check) {
696 xmlCtxtDumpSpaces(ctxt);
697 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
698 }
699 break;
700 case XML_COMMENT_NODE:
701 if (!ctxt->check) {
702 xmlCtxtDumpSpaces(ctxt);
703 fprintf(ctxt->output, "COMMENT\n");
704 }
705 break;
706 case XML_DOCUMENT_NODE:
707 case XML_HTML_DOCUMENT_NODE:
708 if (!ctxt->check) {
709 xmlCtxtDumpSpaces(ctxt);
710 }
711 fprintf(ctxt->output, "PBM: DOCUMENT found here\n");
712 break;
713 case XML_DOCUMENT_TYPE_NODE:
714 if (!ctxt->check) {
715 xmlCtxtDumpSpaces(ctxt);
716 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
717 }
718 break;
719 case XML_DOCUMENT_FRAG_NODE:
720 if (!ctxt->check) {
721 xmlCtxtDumpSpaces(ctxt);
722 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
723 }
724 break;
725 case XML_NOTATION_NODE:
726 if (!ctxt->check) {
727 xmlCtxtDumpSpaces(ctxt);
728 fprintf(ctxt->output, "NOTATION\n");
729 }
730 break;
731 case XML_DTD_NODE:
732 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
733 return;
734 case XML_ELEMENT_DECL:
735 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
736 return;
737 case XML_ATTRIBUTE_DECL:
738 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
739 return;
740 case XML_ENTITY_DECL:
741 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
742 return;
743 case XML_NAMESPACE_DECL:
744 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
745 return;
746 case XML_XINCLUDE_START:
747 if (!ctxt->check) {
748 xmlCtxtDumpSpaces(ctxt);
749 fprintf(ctxt->output, "INCLUDE START\n");
750 }
751 return;
752 case XML_XINCLUDE_END:
753 if (!ctxt->check) {
754 xmlCtxtDumpSpaces(ctxt);
755 fprintf(ctxt->output, "INCLUDE END\n");
756 }
757 return;
758 default:
759 if (!ctxt->check)
760 xmlCtxtDumpSpaces(ctxt);
761 fprintf(ctxt->output, "PBM: NODE_%d !!!\n", node->type);
762 return;
763 }
764 if (node->doc == NULL) {
765 if (!ctxt->check) {
766 xmlCtxtDumpSpaces(ctxt);
767 }
768 fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
769 }
770 ctxt->depth++;
771 if (node->nsDef != NULL)
772 xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
773 if (node->properties != NULL)
774 xmlCtxtDumpAttrList(ctxt, node->properties);
775 if (node->type != XML_ENTITY_REF_NODE) {
776 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
777 if (!ctxt->check) {
778 xmlCtxtDumpSpaces(ctxt);
779 fprintf(ctxt->output, "content=");
780 xmlCtxtDumpString(ctxt, node->content);
781 fprintf(ctxt->output, "\n");
782 }
783 }
784 } else {
785 xmlEntityPtr ent;
786
787 ent = xmlGetDocEntity(node->doc, node->name);
788 if (ent != NULL)
789 xmlCtxtDumpEntity(ctxt, ent);
790 }
791 ctxt->depth--;
792
793 /*
794 * Do a bit of checking
795 */
796 if (node->parent == NULL)
797 fprintf(ctxt->output, "PBM: Node has no parent\n");
798 if (node->doc == NULL)
799 fprintf(ctxt->output, "PBM: Node has no doc\n");
800 if ((node->parent != NULL) && (node->doc != node->parent->doc))
801 fprintf(ctxt->output, "PBM: Node doc differs from parent's one\n");
802 if (node->prev == NULL) {
803 if ((node->parent != NULL) && (node->parent->children != node))
804 fprintf(ctxt->output,
805 "PBM: Node has no prev and not first of list\n");
806 } else {
807 if (node->prev->next != node)
808 fprintf(ctxt->output,
809 "PBM: Node prev->next : back link wrong\n");
810 }
811 if (node->next == NULL) {
812 if ((node->parent != NULL) && (node->parent->last != node))
813 fprintf(ctxt->output,
814 "PBM: Node has no next and not last of list\n");
815 } else {
816 if (node->next->prev != node)
817 fprintf(ctxt->output,
818 "PBM: Node next->prev : forward link wrong\n");
819 }
820}
821
822/**
823 * xmlCtxtDumpNode:
824 * @output: the FILE * for the output
825 * @node: the node
826 * @depth: the indentation level.
827 *
828 * Dumps debug information for the element node, it is recursive
829 */
830static void
831xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
832{
833 if (node == NULL) {
834 if (!ctxt->check) {
835 xmlCtxtDumpSpaces(ctxt);
836 fprintf(ctxt->output, "node is NULL\n");
837 }
838 return;
839 }
840 xmlCtxtDumpOneNode(ctxt, node);
841 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
842 ctxt->depth++;
843 xmlCtxtDumpNodeList(ctxt, node->children);
844 ctxt->depth--;
845 }
846}
847
848/**
849 * xmlCtxtDumpNodeList:
850 * @output: the FILE * for the output
851 * @node: the node list
852 * @depth: the indentation level.
853 *
854 * Dumps debug information for the list of element node, it is recursive
855 */
856static void
857xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
858{
859 while (node != NULL) {
860 xmlCtxtDumpNode(ctxt, node);
861 node = node->next;
862 }
863}
864
865
866/**
867 * xmlCtxtDumpDocumentHead:
868 * @output: the FILE * for the output
869 * @doc: the document
870 *
871 * Dumps debug information cncerning the document, not recursive
872 */
873static void
874xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
875{
876 if (doc == NULL) {
877 if (!ctxt->check)
878 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
879 return;
880 }
881
882 switch (doc->type) {
883 case XML_ELEMENT_NODE:
884 fprintf(ctxt->output, "Error, ELEMENT found here ");
885 break;
886 case XML_ATTRIBUTE_NODE:
887 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
888 break;
889 case XML_TEXT_NODE:
890 fprintf(ctxt->output, "Error, TEXT\n");
891 break;
892 case XML_CDATA_SECTION_NODE:
893 fprintf(ctxt->output, "Error, CDATA_SECTION\n");
894 break;
895 case XML_ENTITY_REF_NODE:
896 fprintf(ctxt->output, "Error, ENTITY_REF\n");
897 break;
898 case XML_ENTITY_NODE:
899 fprintf(ctxt->output, "Error, ENTITY\n");
900 break;
901 case XML_PI_NODE:
902 fprintf(ctxt->output, "Error, PI\n");
903 break;
904 case XML_COMMENT_NODE:
905 fprintf(ctxt->output, "Error, COMMENT\n");
906 break;
907 case XML_DOCUMENT_NODE:
908 fprintf(ctxt->output, "DOCUMENT\n");
909 break;
910 case XML_HTML_DOCUMENT_NODE:
911 fprintf(ctxt->output, "HTML DOCUMENT\n");
912 break;
913 case XML_DOCUMENT_TYPE_NODE:
914 fprintf(ctxt->output, "Error, DOCUMENT_TYPE\n");
915 break;
916 case XML_DOCUMENT_FRAG_NODE:
917 fprintf(ctxt->output, "Error, DOCUMENT_FRAG\n");
918 break;
919 case XML_NOTATION_NODE:
920 fprintf(ctxt->output, "Error, NOTATION\n");
921 break;
922 default:
923 fprintf(ctxt->output, "NODE_%d\n", doc->type);
924 }
925 if (!ctxt->check) {
926 if (doc->name != NULL) {
927 fprintf(ctxt->output, "name=");
928 xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
929 fprintf(ctxt->output, "\n");
930 }
931 if (doc->version != NULL) {
932 fprintf(ctxt->output, "version=");
933 xmlCtxtDumpString(ctxt, doc->version);
934 fprintf(ctxt->output, "\n");
935 }
936 if (doc->encoding != NULL) {
937 fprintf(ctxt->output, "encoding=");
938 xmlCtxtDumpString(ctxt, doc->encoding);
939 fprintf(ctxt->output, "\n");
940 }
941 if (doc->URL != NULL) {
942 fprintf(ctxt->output, "URL=");
943 xmlCtxtDumpString(ctxt, doc->URL);
944 fprintf(ctxt->output, "\n");
945 }
946 if (doc->standalone)
947 fprintf(ctxt->output, "standalone=true\n");
948 }
949 if (doc->oldNs != NULL)
950 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
951}
952
953/**
954 * xmlCtxtDumpDocument:
955 * @output: the FILE * for the output
956 * @doc: the document
957 *
958 * Dumps debug information for the document, it's recursive
959 */
960static void
961xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
962{
963 if (doc == NULL) {
964 if (!ctxt->check)
965 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
966 return;
967 }
968 xmlCtxtDumpDocumentHead(ctxt, doc);
969 if (((doc->type == XML_DOCUMENT_NODE) ||
970 (doc->type == XML_HTML_DOCUMENT_NODE))
971 && (doc->children != NULL)) {
972 ctxt->depth++;
973 xmlCtxtDumpNodeList(ctxt, doc->children);
974 ctxt->depth--;
975 }
976}
977
978static void
979xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt)
980{
981 if (cur == NULL) {
982 if (!ctxt->check)
983 fprintf(ctxt->output, "Entity is NULL");
984 return;
985 }
986 if (!ctxt->check) {
987 fprintf(ctxt->output, "%s : ", (char *) cur->name);
988 switch (cur->etype) {
989 case XML_INTERNAL_GENERAL_ENTITY:
990 fprintf(ctxt->output, "INTERNAL GENERAL, ");
991 break;
992 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
993 fprintf(ctxt->output, "EXTERNAL PARSED, ");
994 break;
995 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
996 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
997 break;
998 case XML_INTERNAL_PARAMETER_ENTITY:
999 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1000 break;
1001 case XML_EXTERNAL_PARAMETER_ENTITY:
1002 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1003 break;
1004 default:
1005 fprintf(ctxt->output, "UNKNOWN TYPE %d", cur->etype);
1006 }
1007 if (cur->ExternalID != NULL)
1008 fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1009 if (cur->SystemID != NULL)
1010 fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1011 if (cur->orig != NULL)
1012 fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1013 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1014 fprintf(ctxt->output, "\n content \"%s\"",
1015 (char *) cur->content);
1016 fprintf(ctxt->output, "\n");
1017 }
1018}
1019
1020/**
1021 * xmlCtxtDumpEntities:
1022 * @output: the FILE * for the output
1023 * @doc: the document
1024 *
1025 * Dumps debug information for all the entities in use by the document
1026 */
1027static void
1028xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1029{
1030 if (doc == NULL) {
1031 if (!ctxt->check)
1032 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1033 return;
1034 }
1035
1036 switch (doc->type) {
1037 case XML_ELEMENT_NODE:
1038 fprintf(ctxt->output, "Error, ELEMENT found here ");
1039 break;
1040 case XML_ATTRIBUTE_NODE:
1041 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
1042 break;
1043 case XML_TEXT_NODE:
1044 fprintf(ctxt->output, "Error, TEXT\n");
1045 break;
1046 case XML_CDATA_SECTION_NODE:
1047 fprintf(ctxt->output, "Error, CDATA_SECTION\n");
1048 break;
1049 case XML_ENTITY_REF_NODE:
1050 fprintf(ctxt->output, "Error, ENTITY_REF\n");
1051 break;
1052 case XML_ENTITY_NODE:
1053 fprintf(ctxt->output, "Error, ENTITY\n");
1054 break;
1055 case XML_PI_NODE:
1056 fprintf(ctxt->output, "Error, PI\n");
1057 break;
1058 case XML_COMMENT_NODE:
1059 fprintf(ctxt->output, "Error, COMMENT\n");
1060 break;
1061 case XML_DOCUMENT_NODE:
1062 fprintf(ctxt->output, "DOCUMENT\n");
1063 break;
1064 case XML_HTML_DOCUMENT_NODE:
1065 fprintf(ctxt->output, "HTML DOCUMENT\n");
1066 break;
1067 case XML_DOCUMENT_TYPE_NODE:
1068 fprintf(ctxt->output, "Error, DOCUMENT_TYPE\n");
1069 break;
1070 case XML_DOCUMENT_FRAG_NODE:
1071 fprintf(ctxt->output, "Error, DOCUMENT_FRAG\n");
1072 break;
1073 case XML_NOTATION_NODE:
1074 fprintf(ctxt->output, "Error, NOTATION\n");
1075 break;
1076 default:
1077 fprintf(ctxt->output, "NODE_%d\n", doc->type);
1078 }
1079 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1080 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1081 doc->intSubset->entities;
1082
1083 if (!ctxt->check)
1084 fprintf(ctxt->output, "Entities in internal subset\n");
1085 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1086 ctxt);
1087 } else
1088 fprintf(ctxt->output, "No entities in internal subset\n");
1089 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1090 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1091 doc->extSubset->entities;
1092
1093 if (!ctxt->check)
1094 fprintf(ctxt->output, "Entities in external subset\n");
1095 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1096 ctxt);
1097 } else if (!ctxt->check)
1098 fprintf(ctxt->output, "No entities in external subset\n");
1099}
1100
1101/**
1102 * xmlCtxtDumpDTD:
1103 * @output: the FILE * for the output
1104 * @dtd: the DTD
1105 *
1106 * Dumps debug information for the DTD
1107 */
1108static void
1109xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1110{
1111 if (dtd == NULL) {
1112 if (!ctxt->check)
1113 fprintf(ctxt->output, "DTD is NULL\n");
1114 return;
1115 }
1116 if (dtd->type != XML_DTD_NODE) {
1117 fprintf(ctxt->output, "PBM: not a DTD\n");
1118 return;
1119 }
1120 if (!ctxt->check) {
1121 if (dtd->name != NULL)
1122 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
1123 else
1124 fprintf(ctxt->output, "DTD");
1125 if (dtd->ExternalID != NULL)
1126 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
1127 if (dtd->SystemID != NULL)
1128 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
1129 fprintf(ctxt->output, "\n");
1130 }
1131 /*
1132 * Do a bit of checking
1133 */
1134 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
1135 fprintf(ctxt->output, "PBM: DTD doc differs from parent's one\n");
1136 if (dtd->prev == NULL) {
1137 if ((dtd->parent != NULL)
1138 && (dtd->parent->children != (xmlNodePtr) dtd))
1139 fprintf(ctxt->output,
1140 "PBM: DTD has no prev and not first of list\n");
1141 } else {
1142 if (dtd->prev->next != (xmlNodePtr) dtd)
1143 fprintf(ctxt->output,
1144 "PBM: DTD prev->next : back link wrong\n");
1145 }
1146 if (dtd->next == NULL) {
1147 if ((dtd->parent != NULL)
1148 && (dtd->parent->last != (xmlNodePtr) dtd))
1149 fprintf(ctxt->output,
1150 "PBM: DTD has no next and not last of list\n");
1151 } else {
1152 if (dtd->next->prev != (xmlNodePtr) dtd)
1153 fprintf(ctxt->output,
1154 "PBM: DTD next->prev : forward link wrong\n");
1155 }
1156 if (dtd->children == NULL)
1157 fprintf(ctxt->output, " DTD is empty\n");
1158 else {
1159 ctxt->depth++;
1160 xmlCtxtDumpNodeList(ctxt, dtd->children);
1161 ctxt->depth--;
1162 }
1163}
1164/************************************************************************
1165 * *
1166 * Public entry points *
1167 * *
1168 ************************************************************************/
1169
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001170/**
1171 * xmlDebugDumpString:
1172 * @output: the FILE * for the output
1173 * @str: the string
1174 *
1175 * Dumps informations about the string, shorten it if necessary
1176 */
1177void
1178xmlDebugDumpString(FILE * output, const xmlChar * str)
1179{
Owen Taylor3473f882001-02-23 17:55:21 +00001180 int i;
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001181
Daniel Veillard7db38712002-02-07 16:39:11 +00001182 if (output == NULL)
1183 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00001184 if (str == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001185 fprintf(output, "(NULL)");
1186 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001187 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001188 for (i = 0; i < 40; i++)
1189 if (str[i] == 0)
1190 return;
William M. Brack76e95df2003-10-18 16:20:14 +00001191 else if (IS_BLANK_CH(str[i]))
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001192 fputc(' ', output);
1193 else if (str[i] >= 0x80)
1194 fprintf(output, "#%X", str[i]);
1195 else
1196 fputc(str[i], output);
Owen Taylor3473f882001-02-23 17:55:21 +00001197 fprintf(output, "...");
1198}
1199
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001200/**
1201 * xmlDebugDumpAttr:
1202 * @output: the FILE * for the output
1203 * @attr: the attribute
1204 * @depth: the indentation level.
1205 *
1206 * Dumps debug information for the attribute
1207 */
1208void
1209xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
Daniel Veillard22cdb842004-10-04 14:09:17 +00001210 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001211
Daniel Veillard22cdb842004-10-04 14:09:17 +00001212 xmlCtxtDumpInitCtxt(&ctxt);
1213 ctxt.output = output;
1214 ctxt.depth = depth;
1215 xmlCtxtDumpAttr(&ctxt, attr);
1216}
Owen Taylor3473f882001-02-23 17:55:21 +00001217
Owen Taylor3473f882001-02-23 17:55:21 +00001218
Daniel Veillard22cdb842004-10-04 14:09:17 +00001219/**
1220 * xmlDebugDumpEntities:
1221 * @output: the FILE * for the output
1222 * @doc: the document
1223 *
1224 * Dumps debug information for all the entities in use by the document
1225 */
1226void
1227xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1228{
1229 xmlDebugCtxt ctxt;
1230
1231 xmlCtxtDumpInitCtxt(&ctxt);
1232 ctxt.output = output;
1233 xmlCtxtDumpEntities(&ctxt, doc);
Owen Taylor3473f882001-02-23 17:55:21 +00001234}
1235
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001236/**
1237 * xmlDebugDumpAttrList:
1238 * @output: the FILE * for the output
1239 * @attr: the attribute list
1240 * @depth: the indentation level.
1241 *
1242 * Dumps debug information for the attribute list
1243 */
1244void
1245xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1246{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001247 xmlDebugCtxt ctxt;
1248
1249 xmlCtxtDumpInitCtxt(&ctxt);
1250 ctxt.output = output;
1251 ctxt.depth = depth;
1252 xmlCtxtDumpAttrList(&ctxt, attr);
Owen Taylor3473f882001-02-23 17:55:21 +00001253}
1254
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001255/**
1256 * xmlDebugDumpOneNode:
1257 * @output: the FILE * for the output
1258 * @node: the node
1259 * @depth: the indentation level.
1260 *
1261 * Dumps debug information for the element node, it is not recursive
1262 */
1263void
1264xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1265{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001266 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001267
Daniel Veillard22cdb842004-10-04 14:09:17 +00001268 xmlCtxtDumpInitCtxt(&ctxt);
1269 ctxt.output = output;
1270 ctxt.depth = depth;
1271 xmlCtxtDumpOneNode(&ctxt, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001272}
1273
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001274/**
1275 * xmlDebugDumpNode:
1276 * @output: the FILE * for the output
1277 * @node: the node
1278 * @depth: the indentation level.
1279 *
1280 * Dumps debug information for the element node, it is recursive
1281 */
1282void
1283xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1284{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001285 xmlDebugCtxt ctxt;
1286
Daniel Veillard7db38712002-02-07 16:39:11 +00001287 if (output == NULL)
1288 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001289 xmlCtxtDumpInitCtxt(&ctxt);
1290 ctxt.output = output;
1291 ctxt.depth = depth;
1292 xmlCtxtDumpNode(&ctxt, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001293}
1294
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001295/**
1296 * xmlDebugDumpNodeList:
1297 * @output: the FILE * for the output
1298 * @node: the node list
1299 * @depth: the indentation level.
1300 *
1301 * Dumps debug information for the list of element node, it is recursive
1302 */
1303void
1304xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1305{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001306 xmlDebugCtxt ctxt;
1307
Daniel Veillard7db38712002-02-07 16:39:11 +00001308 if (output == NULL)
1309 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001310 xmlCtxtDumpInitCtxt(&ctxt);
1311 ctxt.output = output;
1312 ctxt.depth = depth;
1313 xmlCtxtDumpNodeList(&ctxt, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001314}
1315
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001316/**
1317 * xmlDebugDumpDocumentHead:
1318 * @output: the FILE * for the output
1319 * @doc: the document
1320 *
1321 * Dumps debug information cncerning the document, not recursive
1322 */
1323void
1324xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1325{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001326 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001327
Daniel Veillard22cdb842004-10-04 14:09:17 +00001328 if (output == NULL)
1329 output = stdout;
1330 xmlCtxtDumpInitCtxt(&ctxt);
1331 ctxt.output = output;
1332 xmlCtxtDumpDocumentHead(&ctxt, doc);
Owen Taylor3473f882001-02-23 17:55:21 +00001333}
1334
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001335/**
1336 * xmlDebugDumpDocument:
1337 * @output: the FILE * for the output
1338 * @doc: the document
1339 *
1340 * Dumps debug information for the document, it's recursive
1341 */
1342void
1343xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1344{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001345 xmlDebugCtxt ctxt;
1346
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001347 if (output == NULL)
Daniel Veillard22cdb842004-10-04 14:09:17 +00001348 output = stdout;
1349 xmlCtxtDumpInitCtxt(&ctxt);
1350 ctxt.output = output;
1351 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001352}
Owen Taylor3473f882001-02-23 17:55:21 +00001353
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001354/**
1355 * xmlDebugDumpDTD:
1356 * @output: the FILE * for the output
1357 * @dtd: the DTD
1358 *
1359 * Dumps debug information for the DTD
1360 */
1361void
1362xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1363{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001364 xmlDebugCtxt ctxt;
1365
Daniel Veillard7db38712002-02-07 16:39:11 +00001366 if (output == NULL)
1367 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001368 xmlCtxtDumpInitCtxt(&ctxt);
1369 ctxt.output = output;
1370 xmlCtxtDumpDTD(&ctxt, dtd);
Owen Taylor3473f882001-02-23 17:55:21 +00001371}
1372
Daniel Veillard22cdb842004-10-04 14:09:17 +00001373/************************************************************************
1374 * *
1375 * Helpers for Shell *
1376 * *
1377 ************************************************************************/
Owen Taylor3473f882001-02-23 17:55:21 +00001378
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001379/**
1380 * xmlLsCountNode:
1381 * @node: the node to count
1382 *
1383 * Count the children of @node.
1384 *
1385 * Returns the number of children of @node.
1386 */
1387int
1388xmlLsCountNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001389 int ret = 0;
1390 xmlNodePtr list = NULL;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001391
1392 if (node == NULL)
1393 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001394
1395 switch (node->type) {
1396 case XML_ELEMENT_NODE:
1397 list = node->children;
1398 break;
1399 case XML_DOCUMENT_NODE:
1400 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00001401#ifdef LIBXML_DOCB_ENABLED
1402 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00001403#endif
1404 list = ((xmlDocPtr) node)->children;
1405 break;
1406 case XML_ATTRIBUTE_NODE:
1407 list = ((xmlAttrPtr) node)->children;
1408 break;
1409 case XML_TEXT_NODE:
1410 case XML_CDATA_SECTION_NODE:
1411 case XML_PI_NODE:
1412 case XML_COMMENT_NODE:
1413 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001414 ret = xmlStrlen(node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001415 }
1416 break;
1417 case XML_ENTITY_REF_NODE:
1418 case XML_DOCUMENT_TYPE_NODE:
1419 case XML_ENTITY_NODE:
1420 case XML_DOCUMENT_FRAG_NODE:
1421 case XML_NOTATION_NODE:
1422 case XML_DTD_NODE:
1423 case XML_ELEMENT_DECL:
1424 case XML_ATTRIBUTE_DECL:
1425 case XML_ENTITY_DECL:
1426 case XML_NAMESPACE_DECL:
1427 case XML_XINCLUDE_START:
1428 case XML_XINCLUDE_END:
1429 ret = 1;
1430 break;
1431 }
1432 for (;list != NULL;ret++)
1433 list = list->next;
1434 return(ret);
1435}
1436
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001437/**
1438 * xmlLsOneNode:
1439 * @output: the FILE * for the output
1440 * @node: the node to dump
1441 *
1442 * Dump to @output the type and name of @node.
1443 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001444void
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001445xmlLsOneNode(FILE *output, xmlNodePtr node) {
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001446 if (node == NULL) {
1447 fprintf(output, "NULL\n");
1448 return;
1449 }
Owen Taylor3473f882001-02-23 17:55:21 +00001450 switch (node->type) {
1451 case XML_ELEMENT_NODE:
1452 fprintf(output, "-");
1453 break;
1454 case XML_ATTRIBUTE_NODE:
1455 fprintf(output, "a");
1456 break;
1457 case XML_TEXT_NODE:
1458 fprintf(output, "t");
1459 break;
1460 case XML_CDATA_SECTION_NODE:
Daniel Veillard75be0132002-03-13 10:03:35 +00001461 fprintf(output, "C");
Owen Taylor3473f882001-02-23 17:55:21 +00001462 break;
1463 case XML_ENTITY_REF_NODE:
1464 fprintf(output, "e");
1465 break;
1466 case XML_ENTITY_NODE:
1467 fprintf(output, "E");
1468 break;
1469 case XML_PI_NODE:
1470 fprintf(output, "p");
1471 break;
1472 case XML_COMMENT_NODE:
1473 fprintf(output, "c");
1474 break;
1475 case XML_DOCUMENT_NODE:
1476 fprintf(output, "d");
1477 break;
1478 case XML_HTML_DOCUMENT_NODE:
1479 fprintf(output, "h");
1480 break;
1481 case XML_DOCUMENT_TYPE_NODE:
1482 fprintf(output, "T");
1483 break;
1484 case XML_DOCUMENT_FRAG_NODE:
1485 fprintf(output, "F");
1486 break;
1487 case XML_NOTATION_NODE:
1488 fprintf(output, "N");
1489 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001490 case XML_NAMESPACE_DECL:
1491 fprintf(output, "n");
1492 break;
Owen Taylor3473f882001-02-23 17:55:21 +00001493 default:
1494 fprintf(output, "?");
1495 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00001496 if (node->type != XML_NAMESPACE_DECL) {
1497 if (node->properties != NULL)
1498 fprintf(output, "a");
1499 else
1500 fprintf(output, "-");
1501 if (node->nsDef != NULL)
1502 fprintf(output, "n");
1503 else
1504 fprintf(output, "-");
1505 }
Owen Taylor3473f882001-02-23 17:55:21 +00001506
1507 fprintf(output, " %8d ", xmlLsCountNode(node));
1508
1509 switch (node->type) {
1510 case XML_ELEMENT_NODE:
1511 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001512 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001513 break;
1514 case XML_ATTRIBUTE_NODE:
1515 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001516 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001517 break;
1518 case XML_TEXT_NODE:
1519 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001520 xmlDebugDumpString(output, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001521 }
1522 break;
1523 case XML_CDATA_SECTION_NODE:
1524 break;
1525 case XML_ENTITY_REF_NODE:
1526 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001527 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001528 break;
1529 case XML_ENTITY_NODE:
1530 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001531 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001532 break;
1533 case XML_PI_NODE:
1534 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001535 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 break;
1537 case XML_COMMENT_NODE:
1538 break;
1539 case XML_DOCUMENT_NODE:
1540 break;
1541 case XML_HTML_DOCUMENT_NODE:
1542 break;
1543 case XML_DOCUMENT_TYPE_NODE:
1544 break;
1545 case XML_DOCUMENT_FRAG_NODE:
1546 break;
1547 case XML_NOTATION_NODE:
1548 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001549 case XML_NAMESPACE_DECL: {
1550 xmlNsPtr ns = (xmlNsPtr) node;
1551
1552 if (ns->prefix == NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00001553 fprintf(output, "default -> %s", (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001554 else
William M. Brack13dfa872004-09-18 04:52:08 +00001555 fprintf(output, "%s -> %s", (char *)ns->prefix,
1556 (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001557 break;
1558 }
Owen Taylor3473f882001-02-23 17:55:21 +00001559 default:
1560 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001561 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001562 }
1563 fprintf(output, "\n");
1564}
1565
Daniel Veillard78d12092001-10-11 09:12:24 +00001566/**
1567 * xmlBoolToText:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001568 * @boolval: a bool to turn into text
Daniel Veillard78d12092001-10-11 09:12:24 +00001569 *
1570 * Convenient way to turn bool into text
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001571 *
1572 * Returns a pointer to either "True" or "False"
1573 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001574const char *
Daniel Veillardebd38c52001-11-01 08:38:12 +00001575xmlBoolToText(int boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001576{
Daniel Veillardebd38c52001-11-01 08:38:12 +00001577 if (boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001578 return("True");
1579 else
1580 return("False");
1581}
1582
Owen Taylor3473f882001-02-23 17:55:21 +00001583/****************************************************************
1584 * *
1585 * The XML shell related functions *
1586 * *
1587 ****************************************************************/
1588
Daniel Veillard78d12092001-10-11 09:12:24 +00001589
1590
Owen Taylor3473f882001-02-23 17:55:21 +00001591/*
1592 * TODO: Improvement/cleanups for the XML shell
1593 * - allow to shell out an editor on a subpart
1594 * - cleanup function registrations (with help) and calling
1595 * - provide registration routines
1596 */
1597
1598/**
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001599 * xmlShellPrintXPathError:
Daniel Veillard78d12092001-10-11 09:12:24 +00001600 * @errorType: valid xpath error id
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001601 * @arg: the argument that cause xpath to fail
Daniel Veillard78d12092001-10-11 09:12:24 +00001602 *
1603 * Print the xpath error to libxml default error channel
1604 */
1605void
1606xmlShellPrintXPathError(int errorType, const char *arg)
1607{
1608 const char *default_arg = "Result";
1609
1610 if (!arg)
1611 arg = default_arg;
1612
1613 switch (errorType) {
1614 case XPATH_UNDEFINED:
1615 xmlGenericError(xmlGenericErrorContext,
1616 "%s: no such node\n", arg);
1617 break;
1618
1619 case XPATH_BOOLEAN:
1620 xmlGenericError(xmlGenericErrorContext,
1621 "%s is a Boolean\n", arg);
1622 break;
1623 case XPATH_NUMBER:
1624 xmlGenericError(xmlGenericErrorContext,
1625 "%s is a number\n", arg);
1626 break;
1627 case XPATH_STRING:
1628 xmlGenericError(xmlGenericErrorContext,
1629 "%s is a string\n", arg);
1630 break;
1631 case XPATH_POINT:
1632 xmlGenericError(xmlGenericErrorContext,
1633 "%s is a point\n", arg);
1634 break;
1635 case XPATH_RANGE:
1636 xmlGenericError(xmlGenericErrorContext,
1637 "%s is a range\n", arg);
1638 break;
1639 case XPATH_LOCATIONSET:
1640 xmlGenericError(xmlGenericErrorContext,
1641 "%s is a range\n", arg);
1642 break;
1643 case XPATH_USERS:
1644 xmlGenericError(xmlGenericErrorContext,
1645 "%s is user-defined\n", arg);
1646 break;
1647 case XPATH_XSLT_TREE:
1648 xmlGenericError(xmlGenericErrorContext,
1649 "%s is an XSLT value tree\n", arg);
1650 break;
1651 }
1652 xmlGenericError(xmlGenericErrorContext,
1653 "Try casting the result string function (xpath builtin)\n",
1654 arg);
1655}
1656
1657
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001658#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001659/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001660 * xmlShellPrintNodeCtxt:
1661 * @ctxt : a non-null shell context
1662 * @node : a non-null node to print to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001663 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001664 * Print node to the output FILE
1665 */
1666static void
1667xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1668{
Daniel Veillard01992e02002-10-09 10:20:30 +00001669 FILE *fp;
1670
1671 if (!node)
Daniel Veillard321be0c2002-10-08 21:26:42 +00001672 return;
Daniel Veillard01992e02002-10-09 10:20:30 +00001673 if (ctxt == NULL)
1674 fp = stdout;
1675 else
1676 fp = ctxt->output;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001677
1678 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001679 xmlDocDump(fp, (xmlDocPtr) node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001680 else if (node->type == XML_ATTRIBUTE_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001681 xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001682 else
Daniel Veillard01992e02002-10-09 10:20:30 +00001683 xmlElemDump(fp, node->doc, node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001684
Daniel Veillard01992e02002-10-09 10:20:30 +00001685 fprintf(fp, "\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00001686}
1687
1688/**
1689 * xmlShellPrintNode:
1690 * @node : a non-null node to print to the output FILE
1691 *
1692 * Print node to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001693 */
1694void
1695xmlShellPrintNode(xmlNodePtr node)
1696{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001697 xmlShellPrintNodeCtxt(NULL, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001698}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001699#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001700
Daniel Veillard78d12092001-10-11 09:12:24 +00001701/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001702 * xmlShellPrintXPathResultCtxt:
1703 * @ctxt: a valid shell context
Daniel Veillard9d06d302002-01-22 18:15:52 +00001704 * @list: a valid result generated by an xpath evaluation
Daniel Veillard78d12092001-10-11 09:12:24 +00001705 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001706 * Prints result to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001707 */
Daniel Veillard321be0c2002-10-08 21:26:42 +00001708static void
1709xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
Daniel Veillard78d12092001-10-11 09:12:24 +00001710{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001711 if (!ctxt)
1712 return;
Daniel Veillard78d12092001-10-11 09:12:24 +00001713
1714 if (list != NULL) {
1715 switch (list->type) {
1716 case XPATH_NODESET:{
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001717#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001718 int indx;
1719
1720 if (list->nodesetval) {
1721 for (indx = 0; indx < list->nodesetval->nodeNr;
1722 indx++) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001723 xmlShellPrintNodeCtxt(ctxt,
1724 list->nodesetval->nodeTab[indx]);
Daniel Veillard78d12092001-10-11 09:12:24 +00001725 }
1726 } else {
1727 xmlGenericError(xmlGenericErrorContext,
1728 "Empty node set\n");
1729 }
1730 break;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001731#else
1732 xmlGenericError(xmlGenericErrorContext,
1733 "Node set\n");
1734#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001735 }
1736 case XPATH_BOOLEAN:
1737 xmlGenericError(xmlGenericErrorContext,
1738 "Is a Boolean:%s\n",
1739 xmlBoolToText(list->boolval));
1740 break;
1741 case XPATH_NUMBER:
1742 xmlGenericError(xmlGenericErrorContext,
1743 "Is a number:%0g\n", list->floatval);
1744 break;
1745 case XPATH_STRING:
1746 xmlGenericError(xmlGenericErrorContext,
1747 "Is a string:%s\n", list->stringval);
1748 break;
1749
1750 default:
1751 xmlShellPrintXPathError(list->type, NULL);
1752 }
1753 }
1754}
1755
1756/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001757 * xmlShellPrintXPathResult:
1758 * @list: a valid result generated by an xpath evaluation
1759 *
1760 * Prints result to the output FILE
1761 */
1762void
1763xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1764{
1765 xmlShellPrintXPathResultCtxt(NULL, list);
1766}
1767
1768/**
Owen Taylor3473f882001-02-23 17:55:21 +00001769 * xmlShellList:
1770 * @ctxt: the shell context
1771 * @arg: unused
1772 * @node: a node
1773 * @node2: unused
1774 *
1775 * Implements the XML shell function "ls"
1776 * Does an Unix like listing of the given node (like a directory)
1777 *
1778 * Returns 0
1779 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001780int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001781xmlShellList(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001782 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1783 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1784{
Owen Taylor3473f882001-02-23 17:55:21 +00001785 xmlNodePtr cur;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001786 if (!ctxt)
1787 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001788 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001789 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001790 return (0);
1791 }
Owen Taylor3473f882001-02-23 17:55:21 +00001792 if ((node->type == XML_DOCUMENT_NODE) ||
1793 (node->type == XML_HTML_DOCUMENT_NODE)) {
1794 cur = ((xmlDocPtr) node)->children;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001795 } else if (node->type == XML_NAMESPACE_DECL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001796 xmlLsOneNode(ctxt->output, node);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001797 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001798 } else if (node->children != NULL) {
1799 cur = node->children;
1800 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001801 xmlLsOneNode(ctxt->output, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001802 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001803 }
1804 while (cur != NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001805 xmlLsOneNode(ctxt->output, cur);
Daniel Veillard78d12092001-10-11 09:12:24 +00001806 cur = cur->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001807 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001808 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001809}
1810
1811/**
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001812 * xmlShellBase:
1813 * @ctxt: the shell context
1814 * @arg: unused
1815 * @node: a node
1816 * @node2: unused
1817 *
1818 * Implements the XML shell function "base"
1819 * dumps the current XML base of the node
1820 *
1821 * Returns 0
1822 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001823int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001824xmlShellBase(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001825 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1826 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1827{
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001828 xmlChar *base;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001829 if (!ctxt)
1830 return 0;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001831 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001832 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001833 return (0);
1834 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001835
1836 base = xmlNodeGetBase(node->doc, node);
1837
1838 if (base == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001839 fprintf(ctxt->output, " No base found !!!\n");
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001840 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001841 fprintf(ctxt->output, "%s\n", base);
Daniel Veillard78d12092001-10-11 09:12:24 +00001842 xmlFree(base);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001843 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001844 return (0);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001845}
1846
Daniel Veillardb34321c2004-03-04 17:09:47 +00001847#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001848/**
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001849 * xmlShellSetBase:
1850 * @ctxt: the shell context
1851 * @arg: the new base
1852 * @node: a node
1853 * @node2: unused
1854 *
1855 * Implements the XML shell function "setbase"
1856 * change the current XML base of the node
1857 *
1858 * Returns 0
1859 */
1860static int
1861xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1862 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1863 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1864{
1865 xmlNodeSetBase(node, (xmlChar*) arg);
1866 return (0);
1867}
Daniel Veillard2156d432004-03-04 15:59:36 +00001868#endif
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001869
Daniel Veillardbbaa9972004-06-16 14:08:33 +00001870#ifdef LIBXML_XPATH_ENABLED
1871/**
1872 * xmlShellRegisterNamespace:
1873 * @ctxt: the shell context
1874 * @arg: a string in prefix=nsuri format
1875 * @node: unused
1876 * @node2: unused
1877 *
1878 * Implements the XML shell function "setns"
1879 * register/unregister a prefix=namespace pair
1880 * on the XPath context
1881 *
1882 * Returns 0 on success and a negative value otherwise.
1883 */
1884static int
1885xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
1886 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1887{
1888 xmlChar* nsListDup;
1889 xmlChar* prefix;
1890 xmlChar* href;
1891 xmlChar* next;
1892
1893 nsListDup = xmlStrdup((xmlChar *) arg);
1894 next = nsListDup;
1895 while(next != NULL) {
1896 /* skip spaces */
1897 /*while((*next) == ' ') next++;*/
1898 if((*next) == '\0') break;
1899
1900 /* find prefix */
1901 prefix = next;
1902 next = (xmlChar*)xmlStrchr(next, '=');
1903 if(next == NULL) {
1904 fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
1905 xmlFree(nsListDup);
1906 return(-1);
1907 }
1908 *(next++) = '\0';
1909
1910 /* find href */
1911 href = next;
1912 next = (xmlChar*)xmlStrchr(next, ' ');
1913 if(next != NULL) {
1914 *(next++) = '\0';
1915 }
1916
1917 /* do register namespace */
1918 if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
1919 fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
1920 xmlFree(nsListDup);
1921 return(-1);
1922 }
1923 }
1924
1925 xmlFree(nsListDup);
1926 return(0);
1927}
1928#endif
1929
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001930/**
Daniel Veillard1e208222002-10-22 14:25:25 +00001931 * xmlShellGrep:
1932 * @ctxt: the shell context
1933 * @arg: the string or regular expression to find
1934 * @node: a node
1935 * @node2: unused
1936 *
1937 * Implements the XML shell function "grep"
1938 * dumps informations about the node (namespace, attributes, content).
1939 *
1940 * Returns 0
1941 */
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001942static int
Daniel Veillard1e208222002-10-22 14:25:25 +00001943xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1944 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1945{
1946 if (!ctxt)
1947 return (0);
1948 if (node == NULL)
1949 return (0);
1950 if (arg == NULL)
1951 return (0);
1952#ifdef LIBXML_REGEXP_ENABLED
1953 if ((xmlStrchr((xmlChar *) arg, '?')) ||
1954 (xmlStrchr((xmlChar *) arg, '*')) ||
1955 (xmlStrchr((xmlChar *) arg, '.')) ||
1956 (xmlStrchr((xmlChar *) arg, '['))) {
1957 }
1958#endif
1959 while (node != NULL) {
1960 if (node->type == XML_COMMENT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001961 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00001962
1963 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
1964 xmlShellList(ctxt, NULL, node, NULL);
1965 }
1966 } else if (node->type == XML_TEXT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001967 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00001968
1969 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001970 xmlShellList(ctxt, NULL, node->parent, NULL);
Daniel Veillard1e208222002-10-22 14:25:25 +00001971 }
1972 }
1973
1974 /*
1975 * Browse the full subtree, deep first
1976 */
1977
1978 if ((node->type == XML_DOCUMENT_NODE) ||
1979 (node->type == XML_HTML_DOCUMENT_NODE)) {
1980 node = ((xmlDocPtr) node)->children;
1981 } else if ((node->children != NULL)
1982 && (node->type != XML_ENTITY_REF_NODE)) {
1983 /* deep first */
1984 node = node->children;
1985 } else if (node->next != NULL) {
1986 /* then siblings */
1987 node = node->next;
1988 } else {
1989 /* go up to parents->next if needed */
1990 while (node != NULL) {
1991 if (node->parent != NULL) {
1992 node = node->parent;
1993 }
1994 if (node->next != NULL) {
1995 node = node->next;
1996 break;
1997 }
1998 if (node->parent == NULL) {
1999 node = NULL;
2000 break;
2001 }
2002 }
2003 }
2004 }
2005 return (0);
2006}
2007
2008/**
Owen Taylor3473f882001-02-23 17:55:21 +00002009 * xmlShellDir:
2010 * @ctxt: the shell context
2011 * @arg: unused
2012 * @node: a node
2013 * @node2: unused
2014 *
2015 * Implements the XML shell function "dir"
2016 * dumps informations about the node (namespace, attributes, content).
2017 *
2018 * Returns 0
2019 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002020int
2021xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2022 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2023 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2024{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002025 if (!ctxt)
2026 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002027 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002028 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002029 return (0);
2030 }
Owen Taylor3473f882001-02-23 17:55:21 +00002031 if ((node->type == XML_DOCUMENT_NODE) ||
2032 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002033 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
Owen Taylor3473f882001-02-23 17:55:21 +00002034 } else if (node->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002035 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002036 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002037 xmlDebugDumpOneNode(ctxt->output, node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002038 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002039 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002040}
2041
Daniel Veillard29b17482004-08-16 00:39:03 +00002042/**
2043 * xmlShellSetContent:
2044 * @ctxt: the shell context
2045 * @value: the content as a string
2046 * @node: a node
2047 * @node2: unused
2048 *
2049 * Implements the XML shell function "dir"
2050 * dumps informations about the node (namespace, attributes, content).
2051 *
2052 * Returns 0
2053 */
2054static int
2055xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2056 char *value, xmlNodePtr node,
2057 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2058{
2059 xmlNodePtr results;
2060 xmlParserErrors ret;
2061
2062 if (!ctxt)
2063 return (0);
2064 if (node == NULL) {
2065 fprintf(ctxt->output, "NULL\n");
2066 return (0);
2067 }
2068 if (value == NULL) {
2069 fprintf(ctxt->output, "NULL\n");
2070 return (0);
2071 }
2072
2073 ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
2074 if (ret == XML_ERR_OK) {
2075 if (node->children != NULL) {
2076 xmlFreeNodeList(node->children);
2077 node->children = NULL;
2078 node->last = NULL;
2079 }
2080 xmlAddChildList(node, results);
2081 } else {
2082 fprintf(ctxt->output, "failed to parse content\n");
2083 }
2084 return (0);
2085}
2086
Daniel Veillard522bc602004-02-21 11:53:09 +00002087#ifdef LIBXML_SCHEMAS_ENABLED
2088/**
2089 * xmlShellRNGValidate:
2090 * @ctxt: the shell context
2091 * @schemas: the path to the Relax-NG schemas
2092 * @node: a node
2093 * @node2: unused
2094 *
2095 * Implements the XML shell function "relaxng"
2096 * validating the instance against a Relax-NG schemas
2097 *
2098 * Returns 0
2099 */
2100static int
2101xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2102 xmlNodePtr node ATTRIBUTE_UNUSED,
2103 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2104{
2105 xmlRelaxNGPtr relaxngschemas;
2106 xmlRelaxNGParserCtxtPtr ctxt;
2107 xmlRelaxNGValidCtxtPtr vctxt;
2108 int ret;
2109
2110 ctxt = xmlRelaxNGNewParserCtxt(schemas);
2111 xmlRelaxNGSetParserErrors(ctxt,
2112 (xmlRelaxNGValidityErrorFunc) fprintf,
2113 (xmlRelaxNGValidityWarningFunc) fprintf,
2114 stderr);
2115 relaxngschemas = xmlRelaxNGParse(ctxt);
2116 xmlRelaxNGFreeParserCtxt(ctxt);
2117 if (relaxngschemas == NULL) {
2118 xmlGenericError(xmlGenericErrorContext,
2119 "Relax-NG schema %s failed to compile\n", schemas);
2120 return(-1);
2121 }
2122 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2123 xmlRelaxNGSetValidErrors(vctxt,
2124 (xmlRelaxNGValidityErrorFunc) fprintf,
2125 (xmlRelaxNGValidityWarningFunc) fprintf,
2126 stderr);
2127 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2128 if (ret == 0) {
2129 fprintf(stderr, "%s validates\n", sctxt->filename);
2130 } else if (ret > 0) {
2131 fprintf(stderr, "%s fails to validate\n", sctxt->filename);
2132 } else {
2133 fprintf(stderr, "%s validation generated an internal error\n",
2134 sctxt->filename);
2135 }
2136 xmlRelaxNGFreeValidCtxt(vctxt);
2137 if (relaxngschemas != NULL)
2138 xmlRelaxNGFree(relaxngschemas);
2139 return(0);
2140}
2141#endif
2142
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002143#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002144/**
2145 * xmlShellCat:
2146 * @ctxt: the shell context
2147 * @arg: unused
2148 * @node: a node
2149 * @node2: unused
2150 *
2151 * Implements the XML shell function "cat"
2152 * dumps the serialization node content (XML or HTML).
2153 *
2154 * Returns 0
2155 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002156int
2157xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2158 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2159{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002160 if (!ctxt)
2161 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002162 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002163 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002164 return (0);
2165 }
Owen Taylor3473f882001-02-23 17:55:21 +00002166 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2167#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002168 if (node->type == XML_HTML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002169 htmlDocDump(ctxt->output, (htmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002170 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002171 htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002172#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002173 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002174 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002175 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002176 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002177#endif /* LIBXML_HTML_ENABLED */
2178 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00002179 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002180 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002181 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002182 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002183 }
Daniel Veillard321be0c2002-10-08 21:26:42 +00002184 fprintf(ctxt->output, "\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002185 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002186}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002187#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002188
2189/**
2190 * xmlShellLoad:
2191 * @ctxt: the shell context
2192 * @filename: the file name
2193 * @node: unused
2194 * @node2: unused
2195 *
2196 * Implements the XML shell function "load"
2197 * loads a new document specified by the filename
2198 *
2199 * Returns 0 or -1 if loading failed
2200 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002201int
2202xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2203 xmlNodePtr node ATTRIBUTE_UNUSED,
2204 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2205{
Owen Taylor3473f882001-02-23 17:55:21 +00002206 xmlDocPtr doc;
2207 int html = 0;
2208
2209 if (ctxt->doc != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002210 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00002211
2212 if (html) {
2213#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002214 doc = htmlParseFile(filename, NULL);
2215#else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002216 fprintf(ctxt->output, "HTML support not compiled in\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002217 doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002218#endif /* LIBXML_HTML_ENABLED */
2219 } else {
Daniel Veillardebe25d42004-03-25 09:35:49 +00002220 doc = xmlReadFile(filename,NULL,0);
Owen Taylor3473f882001-02-23 17:55:21 +00002221 }
2222 if (doc != NULL) {
2223 if (ctxt->loaded == 1) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002224 xmlFreeDoc(ctxt->doc);
2225 }
2226 ctxt->loaded = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002227#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002228 xmlXPathFreeContext(ctxt->pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002229#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002230 xmlFree(ctxt->filename);
2231 ctxt->doc = doc;
2232 ctxt->node = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002233#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002234 ctxt->pctxt = xmlXPathNewContext(doc);
Owen Taylor3473f882001-02-23 17:55:21 +00002235#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard85095e22003-04-23 13:56:44 +00002236 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002237 } else
Daniel Veillard78d12092001-10-11 09:12:24 +00002238 return (-1);
2239 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002240}
2241
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002242#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002243/**
2244 * xmlShellWrite:
2245 * @ctxt: the shell context
2246 * @filename: the file name
2247 * @node: a node in the tree
2248 * @node2: unused
2249 *
2250 * Implements the XML shell function "write"
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002251 * Write the current node to the filename, it saves the serialization
Owen Taylor3473f882001-02-23 17:55:21 +00002252 * of the subtree under the @node specified
2253 *
2254 * Returns 0 or -1 in case of error
2255 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002256int
Owen Taylor3473f882001-02-23 17:55:21 +00002257xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
Daniel Veillard78d12092001-10-11 09:12:24 +00002258 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2259{
Owen Taylor3473f882001-02-23 17:55:21 +00002260 if (node == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002261 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002262 if ((filename == NULL) || (filename[0] == 0)) {
2263 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002264 "Write command requires a filename argument\n");
2265 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002266 }
2267#ifdef W_OK
2268 if (access((char *) filename, W_OK)) {
2269 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002270 "Cannot write to %s\n", filename);
2271 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002272 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002273#endif
2274 switch (node->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002275 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002276 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2277 xmlGenericError(xmlGenericErrorContext,
2278 "Failed to write to %s\n", filename);
2279 return (-1);
2280 }
2281 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002282 case XML_HTML_DOCUMENT_NODE:
2283#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002284 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2285 xmlGenericError(xmlGenericErrorContext,
2286 "Failed to write to %s\n", filename);
2287 return (-1);
2288 }
Owen Taylor3473f882001-02-23 17:55:21 +00002289#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002290 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2291 xmlGenericError(xmlGenericErrorContext,
2292 "Failed to write to %s\n", filename);
2293 return (-1);
2294 }
Owen Taylor3473f882001-02-23 17:55:21 +00002295#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002296 break;
2297 default:{
2298 FILE *f;
Owen Taylor3473f882001-02-23 17:55:21 +00002299
Daniel Veillard78d12092001-10-11 09:12:24 +00002300 f = fopen((char *) filename, "w");
2301 if (f == NULL) {
2302 xmlGenericError(xmlGenericErrorContext,
2303 "Failed to write to %s\n", filename);
2304 return (-1);
2305 }
2306 xmlElemDump(f, ctxt->doc, node);
2307 fclose(f);
2308 }
Owen Taylor3473f882001-02-23 17:55:21 +00002309 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002310 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002311}
2312
2313/**
2314 * xmlShellSave:
2315 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002316 * @filename: the file name (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002317 * @node: unused
2318 * @node2: unused
2319 *
2320 * Implements the XML shell function "save"
2321 * Write the current document to the filename, or it's original name
2322 *
2323 * Returns 0 or -1 in case of error
2324 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002325int
2326xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2327 xmlNodePtr node ATTRIBUTE_UNUSED,
2328 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2329{
Owen Taylor3473f882001-02-23 17:55:21 +00002330 if (ctxt->doc == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002331 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002332 if ((filename == NULL) || (filename[0] == 0))
2333 filename = ctxt->filename;
2334#ifdef W_OK
2335 if (access((char *) filename, W_OK)) {
2336 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002337 "Cannot save to %s\n", filename);
2338 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002339 }
2340#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002341 switch (ctxt->doc->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002342 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002343 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2344 xmlGenericError(xmlGenericErrorContext,
2345 "Failed to save to %s\n", filename);
2346 }
2347 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002348 case XML_HTML_DOCUMENT_NODE:
2349#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002350 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2351 xmlGenericError(xmlGenericErrorContext,
2352 "Failed to save to %s\n", filename);
2353 }
Owen Taylor3473f882001-02-23 17:55:21 +00002354#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002355 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2356 xmlGenericError(xmlGenericErrorContext,
2357 "Failed to save to %s\n", filename);
2358 }
Owen Taylor3473f882001-02-23 17:55:21 +00002359#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002360 break;
2361 default:
2362 xmlGenericError(xmlGenericErrorContext,
2363 "To save to subparts of a document use the 'write' command\n");
2364 return (-1);
2365
Owen Taylor3473f882001-02-23 17:55:21 +00002366 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002367 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002368}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002369#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002370
Daniel Veillardf54cd532004-02-25 11:52:31 +00002371#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002372/**
2373 * xmlShellValidate:
2374 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002375 * @dtd: the DTD URI (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002376 * @node: unused
2377 * @node2: unused
2378 *
2379 * Implements the XML shell function "validate"
2380 * Validate the document, if a DTD path is provided, then the validation
2381 * is done against the given DTD.
2382 *
2383 * Returns 0 or -1 in case of error
2384 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002385int
2386xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2387 xmlNodePtr node ATTRIBUTE_UNUSED,
2388 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2389{
Owen Taylor3473f882001-02-23 17:55:21 +00002390 xmlValidCtxt vctxt;
2391 int res = -1;
2392
2393 vctxt.userData = stderr;
2394 vctxt.error = (xmlValidityErrorFunc) fprintf;
2395 vctxt.warning = (xmlValidityWarningFunc) fprintf;
2396
2397 if ((dtd == NULL) || (dtd[0] == 0)) {
2398 res = xmlValidateDocument(&vctxt, ctxt->doc);
2399 } else {
2400 xmlDtdPtr subset;
2401
Daniel Veillard78d12092001-10-11 09:12:24 +00002402 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2403 if (subset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002404 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2405
Daniel Veillard78d12092001-10-11 09:12:24 +00002406 xmlFreeDtd(subset);
2407 }
Owen Taylor3473f882001-02-23 17:55:21 +00002408 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002409 return (res);
Owen Taylor3473f882001-02-23 17:55:21 +00002410}
Daniel Veillardf54cd532004-02-25 11:52:31 +00002411#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002412
2413/**
2414 * xmlShellDu:
2415 * @ctxt: the shell context
2416 * @arg: unused
2417 * @tree: a node defining a subtree
2418 * @node2: unused
2419 *
2420 * Implements the XML shell function "du"
2421 * show the structure of the subtree under node @tree
2422 * If @tree is null, the command works on the current node.
2423 *
2424 * Returns 0 or -1 in case of error
2425 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002426int
Daniel Veillard321be0c2002-10-08 21:26:42 +00002427xmlShellDu(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00002428 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2429 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2430{
Owen Taylor3473f882001-02-23 17:55:21 +00002431 xmlNodePtr node;
Daniel Veillard78d12092001-10-11 09:12:24 +00002432 int indent = 0, i;
Owen Taylor3473f882001-02-23 17:55:21 +00002433
Daniel Veillard321be0c2002-10-08 21:26:42 +00002434 if (!ctxt)
2435 return (-1);
2436
Daniel Veillard78d12092001-10-11 09:12:24 +00002437 if (tree == NULL)
2438 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002439 node = tree;
2440 while (node != NULL) {
2441 if ((node->type == XML_DOCUMENT_NODE) ||
2442 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002443 fprintf(ctxt->output, "/\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002444 } else if (node->type == XML_ELEMENT_NODE) {
2445 for (i = 0; i < indent; i++)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002446 fprintf(ctxt->output, " ");
2447 fprintf(ctxt->output, "%s\n", node->name);
Daniel Veillard78d12092001-10-11 09:12:24 +00002448 } else {
2449 }
Owen Taylor3473f882001-02-23 17:55:21 +00002450
Daniel Veillard78d12092001-10-11 09:12:24 +00002451 /*
2452 * Browse the full subtree, deep first
2453 */
Owen Taylor3473f882001-02-23 17:55:21 +00002454
2455 if ((node->type == XML_DOCUMENT_NODE) ||
2456 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002457 node = ((xmlDocPtr) node)->children;
2458 } else if ((node->children != NULL)
2459 && (node->type != XML_ENTITY_REF_NODE)) {
2460 /* deep first */
2461 node = node->children;
2462 indent++;
2463 } else if ((node != tree) && (node->next != NULL)) {
2464 /* then siblings */
2465 node = node->next;
2466 } else if (node != tree) {
2467 /* go up to parents->next if needed */
2468 while (node != tree) {
2469 if (node->parent != NULL) {
2470 node = node->parent;
2471 indent--;
2472 }
2473 if ((node != tree) && (node->next != NULL)) {
2474 node = node->next;
2475 break;
2476 }
2477 if (node->parent == NULL) {
2478 node = NULL;
2479 break;
2480 }
2481 if (node == tree) {
2482 node = NULL;
2483 break;
2484 }
2485 }
2486 /* exit condition */
2487 if (node == tree)
2488 node = NULL;
2489 } else
2490 node = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002491 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002492 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002493}
2494
2495/**
2496 * xmlShellPwd:
2497 * @ctxt: the shell context
2498 * @buffer: the output buffer
Daniel Veillard9d06d302002-01-22 18:15:52 +00002499 * @node: a node
Owen Taylor3473f882001-02-23 17:55:21 +00002500 * @node2: unused
2501 *
2502 * Implements the XML shell function "pwd"
2503 * Show the full path from the root to the node, if needed building
2504 * thumblers when similar elements exists at a given ancestor level.
2505 * The output is compatible with XPath commands.
2506 *
2507 * Returns 0 or -1 in case of error
2508 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002509int
2510xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2511 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2512{
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002513 xmlChar *path;
Owen Taylor3473f882001-02-23 17:55:21 +00002514
Daniel Veillard78d12092001-10-11 09:12:24 +00002515 if (node == NULL)
2516 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002517
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002518 path = xmlGetNodePath(node);
2519 if (path == NULL)
2520 return (-1);
2521
2522 /*
2523 * This test prevents buffer overflow, because this routine
2524 * is only called by xmlShell, in which the second argument is
2525 * 500 chars long.
2526 * It is a dirty hack before a cleaner solution is found.
2527 * Documentation should mention that the second argument must
2528 * be at least 500 chars long, and could be stripped if too long.
2529 */
2530 snprintf(buffer, 499, "%s", path);
2531 buffer[499] = '0';
2532 xmlFree(path);
2533
Daniel Veillard78d12092001-10-11 09:12:24 +00002534 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002535}
2536
2537/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002538 * xmlShell:
Owen Taylor3473f882001-02-23 17:55:21 +00002539 * @doc: the initial document
2540 * @filename: the output buffer
2541 * @input: the line reading function
Daniel Veillard321be0c2002-10-08 21:26:42 +00002542 * @output: the output FILE*, defaults to stdout if NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002543 *
2544 * Implements the XML shell
2545 * This allow to load, validate, view, modify and save a document
2546 * using a environment similar to a UNIX commandline.
2547 */
2548void
2549xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
Daniel Veillard78d12092001-10-11 09:12:24 +00002550 FILE * output)
2551{
Owen Taylor3473f882001-02-23 17:55:21 +00002552 char prompt[500] = "/ > ";
2553 char *cmdline = NULL, *cur;
2554 int nbargs;
2555 char command[100];
2556 char arg[400];
2557 int i;
2558 xmlShellCtxtPtr ctxt;
2559 xmlXPathObjectPtr list;
2560
2561 if (doc == NULL)
2562 return;
2563 if (filename == NULL)
2564 return;
2565 if (input == NULL)
2566 return;
2567 if (output == NULL)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002568 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00002569 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
Daniel Veillard78d12092001-10-11 09:12:24 +00002570 if (ctxt == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002571 return;
2572 ctxt->loaded = 0;
2573 ctxt->doc = doc;
2574 ctxt->input = input;
2575 ctxt->output = output;
2576 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
Daniel Veillard78d12092001-10-11 09:12:24 +00002577 ctxt->node = (xmlNodePtr) ctxt->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002578
2579#ifdef LIBXML_XPATH_ENABLED
2580 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2581 if (ctxt->pctxt == NULL) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002582 xmlFree(ctxt);
2583 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002584 }
2585#endif /* LIBXML_XPATH_ENABLED */
2586 while (1) {
2587 if (ctxt->node == (xmlNodePtr) ctxt->doc)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002588 snprintf(prompt, sizeof(prompt), "%s > ", "/");
Daniel Veillard7a985a12003-07-06 17:57:42 +00002589 else if ((ctxt->node != NULL) && (ctxt->node->name))
Daniel Veillard78d12092001-10-11 09:12:24 +00002590 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002591 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002592 snprintf(prompt, sizeof(prompt), "? > ");
Owen Taylor3473f882001-02-23 17:55:21 +00002593 prompt[sizeof(prompt) - 1] = 0;
2594
Daniel Veillard78d12092001-10-11 09:12:24 +00002595 /*
2596 * Get a new command line
2597 */
Owen Taylor3473f882001-02-23 17:55:21 +00002598 cmdline = ctxt->input(prompt);
Daniel Veillard78d12092001-10-11 09:12:24 +00002599 if (cmdline == NULL)
2600 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002601
Daniel Veillard78d12092001-10-11 09:12:24 +00002602 /*
2603 * Parse the command itself
2604 */
2605 cur = cmdline;
2606 nbargs = 0;
2607 while ((*cur == ' ') || (*cur == '\t'))
2608 cur++;
2609 i = 0;
2610 while ((*cur != ' ') && (*cur != '\t') &&
2611 (*cur != '\n') && (*cur != '\r')) {
2612 if (*cur == 0)
2613 break;
2614 command[i++] = *cur++;
2615 }
2616 command[i] = 0;
2617 if (i == 0)
2618 continue;
2619 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002620
Daniel Veillard78d12092001-10-11 09:12:24 +00002621 /*
2622 * Parse the argument
2623 */
2624 while ((*cur == ' ') || (*cur == '\t'))
2625 cur++;
2626 i = 0;
2627 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2628 if (*cur == 0)
2629 break;
2630 arg[i++] = *cur++;
2631 }
2632 arg[i] = 0;
2633 if (i != 0)
2634 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002635
Daniel Veillard78d12092001-10-11 09:12:24 +00002636 /*
2637 * start interpreting the command
2638 */
Owen Taylor3473f882001-02-23 17:55:21 +00002639 if (!strcmp(command, "exit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002640 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002641 if (!strcmp(command, "quit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002642 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002643 if (!strcmp(command, "bye"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002644 break;
Daniel Veillard5004f422001-11-08 13:53:05 +00002645 if (!strcmp(command, "help")) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002646 fprintf(ctxt->output, "\tbase display XML base of the node\n");
2647 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n");
2648 fprintf(ctxt->output, "\tbye leave shell\n");
2649 fprintf(ctxt->output, "\tcat [node] display node or current node\n");
2650 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n");
2651 fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n");
2652 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n");
2653 fprintf(ctxt->output, "\texit leave shell\n");
2654 fprintf(ctxt->output, "\thelp display this help\n");
2655 fprintf(ctxt->output, "\tfree display memory usage\n");
2656 fprintf(ctxt->output, "\tload [name] load a new document with name\n");
2657 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n");
Daniel Veillardc14c3892004-08-16 12:34:50 +00002658 fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n");
Daniel Veillard2070c482002-01-22 22:12:19 +00002659#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002660 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n");
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002661 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n");
2662 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
Daniel Veillard2070c482002-01-22 22:12:19 +00002663#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard321be0c2002-10-08 21:26:42 +00002664 fprintf(ctxt->output, "\tpwd display current working directory\n");
2665 fprintf(ctxt->output, "\tquit leave shell\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002666#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002667 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00002668 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002669#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf54cd532004-02-25 11:52:31 +00002670#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002671 fprintf(ctxt->output, "\tvalidate check the document for errors\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002672#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard522bc602004-02-21 11:53:09 +00002673#ifdef LIBXML_SCHEMAS_ENABLED
2674 fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n");
2675#endif
Daniel Veillard1e208222002-10-22 14:25:25 +00002676 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002677#ifdef LIBXML_VALID_ENABLED
Daniel Veillard5004f422001-11-08 13:53:05 +00002678 } else if (!strcmp(command, "validate")) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002679 xmlShellValidate(ctxt, arg, NULL, NULL);
Daniel Veillardf54cd532004-02-25 11:52:31 +00002680#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002681 } else if (!strcmp(command, "load")) {
2682 xmlShellLoad(ctxt, arg, NULL, NULL);
Daniel Veillard522bc602004-02-21 11:53:09 +00002683#ifdef LIBXML_SCHEMAS_ENABLED
2684 } else if (!strcmp(command, "relaxng")) {
2685 xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2686#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002687#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002688 } else if (!strcmp(command, "save")) {
2689 xmlShellSave(ctxt, arg, NULL, NULL);
2690 } else if (!strcmp(command, "write")) {
2691 xmlShellWrite(ctxt, arg, NULL, NULL);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002692#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard1e208222002-10-22 14:25:25 +00002693 } else if (!strcmp(command, "grep")) {
2694 xmlShellGrep(ctxt, arg, ctxt->node, NULL);
Daniel Veillard78d12092001-10-11 09:12:24 +00002695 } else if (!strcmp(command, "free")) {
2696 if (arg[0] == 0) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002697 xmlMemShow(ctxt->output, 0);
Daniel Veillard78d12092001-10-11 09:12:24 +00002698 } else {
2699 int len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002700
Daniel Veillard78d12092001-10-11 09:12:24 +00002701 sscanf(arg, "%d", &len);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002702 xmlMemShow(ctxt->output, len);
Daniel Veillard78d12092001-10-11 09:12:24 +00002703 }
2704 } else if (!strcmp(command, "pwd")) {
2705 char dir[500];
Owen Taylor3473f882001-02-23 17:55:21 +00002706
Daniel Veillard78d12092001-10-11 09:12:24 +00002707 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
Daniel Veillard321be0c2002-10-08 21:26:42 +00002708 fprintf(ctxt->output, "%s\n", dir);
Daniel Veillard78d12092001-10-11 09:12:24 +00002709 } else if (!strcmp(command, "du")) {
2710 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2711 } else if (!strcmp(command, "base")) {
2712 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
Daniel Veillard29b17482004-08-16 00:39:03 +00002713 } else if (!strcmp(command, "set")) {
2714 xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2070c482002-01-22 22:12:19 +00002715#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002716 } else if (!strcmp(command, "setns")) {
2717 if (arg[0] == 0) {
2718 xmlGenericError(xmlGenericErrorContext,
2719 "setns: prefix=[nsuri] required\n");
2720 } else {
2721 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
2722 }
Daniel Veillard2070c482002-01-22 22:12:19 +00002723 } else if (!strcmp(command, "xpath")) {
2724 if (arg[0] == 0) {
2725 xmlGenericError(xmlGenericErrorContext,
2726 "xpath: expression required\n");
2727 } else {
2728 ctxt->pctxt->node = ctxt->node;
2729 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002730 xmlXPathDebugDumpObject(ctxt->output, list, 0);
Daniel Veillard2070c482002-01-22 22:12:19 +00002731 xmlXPathFreeObject(list);
2732 }
2733#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard2156d432004-03-04 15:59:36 +00002734#ifdef LIBXML_TREE_ENABLED
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002735 } else if (!strcmp(command, "setbase")) {
2736 xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2156d432004-03-04 15:59:36 +00002737#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002738 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2739 int dir = (!strcmp(command, "dir"));
2740
2741 if (arg[0] == 0) {
2742 if (dir)
2743 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
2744 else
2745 xmlShellList(ctxt, NULL, ctxt->node, NULL);
2746 } else {
2747 ctxt->pctxt->node = ctxt->node;
Daniel Veillard61d80a22001-04-27 17:13:01 +00002748#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002749 ctxt->pctxt->node = ctxt->node;
2750 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2751#else
2752 list = NULL;
2753#endif /* LIBXML_XPATH_ENABLED */
2754 if (list != NULL) {
2755 switch (list->type) {
2756 case XPATH_UNDEFINED:
2757 xmlGenericError(xmlGenericErrorContext,
2758 "%s: no such node\n", arg);
2759 break;
2760 case XPATH_NODESET:{
2761 int indx;
2762
Daniel Veillarda6825e82001-11-07 13:33:59 +00002763 if (list->nodesetval == NULL)
2764 break;
2765
Daniel Veillard78d12092001-10-11 09:12:24 +00002766 for (indx = 0;
2767 indx < list->nodesetval->nodeNr;
2768 indx++) {
2769 if (dir)
2770 xmlShellDir(ctxt, NULL,
2771 list->nodesetval->
2772 nodeTab[indx], NULL);
2773 else
2774 xmlShellList(ctxt, NULL,
2775 list->nodesetval->
2776 nodeTab[indx], NULL);
2777 }
2778 break;
2779 }
2780 case XPATH_BOOLEAN:
2781 xmlGenericError(xmlGenericErrorContext,
2782 "%s is a Boolean\n", arg);
2783 break;
2784 case XPATH_NUMBER:
2785 xmlGenericError(xmlGenericErrorContext,
2786 "%s is a number\n", arg);
2787 break;
2788 case XPATH_STRING:
2789 xmlGenericError(xmlGenericErrorContext,
2790 "%s is a string\n", arg);
2791 break;
2792 case XPATH_POINT:
2793 xmlGenericError(xmlGenericErrorContext,
2794 "%s is a point\n", arg);
2795 break;
2796 case XPATH_RANGE:
2797 xmlGenericError(xmlGenericErrorContext,
2798 "%s is a range\n", arg);
2799 break;
2800 case XPATH_LOCATIONSET:
2801 xmlGenericError(xmlGenericErrorContext,
2802 "%s is a range\n", arg);
2803 break;
2804 case XPATH_USERS:
2805 xmlGenericError(xmlGenericErrorContext,
2806 "%s is user-defined\n", arg);
2807 break;
2808 case XPATH_XSLT_TREE:
2809 xmlGenericError(xmlGenericErrorContext,
2810 "%s is an XSLT value tree\n",
2811 arg);
2812 break;
2813 }
2814#ifdef LIBXML_XPATH_ENABLED
2815 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00002816#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002817 } else {
2818 xmlGenericError(xmlGenericErrorContext,
2819 "%s: no such node\n", arg);
2820 }
2821 ctxt->pctxt->node = NULL;
2822 }
2823 } else if (!strcmp(command, "cd")) {
2824 if (arg[0] == 0) {
2825 ctxt->node = (xmlNodePtr) ctxt->doc;
2826 } else {
2827#ifdef LIBXML_XPATH_ENABLED
2828 ctxt->pctxt->node = ctxt->node;
2829 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2830#else
2831 list = NULL;
2832#endif /* LIBXML_XPATH_ENABLED */
2833 if (list != NULL) {
2834 switch (list->type) {
2835 case XPATH_UNDEFINED:
2836 xmlGenericError(xmlGenericErrorContext,
2837 "%s: no such node\n", arg);
2838 break;
2839 case XPATH_NODESET:
Daniel Veillarda6825e82001-11-07 13:33:59 +00002840 if (list->nodesetval != NULL) {
2841 if (list->nodesetval->nodeNr == 1) {
2842 ctxt->node = list->nodesetval->nodeTab[0];
Daniel Veillard7a985a12003-07-06 17:57:42 +00002843 if ((ctxt->node != NULL) &&
2844 (ctxt->node->type ==
2845 XML_NAMESPACE_DECL)) {
2846 xmlGenericError(xmlGenericErrorContext,
2847 "cannot cd to namespace\n");
2848 ctxt->node = NULL;
2849 }
Daniel Veillarda6825e82001-11-07 13:33:59 +00002850 } else
2851 xmlGenericError(xmlGenericErrorContext,
2852 "%s is a %d Node Set\n",
2853 arg,
2854 list->nodesetval->nodeNr);
Daniel Veillard78d12092001-10-11 09:12:24 +00002855 } else
2856 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6825e82001-11-07 13:33:59 +00002857 "%s is an empty Node Set\n",
2858 arg);
Daniel Veillard78d12092001-10-11 09:12:24 +00002859 break;
2860 case XPATH_BOOLEAN:
2861 xmlGenericError(xmlGenericErrorContext,
2862 "%s is a Boolean\n", arg);
2863 break;
2864 case XPATH_NUMBER:
2865 xmlGenericError(xmlGenericErrorContext,
2866 "%s is a number\n", arg);
2867 break;
2868 case XPATH_STRING:
2869 xmlGenericError(xmlGenericErrorContext,
2870 "%s is a string\n", arg);
2871 break;
2872 case XPATH_POINT:
2873 xmlGenericError(xmlGenericErrorContext,
2874 "%s is a point\n", arg);
2875 break;
2876 case XPATH_RANGE:
2877 xmlGenericError(xmlGenericErrorContext,
2878 "%s is a range\n", arg);
2879 break;
2880 case XPATH_LOCATIONSET:
2881 xmlGenericError(xmlGenericErrorContext,
2882 "%s is a range\n", arg);
2883 break;
2884 case XPATH_USERS:
2885 xmlGenericError(xmlGenericErrorContext,
2886 "%s is user-defined\n", arg);
2887 break;
2888 case XPATH_XSLT_TREE:
2889 xmlGenericError(xmlGenericErrorContext,
2890 "%s is an XSLT value tree\n",
2891 arg);
2892 break;
2893 }
2894#ifdef LIBXML_XPATH_ENABLED
2895 xmlXPathFreeObject(list);
2896#endif
2897 } else {
2898 xmlGenericError(xmlGenericErrorContext,
2899 "%s: no such node\n", arg);
2900 }
2901 ctxt->pctxt->node = NULL;
2902 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002903#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002904 } else if (!strcmp(command, "cat")) {
2905 if (arg[0] == 0) {
2906 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
2907 } else {
2908 ctxt->pctxt->node = ctxt->node;
2909#ifdef LIBXML_XPATH_ENABLED
2910 ctxt->pctxt->node = ctxt->node;
2911 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2912#else
2913 list = NULL;
2914#endif /* LIBXML_XPATH_ENABLED */
2915 if (list != NULL) {
2916 switch (list->type) {
2917 case XPATH_UNDEFINED:
2918 xmlGenericError(xmlGenericErrorContext,
2919 "%s: no such node\n", arg);
2920 break;
2921 case XPATH_NODESET:{
2922 int indx;
2923
Daniel Veillarda6825e82001-11-07 13:33:59 +00002924 if (list->nodesetval == NULL)
2925 break;
2926
Daniel Veillard78d12092001-10-11 09:12:24 +00002927 for (indx = 0;
2928 indx < list->nodesetval->nodeNr;
2929 indx++) {
2930 if (i > 0)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002931 fprintf(ctxt->output, " -------\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002932 xmlShellCat(ctxt, NULL,
2933 list->nodesetval->
2934 nodeTab[indx], NULL);
2935 }
2936 break;
2937 }
2938 case XPATH_BOOLEAN:
2939 xmlGenericError(xmlGenericErrorContext,
2940 "%s is a Boolean\n", arg);
2941 break;
2942 case XPATH_NUMBER:
2943 xmlGenericError(xmlGenericErrorContext,
2944 "%s is a number\n", arg);
2945 break;
2946 case XPATH_STRING:
2947 xmlGenericError(xmlGenericErrorContext,
2948 "%s is a string\n", arg);
2949 break;
2950 case XPATH_POINT:
2951 xmlGenericError(xmlGenericErrorContext,
2952 "%s is a point\n", arg);
2953 break;
2954 case XPATH_RANGE:
2955 xmlGenericError(xmlGenericErrorContext,
2956 "%s is a range\n", arg);
2957 break;
2958 case XPATH_LOCATIONSET:
2959 xmlGenericError(xmlGenericErrorContext,
2960 "%s is a range\n", arg);
2961 break;
2962 case XPATH_USERS:
2963 xmlGenericError(xmlGenericErrorContext,
2964 "%s is user-defined\n", arg);
2965 break;
2966 case XPATH_XSLT_TREE:
2967 xmlGenericError(xmlGenericErrorContext,
2968 "%s is an XSLT value tree\n",
2969 arg);
2970 break;
2971 }
2972#ifdef LIBXML_XPATH_ENABLED
2973 xmlXPathFreeObject(list);
2974#endif
2975 } else {
2976 xmlGenericError(xmlGenericErrorContext,
2977 "%s: no such node\n", arg);
2978 }
2979 ctxt->pctxt->node = NULL;
2980 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002981#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002982 } else {
2983 xmlGenericError(xmlGenericErrorContext,
2984 "Unknown command %s\n", command);
2985 }
2986 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00002987 }
2988#ifdef LIBXML_XPATH_ENABLED
2989 xmlXPathFreeContext(ctxt->pctxt);
2990#endif /* LIBXML_XPATH_ENABLED */
2991 if (ctxt->loaded) {
2992 xmlFreeDoc(ctxt->doc);
2993 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002994 if (ctxt->filename != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002995 xmlFree(ctxt->filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002996 xmlFree(ctxt);
2997 if (cmdline != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002998 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00002999}
3000
3001#endif /* LIBXML_DEBUG_ENABLED */