1 /*
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 *
7 * Daniel Veillard <daniel@veillard.com>
8 */
9
10 #define IN_LIBXML
11 #include "libxml.h"
12 #ifdef LIBXML_DEBUG_ENABLED
13
14 #include <string.h>
15 #include <stdlib.h>
16
17 #include <libxml/xmlmemory.h>
18 #include <libxml/tree.h>
19 #include <libxml/parser.h>
20 #include <libxml/parserInternals.h>
21 #include <libxml/debugXML.h>
22 #include <libxml/HTMLtree.h>
23 #include <libxml/HTMLparser.h>
24 #include <libxml/xmlerror.h>
25 #include <libxml/xpathInternals.h>
26 #include <libxml/uri.h>
27 #ifdef LIBXML_SCHEMAS_ENABLED
28 #include <libxml/relaxng.h>
29 #endif
30
31 #include "private/error.h"
32
33 #define DUMP_TEXT_TYPE 1
34
35 typedef struct _xmlDebugCtxt xmlDebugCtxt;
36 typedef xmlDebugCtxt *xmlDebugCtxtPtr;
37 struct _xmlDebugCtxt {
38 FILE *output; /* the output file */
39 char shift[101]; /* used for indenting */
40 int depth; /* current depth */
41 xmlDocPtr doc; /* current document */
42 xmlNodePtr node; /* current node */
43 xmlDictPtr dict; /* the doc dictionary */
44 int check; /* do just checkings */
45 int errors; /* number of errors found */
46 int nodict; /* if the document has no dictionary */
47 int options; /* options */
48 };
49
50 static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
51
52 static void
xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)53 xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
54 {
55 int i;
56
57 ctxt->depth = 0;
58 ctxt->check = 0;
59 ctxt->errors = 0;
60 ctxt->output = stdout;
61 ctxt->doc = NULL;
62 ctxt->node = NULL;
63 ctxt->dict = NULL;
64 ctxt->nodict = 0;
65 ctxt->options = 0;
66 for (i = 0; i < 100; i++)
67 ctxt->shift[i] = ' ';
68 ctxt->shift[100] = 0;
69 }
70
71 static void
xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)72 xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)
73 {
74 /* remove the ATTRIBUTE_UNUSED when this is added */
75 }
76
77 /**
78 * xmlNsCheckScope:
79 * @node: the node
80 * @ns: the namespace node
81 *
82 * Check that a given namespace is in scope on a node.
83 *
84 * Returns 1 if in scope, -1 in case of argument error,
85 * -2 if the namespace is not in scope, and -3 if not on
86 * an ancestor node.
87 */
88 static int
xmlNsCheckScope(xmlNodePtr node,xmlNsPtr ns)89 xmlNsCheckScope(xmlNodePtr node, xmlNsPtr ns)
90 {
91 xmlNsPtr cur;
92
93 if ((node == NULL) || (ns == NULL))
94 return(-1);
95
96 if ((node->type != XML_ELEMENT_NODE) &&
97 (node->type != XML_ATTRIBUTE_NODE) &&
98 (node->type != XML_DOCUMENT_NODE) &&
99 (node->type != XML_TEXT_NODE) &&
100 (node->type != XML_HTML_DOCUMENT_NODE) &&
101 (node->type != XML_XINCLUDE_START))
102 return(-2);
103
104 while ((node != NULL) &&
105 ((node->type == XML_ELEMENT_NODE) ||
106 (node->type == XML_ATTRIBUTE_NODE) ||
107 (node->type == XML_TEXT_NODE) ||
108 (node->type == XML_XINCLUDE_START))) {
109 if ((node->type == XML_ELEMENT_NODE) ||
110 (node->type == XML_XINCLUDE_START)) {
111 cur = node->nsDef;
112 while (cur != NULL) {
113 if (cur == ns)
114 return(1);
115 if (xmlStrEqual(cur->prefix, ns->prefix))
116 return(-2);
117 cur = cur->next;
118 }
119 }
120 node = node->parent;
121 }
122 /* the xml namespace may be declared on the document node */
123 if ((node != NULL) &&
124 ((node->type == XML_DOCUMENT_NODE) ||
125 (node->type == XML_HTML_DOCUMENT_NODE))) {
126 xmlNsPtr oldNs = ((xmlDocPtr) node)->oldNs;
127 if (oldNs == ns)
128 return(1);
129 }
130 return(-3);
131 }
132
133 static void
xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)134 xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
135 {
136 if (ctxt->check)
137 return;
138 if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
139 if (ctxt->depth < 50)
140 fprintf(ctxt->output, "%s", &ctxt->shift[100 - 2 * ctxt->depth]);
141 else
142 fprintf(ctxt->output, "%s", ctxt->shift);
143 }
144 }
145
146 /**
147 * xmlDebugErr:
148 * @ctxt: a debug context
149 * @error: the error code
150 *
151 * Handle a debug error.
152 */
153 static void
xmlDebugErr(xmlDebugCtxtPtr ctxt,int error,const char * msg)154 xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
155 {
156 ctxt->errors++;
157 fprintf(ctxt->output, "ERROR %d: %s", error, msg);
158 }
159 static void LIBXML_ATTR_FORMAT(3,0)
xmlDebugErr2(xmlDebugCtxtPtr ctxt,int error,const char * msg,int extra)160 xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra)
161 {
162 ctxt->errors++;
163 fprintf(ctxt->output, "ERROR %d: ", error);
164 fprintf(ctxt->output, msg, extra);
165 }
166 static void LIBXML_ATTR_FORMAT(3,0)
xmlDebugErr3(xmlDebugCtxtPtr ctxt,int error,const char * msg,const char * extra)167 xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, const char *extra)
168 {
169 ctxt->errors++;
170 fprintf(ctxt->output, "ERROR %d: ", error);
171 fprintf(ctxt->output, msg, extra);
172 }
173
174 /**
175 * xmlCtxtNsCheckScope:
176 * @ctxt: the debugging context
177 * @node: the node
178 * @ns: the namespace node
179 *
180 * Report if a given namespace is is not in scope.
181 */
182 static void
xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt,xmlNodePtr node,xmlNsPtr ns)183 xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt, xmlNodePtr node, xmlNsPtr ns)
184 {
185 int ret;
186
187 ret = xmlNsCheckScope(node, ns);
188 if (ret == -2) {
189 if (ns->prefix == NULL)
190 xmlDebugErr(ctxt, XML_CHECK_NS_SCOPE,
191 "Reference to default namespace not in scope\n");
192 else
193 xmlDebugErr3(ctxt, XML_CHECK_NS_SCOPE,
194 "Reference to namespace '%s' not in scope\n",
195 (char *) ns->prefix);
196 }
197 if (ret == -3) {
198 if (ns->prefix == NULL)
199 xmlDebugErr(ctxt, XML_CHECK_NS_ANCESTOR,
200 "Reference to default namespace not on ancestor\n");
201 else
202 xmlDebugErr3(ctxt, XML_CHECK_NS_ANCESTOR,
203 "Reference to namespace '%s' not on ancestor\n",
204 (char *) ns->prefix);
205 }
206 }
207
208 /**
209 * xmlCtxtCheckString:
210 * @ctxt: the debug context
211 * @str: the string
212 *
213 * Do debugging on the string, currently it just checks the UTF-8 content
214 */
215 static void
xmlCtxtCheckString(xmlDebugCtxtPtr ctxt,const xmlChar * str)216 xmlCtxtCheckString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
217 {
218 if (str == NULL) return;
219 if (ctxt->check) {
220 if (!xmlCheckUTF8(str)) {
221 xmlDebugErr3(ctxt, XML_CHECK_NOT_UTF8,
222 "String is not UTF-8 %s", (const char *) str);
223 }
224 }
225 }
226
227 /**
228 * xmlCtxtCheckName:
229 * @ctxt: the debug context
230 * @name: the name
231 *
232 * Do debugging on the name, for example the dictionary status and
233 * conformance to the Name production.
234 */
235 static void
xmlCtxtCheckName(xmlDebugCtxtPtr ctxt,const xmlChar * name)236 xmlCtxtCheckName(xmlDebugCtxtPtr ctxt, const xmlChar * name)
237 {
238 if (ctxt->check) {
239 if (name == NULL) {
240 xmlDebugErr(ctxt, XML_CHECK_NO_NAME, "Name is NULL");
241 return;
242 }
243 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
244 if (xmlValidateName(name, 0)) {
245 xmlDebugErr3(ctxt, XML_CHECK_NOT_NCNAME,
246 "Name is not an NCName '%s'", (const char *) name);
247 }
248 #endif
249 if ((ctxt->dict != NULL) &&
250 (!xmlDictOwns(ctxt->dict, name)) &&
251 ((ctxt->doc == NULL) ||
252 ((ctxt->doc->parseFlags & (XML_PARSE_SAX1 | XML_PARSE_NODICT)) == 0))) {
253 xmlDebugErr3(ctxt, XML_CHECK_OUTSIDE_DICT,
254 "Name is not from the document dictionary '%s'",
255 (const char *) name);
256 }
257 }
258 }
259
260 static void
xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt,xmlNodePtr node)261 xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
262 xmlDocPtr doc;
263 xmlDictPtr dict;
264
265 doc = node->doc;
266
267 if (node->parent == NULL)
268 xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
269 "Node has no parent\n");
270 if (node->doc == NULL) {
271 xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
272 "Node has no doc\n");
273 dict = NULL;
274 } else {
275 dict = doc->dict;
276 if ((dict == NULL) && (ctxt->nodict == 0)) {
277 #if 0
278 /* deactivated right now as it raises too many errors */
279 if (doc->type == XML_DOCUMENT_NODE)
280 xmlDebugErr(ctxt, XML_CHECK_NO_DICT,
281 "Document has no dictionary\n");
282 #endif
283 ctxt->nodict = 1;
284 }
285 if (ctxt->doc == NULL)
286 ctxt->doc = doc;
287
288 if (ctxt->dict == NULL) {
289 ctxt->dict = dict;
290 }
291 }
292 if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
293 (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
294 xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
295 "Node doc differs from parent's one\n");
296 if (node->prev == NULL) {
297 if (node->type == XML_ATTRIBUTE_NODE) {
298 if ((node->parent != NULL) &&
299 (node != (xmlNodePtr) node->parent->properties))
300 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
301 "Attr has no prev and not first of attr list\n");
302
303 } else if ((node->parent != NULL) && (node->parent->children != node))
304 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
305 "Node has no prev and not first of parent list\n");
306 } else {
307 if (node->prev->next != node)
308 xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
309 "Node prev->next : back link wrong\n");
310 }
311 if (node->next == NULL) {
312 if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
313 (node->parent->last != node) &&
314 (node->parent->type == XML_ELEMENT_NODE))
315 xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
316 "Node has no next and not last of parent list\n");
317 } else {
318 if (node->next->prev != node)
319 xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
320 "Node next->prev : forward link wrong\n");
321 if (node->next->parent != node->parent)
322 xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT,
323 "Node next->prev : forward link wrong\n");
324 }
325 if (node->type == XML_ELEMENT_NODE) {
326 xmlNsPtr ns;
327
328 ns = node->nsDef;
329 while (ns != NULL) {
330 xmlCtxtNsCheckScope(ctxt, node, ns);
331 ns = ns->next;
332 }
333 if (node->ns != NULL)
334 xmlCtxtNsCheckScope(ctxt, node, node->ns);
335 } else if (node->type == XML_ATTRIBUTE_NODE) {
336 if (node->ns != NULL)
337 xmlCtxtNsCheckScope(ctxt, node, node->ns);
338 }
339
340 if ((node->type != XML_ELEMENT_NODE) &&
341 (node->type != XML_ATTRIBUTE_NODE) &&
342 (node->type != XML_ELEMENT_DECL) &&
343 (node->type != XML_ATTRIBUTE_DECL) &&
344 (node->type != XML_DTD_NODE) &&
345 (node->type != XML_HTML_DOCUMENT_NODE) &&
346 (node->type != XML_DOCUMENT_NODE)) {
347 if (node->content != NULL)
348 xmlCtxtCheckString(ctxt, (const xmlChar *) node->content);
349 }
350 switch (node->type) {
351 case XML_ELEMENT_NODE:
352 case XML_ATTRIBUTE_NODE:
353 xmlCtxtCheckName(ctxt, node->name);
354 break;
355 case XML_TEXT_NODE:
356 if ((node->name == xmlStringText) ||
357 (node->name == xmlStringTextNoenc))
358 break;
359 /* some case of entity substitution can lead to this */
360 if ((ctxt->dict != NULL) &&
361 (node->name == xmlDictLookup(ctxt->dict, BAD_CAST "nbktext",
362 7)))
363 break;
364
365 xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
366 "Text node has wrong name '%s'",
367 (const char *) node->name);
368 break;
369 case XML_COMMENT_NODE:
370 if (node->name == xmlStringComment)
371 break;
372 xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
373 "Comment node has wrong name '%s'",
374 (const char *) node->name);
375 break;
376 case XML_PI_NODE:
377 xmlCtxtCheckName(ctxt, node->name);
378 break;
379 case XML_CDATA_SECTION_NODE:
380 if (node->name == NULL)
381 break;
382 xmlDebugErr3(ctxt, XML_CHECK_NAME_NOT_NULL,
383 "CData section has non NULL name '%s'",
384 (const char *) node->name);
385 break;
386 case XML_ENTITY_REF_NODE:
387 case XML_ENTITY_NODE:
388 case XML_DOCUMENT_TYPE_NODE:
389 case XML_DOCUMENT_FRAG_NODE:
390 case XML_NOTATION_NODE:
391 case XML_DTD_NODE:
392 case XML_ELEMENT_DECL:
393 case XML_ATTRIBUTE_DECL:
394 case XML_ENTITY_DECL:
395 case XML_NAMESPACE_DECL:
396 case XML_XINCLUDE_START:
397 case XML_XINCLUDE_END:
398 case XML_DOCUMENT_NODE:
399 case XML_HTML_DOCUMENT_NODE:
400 break;
401 }
402 }
403
404 static void
xmlCtxtDumpString(xmlDebugCtxtPtr ctxt,const xmlChar * str)405 xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
406 {
407 int i;
408
409 if (ctxt->check) {
410 return;
411 }
412 /* TODO: check UTF8 content of the string */
413 if (str == NULL) {
414 fprintf(ctxt->output, "(NULL)");
415 return;
416 }
417 for (i = 0; i < 40; i++)
418 if (str[i] == 0)
419 return;
420 else if (IS_BLANK_CH(str[i]))
421 fputc(' ', ctxt->output);
422 else if (str[i] >= 0x80)
423 fprintf(ctxt->output, "#%X", str[i]);
424 else
425 fputc(str[i], ctxt->output);
426 fprintf(ctxt->output, "...");
427 }
428
429 static void
xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)430 xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
431 {
432 xmlCtxtDumpSpaces(ctxt);
433
434 if (dtd == NULL) {
435 if (!ctxt->check)
436 fprintf(ctxt->output, "DTD node is NULL\n");
437 return;
438 }
439
440 if (dtd->type != XML_DTD_NODE) {
441 xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
442 "Node is not a DTD");
443 return;
444 }
445 if (!ctxt->check) {
446 if (dtd->name != NULL)
447 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
448 else
449 fprintf(ctxt->output, "DTD");
450 if (dtd->ExternalID != NULL)
451 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
452 if (dtd->SystemID != NULL)
453 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
454 fprintf(ctxt->output, "\n");
455 }
456 /*
457 * Do a bit of checking
458 */
459 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
460 }
461
462 static void
xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt,xmlAttributePtr attr)463 xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
464 {
465 xmlCtxtDumpSpaces(ctxt);
466
467 if (attr == NULL) {
468 if (!ctxt->check)
469 fprintf(ctxt->output, "Attribute declaration is NULL\n");
470 return;
471 }
472 if (attr->type != XML_ATTRIBUTE_DECL) {
473 xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
474 "Node is not an attribute declaration");
475 return;
476 }
477 if (attr->name != NULL) {
478 if (!ctxt->check)
479 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
480 } else
481 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
482 "Node attribute declaration has no name");
483 if (attr->elem != NULL) {
484 if (!ctxt->check)
485 fprintf(ctxt->output, " for %s", (char *) attr->elem);
486 } else
487 xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
488 "Node attribute declaration has no element name");
489 if (!ctxt->check) {
490 switch (attr->atype) {
491 case XML_ATTRIBUTE_CDATA:
492 fprintf(ctxt->output, " CDATA");
493 break;
494 case XML_ATTRIBUTE_ID:
495 fprintf(ctxt->output, " ID");
496 break;
497 case XML_ATTRIBUTE_IDREF:
498 fprintf(ctxt->output, " IDREF");
499 break;
500 case XML_ATTRIBUTE_IDREFS:
501 fprintf(ctxt->output, " IDREFS");
502 break;
503 case XML_ATTRIBUTE_ENTITY:
504 fprintf(ctxt->output, " ENTITY");
505 break;
506 case XML_ATTRIBUTE_ENTITIES:
507 fprintf(ctxt->output, " ENTITIES");
508 break;
509 case XML_ATTRIBUTE_NMTOKEN:
510 fprintf(ctxt->output, " NMTOKEN");
511 break;
512 case XML_ATTRIBUTE_NMTOKENS:
513 fprintf(ctxt->output, " NMTOKENS");
514 break;
515 case XML_ATTRIBUTE_ENUMERATION:
516 fprintf(ctxt->output, " ENUMERATION");
517 break;
518 case XML_ATTRIBUTE_NOTATION:
519 fprintf(ctxt->output, " NOTATION ");
520 break;
521 }
522 if (attr->tree != NULL) {
523 int indx;
524 xmlEnumerationPtr cur = attr->tree;
525
526 for (indx = 0; indx < 5; indx++) {
527 if (indx != 0)
528 fprintf(ctxt->output, "|%s", (char *) cur->name);
529 else
530 fprintf(ctxt->output, " (%s", (char *) cur->name);
531 cur = cur->next;
532 if (cur == NULL)
533 break;
534 }
535 if (cur == NULL)
536 fprintf(ctxt->output, ")");
537 else
538 fprintf(ctxt->output, "...)");
539 }
540 switch (attr->def) {
541 case XML_ATTRIBUTE_NONE:
542 break;
543 case XML_ATTRIBUTE_REQUIRED:
544 fprintf(ctxt->output, " REQUIRED");
545 break;
546 case XML_ATTRIBUTE_IMPLIED:
547 fprintf(ctxt->output, " IMPLIED");
548 break;
549 case XML_ATTRIBUTE_FIXED:
550 fprintf(ctxt->output, " FIXED");
551 break;
552 }
553 if (attr->defaultValue != NULL) {
554 fprintf(ctxt->output, "\"");
555 xmlCtxtDumpString(ctxt, attr->defaultValue);
556 fprintf(ctxt->output, "\"");
557 }
558 fprintf(ctxt->output, "\n");
559 }
560
561 /*
562 * Do a bit of checking
563 */
564 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
565 }
566
567 static void
xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt,xmlElementPtr elem)568 xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
569 {
570 xmlCtxtDumpSpaces(ctxt);
571
572 if (elem == NULL) {
573 if (!ctxt->check)
574 fprintf(ctxt->output, "Element declaration is NULL\n");
575 return;
576 }
577 if (elem->type != XML_ELEMENT_DECL) {
578 xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
579 "Node is not an element declaration");
580 return;
581 }
582 if (elem->name != NULL) {
583 if (!ctxt->check) {
584 fprintf(ctxt->output, "ELEMDECL(");
585 xmlCtxtDumpString(ctxt, elem->name);
586 fprintf(ctxt->output, ")");
587 }
588 } else
589 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
590 "Element declaration has no name");
591 if (!ctxt->check) {
592 switch (elem->etype) {
593 case XML_ELEMENT_TYPE_UNDEFINED:
594 fprintf(ctxt->output, ", UNDEFINED");
595 break;
596 case XML_ELEMENT_TYPE_EMPTY:
597 fprintf(ctxt->output, ", EMPTY");
598 break;
599 case XML_ELEMENT_TYPE_ANY:
600 fprintf(ctxt->output, ", ANY");
601 break;
602 case XML_ELEMENT_TYPE_MIXED:
603 fprintf(ctxt->output, ", MIXED ");
604 break;
605 case XML_ELEMENT_TYPE_ELEMENT:
606 fprintf(ctxt->output, ", MIXED ");
607 break;
608 }
609 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
610 char buf[5001];
611
612 buf[0] = 0;
613 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
614 buf[5000] = 0;
615 fprintf(ctxt->output, "%s", buf);
616 }
617 fprintf(ctxt->output, "\n");
618 }
619
620 /*
621 * Do a bit of checking
622 */
623 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
624 }
625
626 static void
xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)627 xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
628 {
629 xmlCtxtDumpSpaces(ctxt);
630
631 if (ent == NULL) {
632 if (!ctxt->check)
633 fprintf(ctxt->output, "Entity declaration is NULL\n");
634 return;
635 }
636 if (ent->type != XML_ENTITY_DECL) {
637 xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
638 "Node is not an entity declaration");
639 return;
640 }
641 if (ent->name != NULL) {
642 if (!ctxt->check) {
643 fprintf(ctxt->output, "ENTITYDECL(");
644 xmlCtxtDumpString(ctxt, ent->name);
645 fprintf(ctxt->output, ")");
646 }
647 } else
648 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
649 "Entity declaration has no name");
650 if (!ctxt->check) {
651 switch (ent->etype) {
652 case XML_INTERNAL_GENERAL_ENTITY:
653 fprintf(ctxt->output, ", internal\n");
654 break;
655 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
656 fprintf(ctxt->output, ", external parsed\n");
657 break;
658 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
659 fprintf(ctxt->output, ", unparsed\n");
660 break;
661 case XML_INTERNAL_PARAMETER_ENTITY:
662 fprintf(ctxt->output, ", parameter\n");
663 break;
664 case XML_EXTERNAL_PARAMETER_ENTITY:
665 fprintf(ctxt->output, ", external parameter\n");
666 break;
667 case XML_INTERNAL_PREDEFINED_ENTITY:
668 fprintf(ctxt->output, ", predefined\n");
669 break;
670 }
671 if (ent->ExternalID) {
672 xmlCtxtDumpSpaces(ctxt);
673 fprintf(ctxt->output, " ExternalID=%s\n",
674 (char *) ent->ExternalID);
675 }
676 if (ent->SystemID) {
677 xmlCtxtDumpSpaces(ctxt);
678 fprintf(ctxt->output, " SystemID=%s\n",
679 (char *) ent->SystemID);
680 }
681 if (ent->URI != NULL) {
682 xmlCtxtDumpSpaces(ctxt);
683 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
684 }
685 if (ent->content) {
686 xmlCtxtDumpSpaces(ctxt);
687 fprintf(ctxt->output, " content=");
688 xmlCtxtDumpString(ctxt, ent->content);
689 fprintf(ctxt->output, "\n");
690 }
691 }
692
693 /*
694 * Do a bit of checking
695 */
696 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
697 }
698
699 static void
xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)700 xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
701 {
702 xmlCtxtDumpSpaces(ctxt);
703
704 if (ns == NULL) {
705 if (!ctxt->check)
706 fprintf(ctxt->output, "namespace node is NULL\n");
707 return;
708 }
709 if (ns->type != XML_NAMESPACE_DECL) {
710 xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
711 "Node is not a namespace declaration");
712 return;
713 }
714 if (ns->href == NULL) {
715 if (ns->prefix != NULL)
716 xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
717 "Incomplete namespace %s href=NULL\n",
718 (char *) ns->prefix);
719 else
720 xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
721 "Incomplete default namespace href=NULL\n");
722 } else {
723 if (!ctxt->check) {
724 if (ns->prefix != NULL)
725 fprintf(ctxt->output, "namespace %s href=",
726 (char *) ns->prefix);
727 else
728 fprintf(ctxt->output, "default namespace href=");
729
730 xmlCtxtDumpString(ctxt, ns->href);
731 fprintf(ctxt->output, "\n");
732 }
733 }
734 }
735
736 static void
xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)737 xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
738 {
739 while (ns != NULL) {
740 xmlCtxtDumpNamespace(ctxt, ns);
741 ns = ns->next;
742 }
743 }
744
745 static void
xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)746 xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
747 {
748 xmlCtxtDumpSpaces(ctxt);
749
750 if (ent == NULL) {
751 if (!ctxt->check)
752 fprintf(ctxt->output, "Entity is NULL\n");
753 return;
754 }
755 if (!ctxt->check) {
756 switch (ent->etype) {
757 case XML_INTERNAL_GENERAL_ENTITY:
758 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
759 break;
760 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
761 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
762 break;
763 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
764 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
765 break;
766 case XML_INTERNAL_PARAMETER_ENTITY:
767 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
768 break;
769 case XML_EXTERNAL_PARAMETER_ENTITY:
770 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
771 break;
772 default:
773 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
774 }
775 fprintf(ctxt->output, "%s\n", ent->name);
776 if (ent->ExternalID) {
777 xmlCtxtDumpSpaces(ctxt);
778 fprintf(ctxt->output, "ExternalID=%s\n",
779 (char *) ent->ExternalID);
780 }
781 if (ent->SystemID) {
782 xmlCtxtDumpSpaces(ctxt);
783 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
784 }
785 if (ent->URI) {
786 xmlCtxtDumpSpaces(ctxt);
787 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
788 }
789 if (ent->content) {
790 xmlCtxtDumpSpaces(ctxt);
791 fprintf(ctxt->output, "content=");
792 xmlCtxtDumpString(ctxt, ent->content);
793 fprintf(ctxt->output, "\n");
794 }
795 }
796 }
797
798 /**
799 * xmlCtxtDumpAttr:
800 * @output: the FILE * for the output
801 * @attr: the attribute
802 * @depth: the indentation level.
803 *
804 * Dumps debug information for the attribute
805 */
806 static void
xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)807 xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
808 {
809 xmlCtxtDumpSpaces(ctxt);
810
811 if (attr == NULL) {
812 if (!ctxt->check)
813 fprintf(ctxt->output, "Attr is NULL");
814 return;
815 }
816 if (!ctxt->check) {
817 fprintf(ctxt->output, "ATTRIBUTE ");
818 xmlCtxtDumpString(ctxt, attr->name);
819 fprintf(ctxt->output, "\n");
820 if (attr->children != NULL) {
821 ctxt->depth++;
822 xmlCtxtDumpNodeList(ctxt, attr->children);
823 ctxt->depth--;
824 }
825 }
826 if (attr->name == NULL)
827 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
828 "Attribute has no name");
829
830 /*
831 * Do a bit of checking
832 */
833 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
834 }
835
836 /**
837 * xmlCtxtDumpAttrList:
838 * @output: the FILE * for the output
839 * @attr: the attribute list
840 * @depth: the indentation level.
841 *
842 * Dumps debug information for the attribute list
843 */
844 static void
xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)845 xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
846 {
847 while (attr != NULL) {
848 xmlCtxtDumpAttr(ctxt, attr);
849 attr = attr->next;
850 }
851 }
852
853 /**
854 * xmlCtxtDumpOneNode:
855 * @output: the FILE * for the output
856 * @node: the node
857 * @depth: the indentation level.
858 *
859 * Dumps debug information for the element node, it is not recursive
860 */
861 static void
xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)862 xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
863 {
864 if (node == NULL) {
865 if (!ctxt->check) {
866 xmlCtxtDumpSpaces(ctxt);
867 fprintf(ctxt->output, "node is NULL\n");
868 }
869 return;
870 }
871 ctxt->node = node;
872
873 switch (node->type) {
874 case XML_ELEMENT_NODE:
875 if (!ctxt->check) {
876 xmlCtxtDumpSpaces(ctxt);
877 fprintf(ctxt->output, "ELEMENT ");
878 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
879 xmlCtxtDumpString(ctxt, node->ns->prefix);
880 fprintf(ctxt->output, ":");
881 }
882 xmlCtxtDumpString(ctxt, node->name);
883 fprintf(ctxt->output, "\n");
884 }
885 break;
886 case XML_ATTRIBUTE_NODE:
887 if (!ctxt->check)
888 xmlCtxtDumpSpaces(ctxt);
889 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
890 xmlCtxtGenericNodeCheck(ctxt, node);
891 return;
892 case XML_TEXT_NODE:
893 if (!ctxt->check) {
894 xmlCtxtDumpSpaces(ctxt);
895 if (node->name == (const xmlChar *) xmlStringTextNoenc)
896 fprintf(ctxt->output, "TEXT no enc");
897 else
898 fprintf(ctxt->output, "TEXT");
899 if (ctxt->options & DUMP_TEXT_TYPE) {
900 if (node->content == (xmlChar *) &(node->properties))
901 fprintf(ctxt->output, " compact\n");
902 else if (xmlDictOwns(ctxt->dict, node->content) == 1)
903 fprintf(ctxt->output, " interned\n");
904 else
905 fprintf(ctxt->output, "\n");
906 } else
907 fprintf(ctxt->output, "\n");
908 }
909 break;
910 case XML_CDATA_SECTION_NODE:
911 if (!ctxt->check) {
912 xmlCtxtDumpSpaces(ctxt);
913 fprintf(ctxt->output, "CDATA_SECTION\n");
914 }
915 break;
916 case XML_ENTITY_REF_NODE:
917 if (!ctxt->check) {
918 xmlCtxtDumpSpaces(ctxt);
919 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
920 (char *) node->name);
921 }
922 break;
923 case XML_ENTITY_NODE:
924 if (!ctxt->check) {
925 xmlCtxtDumpSpaces(ctxt);
926 fprintf(ctxt->output, "ENTITY\n");
927 }
928 break;
929 case XML_PI_NODE:
930 if (!ctxt->check) {
931 xmlCtxtDumpSpaces(ctxt);
932 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
933 }
934 break;
935 case XML_COMMENT_NODE:
936 if (!ctxt->check) {
937 xmlCtxtDumpSpaces(ctxt);
938 fprintf(ctxt->output, "COMMENT\n");
939 }
940 break;
941 case XML_DOCUMENT_NODE:
942 case XML_HTML_DOCUMENT_NODE:
943 if (!ctxt->check) {
944 xmlCtxtDumpSpaces(ctxt);
945 }
946 fprintf(ctxt->output, "Error, DOCUMENT found here\n");
947 xmlCtxtGenericNodeCheck(ctxt, node);
948 return;
949 case XML_DOCUMENT_TYPE_NODE:
950 if (!ctxt->check) {
951 xmlCtxtDumpSpaces(ctxt);
952 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
953 }
954 break;
955 case XML_DOCUMENT_FRAG_NODE:
956 if (!ctxt->check) {
957 xmlCtxtDumpSpaces(ctxt);
958 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
959 }
960 break;
961 case XML_NOTATION_NODE:
962 if (!ctxt->check) {
963 xmlCtxtDumpSpaces(ctxt);
964 fprintf(ctxt->output, "NOTATION\n");
965 }
966 break;
967 case XML_DTD_NODE:
968 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
969 return;
970 case XML_ELEMENT_DECL:
971 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
972 return;
973 case XML_ATTRIBUTE_DECL:
974 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
975 return;
976 case XML_ENTITY_DECL:
977 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
978 return;
979 case XML_NAMESPACE_DECL:
980 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
981 return;
982 case XML_XINCLUDE_START:
983 if (!ctxt->check) {
984 xmlCtxtDumpSpaces(ctxt);
985 fprintf(ctxt->output, "INCLUDE START\n");
986 }
987 return;
988 case XML_XINCLUDE_END:
989 if (!ctxt->check) {
990 xmlCtxtDumpSpaces(ctxt);
991 fprintf(ctxt->output, "INCLUDE END\n");
992 }
993 return;
994 default:
995 if (!ctxt->check)
996 xmlCtxtDumpSpaces(ctxt);
997 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
998 "Unknown node type %d\n", node->type);
999 return;
1000 }
1001 if (node->doc == NULL) {
1002 if (!ctxt->check) {
1003 xmlCtxtDumpSpaces(ctxt);
1004 }
1005 fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
1006 }
1007 ctxt->depth++;
1008 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
1009 xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
1010 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
1011 xmlCtxtDumpAttrList(ctxt, node->properties);
1012 if (node->type != XML_ENTITY_REF_NODE) {
1013 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
1014 if (!ctxt->check) {
1015 xmlCtxtDumpSpaces(ctxt);
1016 fprintf(ctxt->output, "content=");
1017 xmlCtxtDumpString(ctxt, node->content);
1018 fprintf(ctxt->output, "\n");
1019 }
1020 }
1021 } else {
1022 xmlEntityPtr ent;
1023
1024 ent = xmlGetDocEntity(node->doc, node->name);
1025 if (ent != NULL)
1026 xmlCtxtDumpEntity(ctxt, ent);
1027 }
1028 ctxt->depth--;
1029
1030 /*
1031 * Do a bit of checking
1032 */
1033 xmlCtxtGenericNodeCheck(ctxt, node);
1034 }
1035
1036 /**
1037 * xmlCtxtDumpNode:
1038 * @output: the FILE * for the output
1039 * @node: the node
1040 * @depth: the indentation level.
1041 *
1042 * Dumps debug information for the element node, it is recursive
1043 */
1044 static void
xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1045 xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1046 {
1047 if (node == NULL) {
1048 if (!ctxt->check) {
1049 xmlCtxtDumpSpaces(ctxt);
1050 fprintf(ctxt->output, "node is NULL\n");
1051 }
1052 return;
1053 }
1054 xmlCtxtDumpOneNode(ctxt, node);
1055 if ((node->type != XML_NAMESPACE_DECL) &&
1056 (node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1057 ctxt->depth++;
1058 xmlCtxtDumpNodeList(ctxt, node->children);
1059 ctxt->depth--;
1060 }
1061 }
1062
1063 /**
1064 * xmlCtxtDumpNodeList:
1065 * @output: the FILE * for the output
1066 * @node: the node list
1067 * @depth: the indentation level.
1068 *
1069 * Dumps debug information for the list of element node, it is recursive
1070 */
1071 static void
xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1072 xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1073 {
1074 while (node != NULL) {
1075 xmlCtxtDumpNode(ctxt, node);
1076 node = node->next;
1077 }
1078 }
1079
1080 static void
xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1081 xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1082 {
1083 if (doc == NULL) {
1084 if (!ctxt->check)
1085 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1086 return;
1087 }
1088 ctxt->node = (xmlNodePtr) doc;
1089
1090 switch (doc->type) {
1091 case XML_ELEMENT_NODE:
1092 xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
1093 "Misplaced ELEMENT node\n");
1094 break;
1095 case XML_ATTRIBUTE_NODE:
1096 xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
1097 "Misplaced ATTRIBUTE node\n");
1098 break;
1099 case XML_TEXT_NODE:
1100 xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
1101 "Misplaced TEXT node\n");
1102 break;
1103 case XML_CDATA_SECTION_NODE:
1104 xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
1105 "Misplaced CDATA node\n");
1106 break;
1107 case XML_ENTITY_REF_NODE:
1108 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
1109 "Misplaced ENTITYREF node\n");
1110 break;
1111 case XML_ENTITY_NODE:
1112 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
1113 "Misplaced ENTITY node\n");
1114 break;
1115 case XML_PI_NODE:
1116 xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
1117 "Misplaced PI node\n");
1118 break;
1119 case XML_COMMENT_NODE:
1120 xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
1121 "Misplaced COMMENT node\n");
1122 break;
1123 case XML_DOCUMENT_NODE:
1124 if (!ctxt->check)
1125 fprintf(ctxt->output, "DOCUMENT\n");
1126 break;
1127 case XML_HTML_DOCUMENT_NODE:
1128 if (!ctxt->check)
1129 fprintf(ctxt->output, "HTML DOCUMENT\n");
1130 break;
1131 case XML_DOCUMENT_TYPE_NODE:
1132 xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
1133 "Misplaced DOCTYPE node\n");
1134 break;
1135 case XML_DOCUMENT_FRAG_NODE:
1136 xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
1137 "Misplaced FRAGMENT node\n");
1138 break;
1139 case XML_NOTATION_NODE:
1140 xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
1141 "Misplaced NOTATION node\n");
1142 break;
1143 default:
1144 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
1145 "Unknown node type %d\n", doc->type);
1146 }
1147 }
1148
1149 /**
1150 * xmlCtxtDumpDocumentHead:
1151 * @output: the FILE * for the output
1152 * @doc: the document
1153 *
1154 * Dumps debug information concerning the document, not recursive
1155 */
1156 static void
xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1157 xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1158 {
1159 if (doc == NULL) return;
1160 xmlCtxtDumpDocHead(ctxt, doc);
1161 if (!ctxt->check) {
1162 if (doc->name != NULL) {
1163 fprintf(ctxt->output, "name=");
1164 xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
1165 fprintf(ctxt->output, "\n");
1166 }
1167 if (doc->version != NULL) {
1168 fprintf(ctxt->output, "version=");
1169 xmlCtxtDumpString(ctxt, doc->version);
1170 fprintf(ctxt->output, "\n");
1171 }
1172 if (doc->encoding != NULL) {
1173 fprintf(ctxt->output, "encoding=");
1174 xmlCtxtDumpString(ctxt, doc->encoding);
1175 fprintf(ctxt->output, "\n");
1176 }
1177 if (doc->URL != NULL) {
1178 fprintf(ctxt->output, "URL=");
1179 xmlCtxtDumpString(ctxt, doc->URL);
1180 fprintf(ctxt->output, "\n");
1181 }
1182 if (doc->standalone)
1183 fprintf(ctxt->output, "standalone=true\n");
1184 }
1185 if (doc->oldNs != NULL)
1186 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
1187 }
1188
1189 /**
1190 * xmlCtxtDumpDocument:
1191 * @output: the FILE * for the output
1192 * @doc: the document
1193 *
1194 * Dumps debug information for the document, it's recursive
1195 */
1196 static void
xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1197 xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1198 {
1199 if (doc == NULL) {
1200 if (!ctxt->check)
1201 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1202 return;
1203 }
1204 xmlCtxtDumpDocumentHead(ctxt, doc);
1205 if (((doc->type == XML_DOCUMENT_NODE) ||
1206 (doc->type == XML_HTML_DOCUMENT_NODE))
1207 && (doc->children != NULL)) {
1208 ctxt->depth++;
1209 xmlCtxtDumpNodeList(ctxt, doc->children);
1210 ctxt->depth--;
1211 }
1212 }
1213
1214 static void
xmlCtxtDumpEntityCallback(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)1215 xmlCtxtDumpEntityCallback(void *payload, void *data,
1216 const xmlChar *name ATTRIBUTE_UNUSED)
1217 {
1218 xmlEntityPtr cur = (xmlEntityPtr) payload;
1219 xmlDebugCtxtPtr ctxt = (xmlDebugCtxtPtr) data;
1220 if (cur == NULL) {
1221 if (!ctxt->check)
1222 fprintf(ctxt->output, "Entity is NULL");
1223 return;
1224 }
1225 if (!ctxt->check) {
1226 fprintf(ctxt->output, "%s : ", (char *) cur->name);
1227 switch (cur->etype) {
1228 case XML_INTERNAL_GENERAL_ENTITY:
1229 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1230 break;
1231 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1232 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1233 break;
1234 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1235 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1236 break;
1237 case XML_INTERNAL_PARAMETER_ENTITY:
1238 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1239 break;
1240 case XML_EXTERNAL_PARAMETER_ENTITY:
1241 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1242 break;
1243 default:
1244 xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1245 "Unknown entity type %d\n", cur->etype);
1246 }
1247 if (cur->ExternalID != NULL)
1248 fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1249 if (cur->SystemID != NULL)
1250 fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1251 if (cur->orig != NULL)
1252 fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1253 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1254 fprintf(ctxt->output, "\n content \"%s\"",
1255 (char *) cur->content);
1256 fprintf(ctxt->output, "\n");
1257 }
1258 }
1259
1260 /**
1261 * xmlCtxtDumpEntities:
1262 * @output: the FILE * for the output
1263 * @doc: the document
1264 *
1265 * Dumps debug information for all the entities in use by the document
1266 */
1267 static void
xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1268 xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1269 {
1270 if (doc == NULL) return;
1271 xmlCtxtDumpDocHead(ctxt, doc);
1272 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1273 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1274 doc->intSubset->entities;
1275
1276 if (!ctxt->check)
1277 fprintf(ctxt->output, "Entities in internal subset\n");
1278 xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1279 } else
1280 fprintf(ctxt->output, "No entities in internal subset\n");
1281 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1282 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1283 doc->extSubset->entities;
1284
1285 if (!ctxt->check)
1286 fprintf(ctxt->output, "Entities in external subset\n");
1287 xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1288 } else if (!ctxt->check)
1289 fprintf(ctxt->output, "No entities in external subset\n");
1290 }
1291
1292 /**
1293 * xmlCtxtDumpDTD:
1294 * @output: the FILE * for the output
1295 * @dtd: the DTD
1296 *
1297 * Dumps debug information for the DTD
1298 */
1299 static void
xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)1300 xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1301 {
1302 if (dtd == NULL) {
1303 if (!ctxt->check)
1304 fprintf(ctxt->output, "DTD is NULL\n");
1305 return;
1306 }
1307 xmlCtxtDumpDtdNode(ctxt, dtd);
1308 if (dtd->children == NULL)
1309 fprintf(ctxt->output, " DTD is empty\n");
1310 else {
1311 ctxt->depth++;
1312 xmlCtxtDumpNodeList(ctxt, dtd->children);
1313 ctxt->depth--;
1314 }
1315 }
1316
1317 /************************************************************************
1318 * *
1319 * Public entry points for dump *
1320 * *
1321 ************************************************************************/
1322
1323 /**
1324 * xmlDebugDumpString:
1325 * @output: the FILE * for the output
1326 * @str: the string
1327 *
1328 * Dumps information about the string, shorten it if necessary
1329 */
1330 void
xmlDebugDumpString(FILE * output,const xmlChar * str)1331 xmlDebugDumpString(FILE * output, const xmlChar * str)
1332 {
1333 int i;
1334
1335 if (output == NULL)
1336 output = stdout;
1337 if (str == NULL) {
1338 fprintf(output, "(NULL)");
1339 return;
1340 }
1341 for (i = 0; i < 40; i++)
1342 if (str[i] == 0)
1343 return;
1344 else if (IS_BLANK_CH(str[i]))
1345 fputc(' ', output);
1346 else if (str[i] >= 0x80)
1347 fprintf(output, "#%X", str[i]);
1348 else
1349 fputc(str[i], output);
1350 fprintf(output, "...");
1351 }
1352
1353 /**
1354 * xmlDebugDumpAttr:
1355 * @output: the FILE * for the output
1356 * @attr: the attribute
1357 * @depth: the indentation level.
1358 *
1359 * Dumps debug information for the attribute
1360 */
1361 void
xmlDebugDumpAttr(FILE * output,xmlAttrPtr attr,int depth)1362 xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
1363 xmlDebugCtxt ctxt;
1364
1365 if (output == NULL) return;
1366 xmlCtxtDumpInitCtxt(&ctxt);
1367 ctxt.output = output;
1368 ctxt.depth = depth;
1369 xmlCtxtDumpAttr(&ctxt, attr);
1370 xmlCtxtDumpCleanCtxt(&ctxt);
1371 }
1372
1373
1374 /**
1375 * xmlDebugDumpEntities:
1376 * @output: the FILE * for the output
1377 * @doc: the document
1378 *
1379 * Dumps debug information for all the entities in use by the document
1380 */
1381 void
xmlDebugDumpEntities(FILE * output,xmlDocPtr doc)1382 xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1383 {
1384 xmlDebugCtxt ctxt;
1385
1386 if (output == NULL) return;
1387 xmlCtxtDumpInitCtxt(&ctxt);
1388 ctxt.output = output;
1389 xmlCtxtDumpEntities(&ctxt, doc);
1390 xmlCtxtDumpCleanCtxt(&ctxt);
1391 }
1392
1393 /**
1394 * xmlDebugDumpAttrList:
1395 * @output: the FILE * for the output
1396 * @attr: the attribute list
1397 * @depth: the indentation level.
1398 *
1399 * Dumps debug information for the attribute list
1400 */
1401 void
xmlDebugDumpAttrList(FILE * output,xmlAttrPtr attr,int depth)1402 xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1403 {
1404 xmlDebugCtxt ctxt;
1405
1406 if (output == NULL) return;
1407 xmlCtxtDumpInitCtxt(&ctxt);
1408 ctxt.output = output;
1409 ctxt.depth = depth;
1410 xmlCtxtDumpAttrList(&ctxt, attr);
1411 xmlCtxtDumpCleanCtxt(&ctxt);
1412 }
1413
1414 /**
1415 * xmlDebugDumpOneNode:
1416 * @output: the FILE * for the output
1417 * @node: the node
1418 * @depth: the indentation level.
1419 *
1420 * Dumps debug information for the element node, it is not recursive
1421 */
1422 void
xmlDebugDumpOneNode(FILE * output,xmlNodePtr node,int depth)1423 xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1424 {
1425 xmlDebugCtxt ctxt;
1426
1427 if (output == NULL) return;
1428 xmlCtxtDumpInitCtxt(&ctxt);
1429 ctxt.output = output;
1430 ctxt.depth = depth;
1431 xmlCtxtDumpOneNode(&ctxt, node);
1432 xmlCtxtDumpCleanCtxt(&ctxt);
1433 }
1434
1435 /**
1436 * xmlDebugDumpNode:
1437 * @output: the FILE * for the output
1438 * @node: the node
1439 * @depth: the indentation level.
1440 *
1441 * Dumps debug information for the element node, it is recursive
1442 */
1443 void
xmlDebugDumpNode(FILE * output,xmlNodePtr node,int depth)1444 xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1445 {
1446 xmlDebugCtxt ctxt;
1447
1448 if (output == NULL)
1449 output = stdout;
1450 xmlCtxtDumpInitCtxt(&ctxt);
1451 ctxt.output = output;
1452 ctxt.depth = depth;
1453 xmlCtxtDumpNode(&ctxt, node);
1454 xmlCtxtDumpCleanCtxt(&ctxt);
1455 }
1456
1457 /**
1458 * xmlDebugDumpNodeList:
1459 * @output: the FILE * for the output
1460 * @node: the node list
1461 * @depth: the indentation level.
1462 *
1463 * Dumps debug information for the list of element node, it is recursive
1464 */
1465 void
xmlDebugDumpNodeList(FILE * output,xmlNodePtr node,int depth)1466 xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1467 {
1468 xmlDebugCtxt ctxt;
1469
1470 if (output == NULL)
1471 output = stdout;
1472 xmlCtxtDumpInitCtxt(&ctxt);
1473 ctxt.output = output;
1474 ctxt.depth = depth;
1475 xmlCtxtDumpNodeList(&ctxt, node);
1476 xmlCtxtDumpCleanCtxt(&ctxt);
1477 }
1478
1479 /**
1480 * xmlDebugDumpDocumentHead:
1481 * @output: the FILE * for the output
1482 * @doc: the document
1483 *
1484 * Dumps debug information concerning the document, not recursive
1485 */
1486 void
xmlDebugDumpDocumentHead(FILE * output,xmlDocPtr doc)1487 xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1488 {
1489 xmlDebugCtxt ctxt;
1490
1491 if (output == NULL)
1492 output = stdout;
1493 xmlCtxtDumpInitCtxt(&ctxt);
1494 ctxt.options |= DUMP_TEXT_TYPE;
1495 ctxt.output = output;
1496 xmlCtxtDumpDocumentHead(&ctxt, doc);
1497 xmlCtxtDumpCleanCtxt(&ctxt);
1498 }
1499
1500 /**
1501 * xmlDebugDumpDocument:
1502 * @output: the FILE * for the output
1503 * @doc: the document
1504 *
1505 * Dumps debug information for the document, it's recursive
1506 */
1507 void
xmlDebugDumpDocument(FILE * output,xmlDocPtr doc)1508 xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1509 {
1510 xmlDebugCtxt ctxt;
1511
1512 if (output == NULL)
1513 output = stdout;
1514 xmlCtxtDumpInitCtxt(&ctxt);
1515 ctxt.options |= DUMP_TEXT_TYPE;
1516 ctxt.output = output;
1517 xmlCtxtDumpDocument(&ctxt, doc);
1518 xmlCtxtDumpCleanCtxt(&ctxt);
1519 }
1520
1521 /**
1522 * xmlDebugDumpDTD:
1523 * @output: the FILE * for the output
1524 * @dtd: the DTD
1525 *
1526 * Dumps debug information for the DTD
1527 */
1528 void
xmlDebugDumpDTD(FILE * output,xmlDtdPtr dtd)1529 xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1530 {
1531 xmlDebugCtxt ctxt;
1532
1533 if (output == NULL)
1534 output = stdout;
1535 xmlCtxtDumpInitCtxt(&ctxt);
1536 ctxt.options |= DUMP_TEXT_TYPE;
1537 ctxt.output = output;
1538 xmlCtxtDumpDTD(&ctxt, dtd);
1539 xmlCtxtDumpCleanCtxt(&ctxt);
1540 }
1541
1542 /************************************************************************
1543 * *
1544 * Public entry points for checkings *
1545 * *
1546 ************************************************************************/
1547
1548 /**
1549 * xmlDebugCheckDocument:
1550 * @output: the FILE * for the output
1551 * @doc: the document
1552 *
1553 * Check the document for potential content problems, and output
1554 * the errors to @output
1555 *
1556 * Returns the number of errors found
1557 */
1558 int
xmlDebugCheckDocument(FILE * output,xmlDocPtr doc)1559 xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1560 {
1561 xmlDebugCtxt ctxt;
1562
1563 if (output == NULL)
1564 output = stdout;
1565 xmlCtxtDumpInitCtxt(&ctxt);
1566 ctxt.output = output;
1567 ctxt.check = 1;
1568 xmlCtxtDumpDocument(&ctxt, doc);
1569 xmlCtxtDumpCleanCtxt(&ctxt);
1570 return(ctxt.errors);
1571 }
1572
1573 /************************************************************************
1574 * *
1575 * Helpers for Shell *
1576 * *
1577 ************************************************************************/
1578
1579 /**
1580 * xmlLsCountNode:
1581 * @node: the node to count
1582 *
1583 * Count the children of @node.
1584 *
1585 * Returns the number of children of @node.
1586 */
1587 int
xmlLsCountNode(xmlNodePtr node)1588 xmlLsCountNode(xmlNodePtr node) {
1589 int ret = 0;
1590 xmlNodePtr list = NULL;
1591
1592 if (node == NULL)
1593 return(0);
1594
1595 switch (node->type) {
1596 case XML_ELEMENT_NODE:
1597 list = node->children;
1598 break;
1599 case XML_DOCUMENT_NODE:
1600 case XML_HTML_DOCUMENT_NODE:
1601 list = ((xmlDocPtr) node)->children;
1602 break;
1603 case XML_ATTRIBUTE_NODE:
1604 list = ((xmlAttrPtr) node)->children;
1605 break;
1606 case XML_TEXT_NODE:
1607 case XML_CDATA_SECTION_NODE:
1608 case XML_PI_NODE:
1609 case XML_COMMENT_NODE:
1610 if (node->content != NULL) {
1611 ret = xmlStrlen(node->content);
1612 }
1613 break;
1614 case XML_ENTITY_REF_NODE:
1615 case XML_DOCUMENT_TYPE_NODE:
1616 case XML_ENTITY_NODE:
1617 case XML_DOCUMENT_FRAG_NODE:
1618 case XML_NOTATION_NODE:
1619 case XML_DTD_NODE:
1620 case XML_ELEMENT_DECL:
1621 case XML_ATTRIBUTE_DECL:
1622 case XML_ENTITY_DECL:
1623 case XML_NAMESPACE_DECL:
1624 case XML_XINCLUDE_START:
1625 case XML_XINCLUDE_END:
1626 ret = 1;
1627 break;
1628 }
1629 for (;list != NULL;ret++)
1630 list = list->next;
1631 return(ret);
1632 }
1633
1634 /**
1635 * xmlLsOneNode:
1636 * @output: the FILE * for the output
1637 * @node: the node to dump
1638 *
1639 * Dump to @output the type and name of @node.
1640 */
1641 void
xmlLsOneNode(FILE * output,xmlNodePtr node)1642 xmlLsOneNode(FILE *output, xmlNodePtr node) {
1643 if (output == NULL) return;
1644 if (node == NULL) {
1645 fprintf(output, "NULL\n");
1646 return;
1647 }
1648 switch (node->type) {
1649 case XML_ELEMENT_NODE:
1650 fprintf(output, "-");
1651 break;
1652 case XML_ATTRIBUTE_NODE:
1653 fprintf(output, "a");
1654 break;
1655 case XML_TEXT_NODE:
1656 fprintf(output, "t");
1657 break;
1658 case XML_CDATA_SECTION_NODE:
1659 fprintf(output, "C");
1660 break;
1661 case XML_ENTITY_REF_NODE:
1662 fprintf(output, "e");
1663 break;
1664 case XML_ENTITY_NODE:
1665 fprintf(output, "E");
1666 break;
1667 case XML_PI_NODE:
1668 fprintf(output, "p");
1669 break;
1670 case XML_COMMENT_NODE:
1671 fprintf(output, "c");
1672 break;
1673 case XML_DOCUMENT_NODE:
1674 fprintf(output, "d");
1675 break;
1676 case XML_HTML_DOCUMENT_NODE:
1677 fprintf(output, "h");
1678 break;
1679 case XML_DOCUMENT_TYPE_NODE:
1680 fprintf(output, "T");
1681 break;
1682 case XML_DOCUMENT_FRAG_NODE:
1683 fprintf(output, "F");
1684 break;
1685 case XML_NOTATION_NODE:
1686 fprintf(output, "N");
1687 break;
1688 case XML_NAMESPACE_DECL:
1689 fprintf(output, "n");
1690 break;
1691 default:
1692 fprintf(output, "?");
1693 }
1694 if (node->type != XML_NAMESPACE_DECL) {
1695 if (node->properties != NULL)
1696 fprintf(output, "a");
1697 else
1698 fprintf(output, "-");
1699 if (node->nsDef != NULL)
1700 fprintf(output, "n");
1701 else
1702 fprintf(output, "-");
1703 }
1704
1705 fprintf(output, " %8d ", xmlLsCountNode(node));
1706
1707 switch (node->type) {
1708 case XML_ELEMENT_NODE:
1709 if (node->name != NULL) {
1710 if ((node->ns != NULL) && (node->ns->prefix != NULL))
1711 fprintf(output, "%s:", node->ns->prefix);
1712 fprintf(output, "%s", (const char *) node->name);
1713 }
1714 break;
1715 case XML_ATTRIBUTE_NODE:
1716 if (node->name != NULL)
1717 fprintf(output, "%s", (const char *) node->name);
1718 break;
1719 case XML_TEXT_NODE:
1720 if (node->content != NULL) {
1721 xmlDebugDumpString(output, node->content);
1722 }
1723 break;
1724 case XML_CDATA_SECTION_NODE:
1725 break;
1726 case XML_ENTITY_REF_NODE:
1727 if (node->name != NULL)
1728 fprintf(output, "%s", (const char *) node->name);
1729 break;
1730 case XML_ENTITY_NODE:
1731 if (node->name != NULL)
1732 fprintf(output, "%s", (const char *) node->name);
1733 break;
1734 case XML_PI_NODE:
1735 if (node->name != NULL)
1736 fprintf(output, "%s", (const char *) node->name);
1737 break;
1738 case XML_COMMENT_NODE:
1739 break;
1740 case XML_DOCUMENT_NODE:
1741 break;
1742 case XML_HTML_DOCUMENT_NODE:
1743 break;
1744 case XML_DOCUMENT_TYPE_NODE:
1745 break;
1746 case XML_DOCUMENT_FRAG_NODE:
1747 break;
1748 case XML_NOTATION_NODE:
1749 break;
1750 case XML_NAMESPACE_DECL: {
1751 xmlNsPtr ns = (xmlNsPtr) node;
1752
1753 if (ns->prefix == NULL)
1754 fprintf(output, "default -> %s", (char *)ns->href);
1755 else
1756 fprintf(output, "%s -> %s", (char *)ns->prefix,
1757 (char *)ns->href);
1758 break;
1759 }
1760 default:
1761 if (node->name != NULL)
1762 fprintf(output, "%s", (const char *) node->name);
1763 }
1764 fprintf(output, "\n");
1765 }
1766
1767 /**
1768 * xmlBoolToText:
1769 * @boolval: a bool to turn into text
1770 *
1771 * Convenient way to turn bool into text
1772 *
1773 * Returns a pointer to either "True" or "False"
1774 */
1775 const char *
xmlBoolToText(int boolval)1776 xmlBoolToText(int boolval)
1777 {
1778 if (boolval)
1779 return("True");
1780 else
1781 return("False");
1782 }
1783
1784 #ifdef LIBXML_XPATH_ENABLED
1785 /****************************************************************
1786 * *
1787 * The XML shell related functions *
1788 * *
1789 ****************************************************************/
1790
1791
1792
1793 /*
1794 * TODO: Improvement/cleanups for the XML shell
1795 * - allow to shell out an editor on a subpart
1796 * - cleanup function registrations (with help) and calling
1797 * - provide registration routines
1798 */
1799
1800 /**
1801 * xmlShellPrintXPathError:
1802 * @errorType: valid xpath error id
1803 * @arg: the argument that cause xpath to fail
1804 *
1805 * Print the xpath error to libxml default error channel
1806 */
1807 void
xmlShellPrintXPathError(int errorType,const char * arg)1808 xmlShellPrintXPathError(int errorType, const char *arg)
1809 {
1810 const char *default_arg = "Result";
1811
1812 if (!arg)
1813 arg = default_arg;
1814
1815 switch (errorType) {
1816 case XPATH_UNDEFINED:
1817 fprintf(stderr,
1818 "%s: no such node\n", arg);
1819 break;
1820
1821 case XPATH_BOOLEAN:
1822 fprintf(stderr,
1823 "%s is a Boolean\n", arg);
1824 break;
1825 case XPATH_NUMBER:
1826 fprintf(stderr,
1827 "%s is a number\n", arg);
1828 break;
1829 case XPATH_STRING:
1830 fprintf(stderr,
1831 "%s is a string\n", arg);
1832 break;
1833 case XPATH_USERS:
1834 fprintf(stderr,
1835 "%s is user-defined\n", arg);
1836 break;
1837 case XPATH_XSLT_TREE:
1838 fprintf(stderr,
1839 "%s is an XSLT value tree\n", arg);
1840 break;
1841 }
1842 #if 0
1843 fprintf(stderr,
1844 "Try casting the result string function (xpath builtin)\n",
1845 arg);
1846 #endif
1847 }
1848
1849
1850 #ifdef LIBXML_OUTPUT_ENABLED
1851 /**
1852 * xmlShellPrintNodeCtxt:
1853 * @ctxt : a non-null shell context
1854 * @node : a non-null node to print to the output FILE
1855 *
1856 * Print node to the output FILE
1857 */
1858 static void
xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)1859 xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1860 {
1861 FILE *fp;
1862
1863 if (!node)
1864 return;
1865 if (ctxt == NULL)
1866 fp = stdout;
1867 else
1868 fp = ctxt->output;
1869
1870 if (node->type == XML_DOCUMENT_NODE)
1871 xmlDocDump(fp, (xmlDocPtr) node);
1872 else if (node->type == XML_ATTRIBUTE_NODE)
1873 xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
1874 else
1875 xmlElemDump(fp, node->doc, node);
1876
1877 fprintf(fp, "\n");
1878 }
1879
1880 /**
1881 * xmlShellPrintNode:
1882 * @node : a non-null node to print to the output FILE
1883 *
1884 * Print node to the output FILE
1885 */
1886 void
xmlShellPrintNode(xmlNodePtr node)1887 xmlShellPrintNode(xmlNodePtr node)
1888 {
1889 xmlShellPrintNodeCtxt(NULL, node);
1890 }
1891 #endif /* LIBXML_OUTPUT_ENABLED */
1892
1893 /**
1894 * xmlShellPrintXPathResultCtxt:
1895 * @ctxt: a valid shell context
1896 * @list: a valid result generated by an xpath evaluation
1897 *
1898 * Prints result to the output FILE
1899 */
1900 static void
xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)1901 xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
1902 {
1903 if (!ctxt)
1904 return;
1905
1906 if (list != NULL) {
1907 switch (list->type) {
1908 case XPATH_NODESET:{
1909 #ifdef LIBXML_OUTPUT_ENABLED
1910 int indx;
1911
1912 if (list->nodesetval) {
1913 for (indx = 0; indx < list->nodesetval->nodeNr;
1914 indx++) {
1915 xmlShellPrintNodeCtxt(ctxt,
1916 list->nodesetval->nodeTab[indx]);
1917 }
1918 } else {
1919 fprintf(ctxt->output,
1920 "Empty node set\n");
1921 }
1922 break;
1923 #else
1924 fprintf(ctxt->output,
1925 "Node set\n");
1926 #endif /* LIBXML_OUTPUT_ENABLED */
1927 }
1928 case XPATH_BOOLEAN:
1929 fprintf(ctxt->output,
1930 "Is a Boolean:%s\n",
1931 xmlBoolToText(list->boolval));
1932 break;
1933 case XPATH_NUMBER:
1934 fprintf(ctxt->output,
1935 "Is a number:%0g\n", list->floatval);
1936 break;
1937 case XPATH_STRING:
1938 fprintf(ctxt->output,
1939 "Is a string:%s\n", list->stringval);
1940 break;
1941
1942 default:
1943 xmlShellPrintXPathError(list->type, NULL);
1944 }
1945 }
1946 }
1947
1948 /**
1949 * xmlShellPrintXPathResult:
1950 * @list: a valid result generated by an xpath evaluation
1951 *
1952 * Prints result to the output FILE
1953 */
1954 void
xmlShellPrintXPathResult(xmlXPathObjectPtr list)1955 xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1956 {
1957 xmlShellPrintXPathResultCtxt(NULL, list);
1958 }
1959
1960 /**
1961 * xmlShellList:
1962 * @ctxt: the shell context
1963 * @arg: unused
1964 * @node: a node
1965 * @node2: unused
1966 *
1967 * Implements the XML shell function "ls"
1968 * Does an Unix like listing of the given node (like a directory)
1969 *
1970 * Returns 0
1971 */
1972 int
xmlShellList(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)1973 xmlShellList(xmlShellCtxtPtr ctxt,
1974 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1975 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1976 {
1977 xmlNodePtr cur;
1978 if (!ctxt)
1979 return (0);
1980 if (node == NULL) {
1981 fprintf(ctxt->output, "NULL\n");
1982 return (0);
1983 }
1984 if ((node->type == XML_DOCUMENT_NODE) ||
1985 (node->type == XML_HTML_DOCUMENT_NODE)) {
1986 cur = ((xmlDocPtr) node)->children;
1987 } else if (node->type == XML_NAMESPACE_DECL) {
1988 xmlLsOneNode(ctxt->output, node);
1989 return (0);
1990 } else if (node->children != NULL) {
1991 cur = node->children;
1992 } else {
1993 xmlLsOneNode(ctxt->output, node);
1994 return (0);
1995 }
1996 while (cur != NULL) {
1997 xmlLsOneNode(ctxt->output, cur);
1998 cur = cur->next;
1999 }
2000 return (0);
2001 }
2002
2003 /**
2004 * xmlShellBase:
2005 * @ctxt: the shell context
2006 * @arg: unused
2007 * @node: a node
2008 * @node2: unused
2009 *
2010 * Implements the XML shell function "base"
2011 * dumps the current XML base of the node
2012 *
2013 * Returns 0
2014 */
2015 int
xmlShellBase(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2016 xmlShellBase(xmlShellCtxtPtr ctxt,
2017 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2018 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2019 {
2020 xmlChar *base;
2021 if (!ctxt)
2022 return 0;
2023 if (node == NULL) {
2024 fprintf(ctxt->output, "NULL\n");
2025 return (0);
2026 }
2027
2028 base = xmlNodeGetBase(node->doc, node);
2029
2030 if (base == NULL) {
2031 fprintf(ctxt->output, " No base found !!!\n");
2032 } else {
2033 fprintf(ctxt->output, "%s\n", base);
2034 xmlFree(base);
2035 }
2036 return (0);
2037 }
2038
2039 #ifdef LIBXML_TREE_ENABLED
2040 /**
2041 * xmlShellSetBase:
2042 * @ctxt: the shell context
2043 * @arg: the new base
2044 * @node: a node
2045 * @node2: unused
2046 *
2047 * Implements the XML shell function "setbase"
2048 * change the current XML base of the node
2049 *
2050 * Returns 0
2051 */
2052 static int
xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2053 xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2054 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2055 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2056 {
2057 xmlNodeSetBase(node, (xmlChar*) arg);
2058 return (0);
2059 }
2060 #endif
2061
2062 #ifdef LIBXML_XPATH_ENABLED
2063 /**
2064 * xmlShellRegisterNamespace:
2065 * @ctxt: the shell context
2066 * @arg: a string in prefix=nsuri format
2067 * @node: unused
2068 * @node2: unused
2069 *
2070 * Implements the XML shell function "setns"
2071 * register/unregister a prefix=namespace pair
2072 * on the XPath context
2073 *
2074 * Returns 0 on success and a negative value otherwise.
2075 */
2076 static int
xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt,char * arg,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2077 xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
2078 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2079 {
2080 xmlChar* nsListDup;
2081 xmlChar* prefix;
2082 xmlChar* href;
2083 xmlChar* next;
2084
2085 nsListDup = xmlStrdup((xmlChar *) arg);
2086 next = nsListDup;
2087 while(next != NULL) {
2088 /* skip spaces */
2089 /*while((*next) == ' ') next++;*/
2090 if((*next) == '\0') break;
2091
2092 /* find prefix */
2093 prefix = next;
2094 next = (xmlChar*)xmlStrchr(next, '=');
2095 if(next == NULL) {
2096 fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
2097 xmlFree(nsListDup);
2098 return(-1);
2099 }
2100 *(next++) = '\0';
2101
2102 /* find href */
2103 href = next;
2104 next = (xmlChar*)xmlStrchr(next, ' ');
2105 if(next != NULL) {
2106 *(next++) = '\0';
2107 }
2108
2109 /* do register namespace */
2110 if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
2111 fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
2112 xmlFree(nsListDup);
2113 return(-1);
2114 }
2115 }
2116
2117 xmlFree(nsListDup);
2118 return(0);
2119 }
2120 /**
2121 * xmlShellRegisterRootNamespaces:
2122 * @ctxt: the shell context
2123 * @arg: unused
2124 * @node: the root element
2125 * @node2: unused
2126 *
2127 * Implements the XML shell function "setrootns"
2128 * which registers all namespaces declarations found on the root element.
2129 *
2130 * Returns 0 on success and a negative value otherwise.
2131 */
2132 static int
xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr root,xmlNodePtr node2 ATTRIBUTE_UNUSED)2133 xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2134 xmlNodePtr root, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2135 {
2136 xmlNsPtr ns;
2137
2138 if ((root == NULL) || (root->type != XML_ELEMENT_NODE) ||
2139 (root->nsDef == NULL) || (ctxt == NULL) || (ctxt->pctxt == NULL))
2140 return(-1);
2141 ns = root->nsDef;
2142 while (ns != NULL) {
2143 if (ns->prefix == NULL)
2144 xmlXPathRegisterNs(ctxt->pctxt, BAD_CAST "defaultns", ns->href);
2145 else
2146 xmlXPathRegisterNs(ctxt->pctxt, ns->prefix, ns->href);
2147 ns = ns->next;
2148 }
2149 return(0);
2150 }
2151 #endif
2152
2153 /**
2154 * xmlShellGrep:
2155 * @ctxt: the shell context
2156 * @arg: the string or regular expression to find
2157 * @node: a node
2158 * @node2: unused
2159 *
2160 * Implements the XML shell function "grep"
2161 * dumps information about the node (namespace, attributes, content).
2162 *
2163 * Returns 0
2164 */
2165 static int
xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2166 xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2167 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2168 {
2169 if (!ctxt)
2170 return (0);
2171 if (node == NULL)
2172 return (0);
2173 if (arg == NULL)
2174 return (0);
2175 #ifdef LIBXML_REGEXP_ENABLED
2176 if ((xmlStrchr((xmlChar *) arg, '?')) ||
2177 (xmlStrchr((xmlChar *) arg, '*')) ||
2178 (xmlStrchr((xmlChar *) arg, '.')) ||
2179 (xmlStrchr((xmlChar *) arg, '['))) {
2180 }
2181 #endif
2182 while (node != NULL) {
2183 if (node->type == XML_COMMENT_NODE) {
2184 if (xmlStrstr(node->content, (xmlChar *) arg)) {
2185
2186 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
2187 xmlShellList(ctxt, NULL, node, NULL);
2188 }
2189 } else if (node->type == XML_TEXT_NODE) {
2190 if (xmlStrstr(node->content, (xmlChar *) arg)) {
2191
2192 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
2193 xmlShellList(ctxt, NULL, node->parent, NULL);
2194 }
2195 }
2196
2197 /*
2198 * Browse the full subtree, deep first
2199 */
2200
2201 if ((node->type == XML_DOCUMENT_NODE) ||
2202 (node->type == XML_HTML_DOCUMENT_NODE)) {
2203 node = ((xmlDocPtr) node)->children;
2204 } else if ((node->children != NULL)
2205 && (node->type != XML_ENTITY_REF_NODE)) {
2206 /* deep first */
2207 node = node->children;
2208 } else if (node->next != NULL) {
2209 /* then siblings */
2210 node = node->next;
2211 } else {
2212 /* go up to parents->next if needed */
2213 while (node != NULL) {
2214 if (node->parent != NULL) {
2215 node = node->parent;
2216 }
2217 if (node->next != NULL) {
2218 node = node->next;
2219 break;
2220 }
2221 if (node->parent == NULL) {
2222 node = NULL;
2223 break;
2224 }
2225 }
2226 }
2227 }
2228 return (0);
2229 }
2230
2231 /**
2232 * xmlShellDir:
2233 * @ctxt: the shell context
2234 * @arg: unused
2235 * @node: a node
2236 * @node2: unused
2237 *
2238 * Implements the XML shell function "dir"
2239 * dumps information about the node (namespace, attributes, content).
2240 *
2241 * Returns 0
2242 */
2243 int
xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2244 xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2245 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2246 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2247 {
2248 if (!ctxt)
2249 return (0);
2250 if (node == NULL) {
2251 fprintf(ctxt->output, "NULL\n");
2252 return (0);
2253 }
2254 if ((node->type == XML_DOCUMENT_NODE) ||
2255 (node->type == XML_HTML_DOCUMENT_NODE)) {
2256 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
2257 } else if (node->type == XML_ATTRIBUTE_NODE) {
2258 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
2259 } else {
2260 xmlDebugDumpOneNode(ctxt->output, node, 0);
2261 }
2262 return (0);
2263 }
2264
2265 /**
2266 * xmlShellSetContent:
2267 * @ctxt: the shell context
2268 * @value: the content as a string
2269 * @node: a node
2270 * @node2: unused
2271 *
2272 * Implements the XML shell function "dir"
2273 * dumps information about the node (namespace, attributes, content).
2274 *
2275 * Returns 0
2276 */
2277 static int
xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * value,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2278 xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2279 char *value, xmlNodePtr node,
2280 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2281 {
2282 xmlNodePtr results;
2283 xmlParserErrors ret;
2284
2285 if (!ctxt)
2286 return (0);
2287 if (node == NULL) {
2288 fprintf(ctxt->output, "NULL\n");
2289 return (0);
2290 }
2291 if (value == NULL) {
2292 fprintf(ctxt->output, "NULL\n");
2293 return (0);
2294 }
2295
2296 ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
2297 if (ret == XML_ERR_OK) {
2298 if (node->children != NULL) {
2299 xmlFreeNodeList(node->children);
2300 node->children = NULL;
2301 node->last = NULL;
2302 }
2303 xmlAddChildList(node, results);
2304 } else {
2305 fprintf(ctxt->output, "failed to parse content\n");
2306 }
2307 return (0);
2308 }
2309
2310 static void
xmlShellPrintf(void * ctx,const char * msg,...)2311 xmlShellPrintf(void *ctx, const char *msg, ...) {
2312 xmlShellCtxtPtr sctxt = ctx;
2313 va_list ap;
2314
2315 va_start(ap, msg);
2316 vfprintf(sctxt->output, msg, ap);
2317 va_end(ap);
2318 }
2319
2320 #ifdef LIBXML_SCHEMAS_ENABLED
2321 /**
2322 * xmlShellRNGValidate:
2323 * @ctxt: the shell context
2324 * @schemas: the path to the Relax-NG schemas
2325 * @node: a node
2326 * @node2: unused
2327 *
2328 * Implements the XML shell function "relaxng"
2329 * validating the instance against a Relax-NG schemas
2330 *
2331 * Returns 0
2332 */
2333 static int
xmlShellRNGValidate(xmlShellCtxtPtr sctxt,char * schemas,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2334 xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2335 xmlNodePtr node ATTRIBUTE_UNUSED,
2336 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2337 {
2338 xmlRelaxNGPtr relaxngschemas;
2339 xmlRelaxNGParserCtxtPtr ctxt;
2340 xmlRelaxNGValidCtxtPtr vctxt;
2341 int ret;
2342
2343 ctxt = xmlRelaxNGNewParserCtxt(schemas);
2344 xmlRelaxNGSetParserErrors(ctxt, xmlShellPrintf, xmlShellPrintf, sctxt);
2345 relaxngschemas = xmlRelaxNGParse(ctxt);
2346 xmlRelaxNGFreeParserCtxt(ctxt);
2347 if (relaxngschemas == NULL) {
2348 fprintf(sctxt->output,
2349 "Relax-NG schema %s failed to compile\n", schemas);
2350 return(-1);
2351 }
2352 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2353 xmlRelaxNGSetValidErrors(vctxt, xmlShellPrintf, xmlShellPrintf, sctxt);
2354 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2355 if (ret == 0) {
2356 fprintf(sctxt->output, "%s validates\n", sctxt->filename);
2357 } else if (ret > 0) {
2358 fprintf(sctxt->output, "%s fails to validate\n", sctxt->filename);
2359 } else {
2360 fprintf(sctxt->output, "%s validation generated an internal error\n",
2361 sctxt->filename);
2362 }
2363 xmlRelaxNGFreeValidCtxt(vctxt);
2364 if (relaxngschemas != NULL)
2365 xmlRelaxNGFree(relaxngschemas);
2366 return(0);
2367 }
2368 #endif
2369
2370 #ifdef LIBXML_OUTPUT_ENABLED
2371 /**
2372 * xmlShellCat:
2373 * @ctxt: the shell context
2374 * @arg: unused
2375 * @node: a node
2376 * @node2: unused
2377 *
2378 * Implements the XML shell function "cat"
2379 * dumps the serialization node content (XML or HTML).
2380 *
2381 * Returns 0
2382 */
2383 int
xmlShellCat(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2384 xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2385 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2386 {
2387 if (!ctxt)
2388 return (0);
2389 if (node == NULL) {
2390 fprintf(ctxt->output, "NULL\n");
2391 return (0);
2392 }
2393 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2394 #ifdef LIBXML_HTML_ENABLED
2395 if (node->type == XML_HTML_DOCUMENT_NODE)
2396 htmlDocDump(ctxt->output, (htmlDocPtr) node);
2397 else
2398 htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
2399 #else
2400 if (node->type == XML_DOCUMENT_NODE)
2401 xmlDocDump(ctxt->output, (xmlDocPtr) node);
2402 else
2403 xmlElemDump(ctxt->output, ctxt->doc, node);
2404 #endif /* LIBXML_HTML_ENABLED */
2405 } else {
2406 if (node->type == XML_DOCUMENT_NODE)
2407 xmlDocDump(ctxt->output, (xmlDocPtr) node);
2408 else
2409 xmlElemDump(ctxt->output, ctxt->doc, node);
2410 }
2411 fprintf(ctxt->output, "\n");
2412 return (0);
2413 }
2414 #endif /* LIBXML_OUTPUT_ENABLED */
2415
2416 /**
2417 * xmlShellLoad:
2418 * @ctxt: the shell context
2419 * @filename: the file name
2420 * @node: unused
2421 * @node2: unused
2422 *
2423 * Implements the XML shell function "load"
2424 * loads a new document specified by the filename
2425 *
2426 * Returns 0 or -1 if loading failed
2427 */
2428 int
xmlShellLoad(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2429 xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2430 xmlNodePtr node ATTRIBUTE_UNUSED,
2431 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2432 {
2433 xmlDocPtr doc;
2434 int html = 0;
2435
2436 if ((ctxt == NULL) || (filename == NULL)) return(-1);
2437 if (ctxt->doc != NULL)
2438 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
2439
2440 if (html) {
2441 #ifdef LIBXML_HTML_ENABLED
2442 doc = htmlParseFile(filename, NULL);
2443 #else
2444 fprintf(ctxt->output, "HTML support not compiled in\n");
2445 doc = NULL;
2446 #endif /* LIBXML_HTML_ENABLED */
2447 } else {
2448 doc = xmlReadFile(filename,NULL,0);
2449 }
2450 if (doc != NULL) {
2451 if (ctxt->loaded == 1) {
2452 xmlFreeDoc(ctxt->doc);
2453 }
2454 ctxt->loaded = 1;
2455 #ifdef LIBXML_XPATH_ENABLED
2456 xmlXPathFreeContext(ctxt->pctxt);
2457 #endif /* LIBXML_XPATH_ENABLED */
2458 xmlFree(ctxt->filename);
2459 ctxt->doc = doc;
2460 ctxt->node = (xmlNodePtr) doc;
2461 #ifdef LIBXML_XPATH_ENABLED
2462 ctxt->pctxt = xmlXPathNewContext(doc);
2463 #endif /* LIBXML_XPATH_ENABLED */
2464 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
2465 } else
2466 return (-1);
2467 return (0);
2468 }
2469
2470 #ifdef LIBXML_OUTPUT_ENABLED
2471 /**
2472 * xmlShellWrite:
2473 * @ctxt: the shell context
2474 * @filename: the file name
2475 * @node: a node in the tree
2476 * @node2: unused
2477 *
2478 * Implements the XML shell function "write"
2479 * Write the current node to the filename, it saves the serialization
2480 * of the subtree under the @node specified
2481 *
2482 * Returns 0 or -1 in case of error
2483 */
2484 int
xmlShellWrite(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2485 xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
2486 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2487 {
2488 if (node == NULL)
2489 return (-1);
2490 if ((filename == NULL) || (filename[0] == 0)) {
2491 return (-1);
2492 }
2493 #ifdef W_OK
2494 if (access((char *) filename, W_OK)) {
2495 fprintf(ctxt->output,
2496 "Cannot write to %s\n", filename);
2497 return (-1);
2498 }
2499 #endif
2500 switch (node->type) {
2501 case XML_DOCUMENT_NODE:
2502 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2503 fprintf(ctxt->output,
2504 "Failed to write to %s\n", filename);
2505 return (-1);
2506 }
2507 break;
2508 case XML_HTML_DOCUMENT_NODE:
2509 #ifdef LIBXML_HTML_ENABLED
2510 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2511 fprintf(ctxt->output,
2512 "Failed to write to %s\n", filename);
2513 return (-1);
2514 }
2515 #else
2516 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2517 fprintf(ctxt->output,
2518 "Failed to write to %s\n", filename);
2519 return (-1);
2520 }
2521 #endif /* LIBXML_HTML_ENABLED */
2522 break;
2523 default:{
2524 FILE *f;
2525
2526 f = fopen((char *) filename, "w");
2527 if (f == NULL) {
2528 fprintf(ctxt->output,
2529 "Failed to write to %s\n", filename);
2530 return (-1);
2531 }
2532 xmlElemDump(f, ctxt->doc, node);
2533 fclose(f);
2534 }
2535 }
2536 return (0);
2537 }
2538
2539 /**
2540 * xmlShellSave:
2541 * @ctxt: the shell context
2542 * @filename: the file name (optional)
2543 * @node: unused
2544 * @node2: unused
2545 *
2546 * Implements the XML shell function "save"
2547 * Write the current document to the filename, or it's original name
2548 *
2549 * Returns 0 or -1 in case of error
2550 */
2551 int
xmlShellSave(xmlShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2552 xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2553 xmlNodePtr node ATTRIBUTE_UNUSED,
2554 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2555 {
2556 if ((ctxt == NULL) || (ctxt->doc == NULL))
2557 return (-1);
2558 if ((filename == NULL) || (filename[0] == 0))
2559 filename = ctxt->filename;
2560 if (filename == NULL)
2561 return (-1);
2562 #ifdef W_OK
2563 if (access((char *) filename, W_OK)) {
2564 fprintf(ctxt->output,
2565 "Cannot save to %s\n", filename);
2566 return (-1);
2567 }
2568 #endif
2569 switch (ctxt->doc->type) {
2570 case XML_DOCUMENT_NODE:
2571 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2572 fprintf(ctxt->output,
2573 "Failed to save to %s\n", filename);
2574 }
2575 break;
2576 case XML_HTML_DOCUMENT_NODE:
2577 #ifdef LIBXML_HTML_ENABLED
2578 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2579 fprintf(ctxt->output,
2580 "Failed to save to %s\n", filename);
2581 }
2582 #else
2583 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2584 fprintf(ctxt->output,
2585 "Failed to save to %s\n", filename);
2586 }
2587 #endif /* LIBXML_HTML_ENABLED */
2588 break;
2589 default:
2590 fprintf(ctxt->output,
2591 "To save to subparts of a document use the 'write' command\n");
2592 return (-1);
2593
2594 }
2595 return (0);
2596 }
2597 #endif /* LIBXML_OUTPUT_ENABLED */
2598
2599 #ifdef LIBXML_VALID_ENABLED
2600 /**
2601 * xmlShellValidate:
2602 * @ctxt: the shell context
2603 * @dtd: the DTD URI (optional)
2604 * @node: unused
2605 * @node2: unused
2606 *
2607 * Implements the XML shell function "validate"
2608 * Validate the document, if a DTD path is provided, then the validation
2609 * is done against the given DTD.
2610 *
2611 * Returns 0 or -1 in case of error
2612 */
2613 int
xmlShellValidate(xmlShellCtxtPtr ctxt,char * dtd,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)2614 xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2615 xmlNodePtr node ATTRIBUTE_UNUSED,
2616 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2617 {
2618 xmlValidCtxt vctxt;
2619 int res = -1;
2620
2621 if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1);
2622 memset(&vctxt, 0, sizeof(vctxt));
2623 vctxt.error = xmlShellPrintf;
2624 vctxt.warning = xmlShellPrintf;
2625 vctxt.userData = ctxt;
2626
2627 if ((dtd == NULL) || (dtd[0] == 0)) {
2628 res = xmlValidateDocument(&vctxt, ctxt->doc);
2629 } else {
2630 xmlDtdPtr subset;
2631
2632 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2633 if (subset != NULL) {
2634 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2635
2636 xmlFreeDtd(subset);
2637 }
2638 }
2639 return (res);
2640 }
2641 #endif /* LIBXML_VALID_ENABLED */
2642
2643 /**
2644 * xmlShellDu:
2645 * @ctxt: the shell context
2646 * @arg: unused
2647 * @tree: a node defining a subtree
2648 * @node2: unused
2649 *
2650 * Implements the XML shell function "du"
2651 * show the structure of the subtree under node @tree
2652 * If @tree is null, the command works on the current node.
2653 *
2654 * Returns 0 or -1 in case of error
2655 */
2656 int
xmlShellDu(xmlShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr tree,xmlNodePtr node2 ATTRIBUTE_UNUSED)2657 xmlShellDu(xmlShellCtxtPtr ctxt,
2658 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2659 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2660 {
2661 xmlNodePtr node;
2662 int indent = 0, i;
2663
2664 if (!ctxt)
2665 return (-1);
2666
2667 if (tree == NULL)
2668 return (-1);
2669 node = tree;
2670 while (node != NULL) {
2671 if ((node->type == XML_DOCUMENT_NODE) ||
2672 (node->type == XML_HTML_DOCUMENT_NODE)) {
2673 fprintf(ctxt->output, "/\n");
2674 } else if (node->type == XML_ELEMENT_NODE) {
2675 for (i = 0; i < indent; i++)
2676 fprintf(ctxt->output, " ");
2677 if ((node->ns) && (node->ns->prefix))
2678 fprintf(ctxt->output, "%s:", node->ns->prefix);
2679 fprintf(ctxt->output, "%s\n", node->name);
2680 } else {
2681 }
2682
2683 /*
2684 * Browse the full subtree, deep first
2685 */
2686
2687 if ((node->type == XML_DOCUMENT_NODE) ||
2688 (node->type == XML_HTML_DOCUMENT_NODE)) {
2689 node = ((xmlDocPtr) node)->children;
2690 } else if ((node->children != NULL)
2691 && (node->type != XML_ENTITY_REF_NODE)) {
2692 /* deep first */
2693 node = node->children;
2694 indent++;
2695 } else if ((node != tree) && (node->next != NULL)) {
2696 /* then siblings */
2697 node = node->next;
2698 } else if (node != tree) {
2699 /* go up to parents->next if needed */
2700 while (node != tree) {
2701 if (node->parent != NULL) {
2702 node = node->parent;
2703 indent--;
2704 }
2705 if ((node != tree) && (node->next != NULL)) {
2706 node = node->next;
2707 break;
2708 }
2709 if (node->parent == NULL) {
2710 node = NULL;
2711 break;
2712 }
2713 if (node == tree) {
2714 node = NULL;
2715 break;
2716 }
2717 }
2718 /* exit condition */
2719 if (node == tree)
2720 node = NULL;
2721 } else
2722 node = NULL;
2723 }
2724 return (0);
2725 }
2726
2727 /**
2728 * xmlShellPwd:
2729 * @ctxt: the shell context
2730 * @buffer: the output buffer
2731 * @node: a node
2732 * @node2: unused
2733 *
2734 * Implements the XML shell function "pwd"
2735 * Show the full path from the root to the node, if needed building
2736 * thumblers when similar elements exists at a given ancestor level.
2737 * The output is compatible with XPath commands.
2738 *
2739 * Returns 0 or -1 in case of error
2740 */
2741 int
xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * buffer,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)2742 xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2743 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2744 {
2745 xmlChar *path;
2746
2747 if ((node == NULL) || (buffer == NULL))
2748 return (-1);
2749
2750 path = xmlGetNodePath(node);
2751 if (path == NULL)
2752 return (-1);
2753
2754 /*
2755 * This test prevents buffer overflow, because this routine
2756 * is only called by xmlShell, in which the second argument is
2757 * 500 chars long.
2758 * It is a dirty hack before a cleaner solution is found.
2759 * Documentation should mention that the second argument must
2760 * be at least 500 chars long, and could be stripped if too long.
2761 */
2762 snprintf(buffer, 499, "%s", path);
2763 buffer[499] = '0';
2764 xmlFree(path);
2765
2766 return (0);
2767 }
2768
2769 /**
2770 * xmlShell:
2771 * @doc: the initial document
2772 * @filename: the output buffer
2773 * @input: the line reading function
2774 * @output: the output FILE*, defaults to stdout if NULL
2775 *
2776 * Implements the XML shell
2777 * This allow to load, validate, view, modify and save a document
2778 * using a environment similar to a UNIX commandline.
2779 */
2780 void
xmlShell(xmlDocPtr doc,const char * filename,xmlShellReadlineFunc input,FILE * output)2781 xmlShell(xmlDocPtr doc, const char *filename, xmlShellReadlineFunc input,
2782 FILE * output)
2783 {
2784 char prompt[500] = "/ > ";
2785 char *cmdline = NULL, *cur;
2786 char command[100];
2787 char arg[400];
2788 int i;
2789 xmlShellCtxtPtr ctxt;
2790 xmlXPathObjectPtr list;
2791
2792 if (doc == NULL)
2793 return;
2794 if (filename == NULL)
2795 return;
2796 if (input == NULL)
2797 return;
2798 if (output == NULL)
2799 output = stdout;
2800 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
2801 if (ctxt == NULL)
2802 return;
2803 ctxt->loaded = 0;
2804 ctxt->doc = doc;
2805 ctxt->input = input;
2806 ctxt->output = output;
2807 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
2808 ctxt->node = (xmlNodePtr) ctxt->doc;
2809
2810 #ifdef LIBXML_XPATH_ENABLED
2811 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2812 if (ctxt->pctxt == NULL) {
2813 xmlFree(ctxt);
2814 return;
2815 }
2816 #endif /* LIBXML_XPATH_ENABLED */
2817 while (1) {
2818 if (ctxt->node == (xmlNodePtr) ctxt->doc)
2819 snprintf(prompt, sizeof(prompt), "%s > ", "/");
2820 else if ((ctxt->node != NULL) && (ctxt->node->name) &&
2821 (ctxt->node->ns) && (ctxt->node->ns->prefix))
2822 snprintf(prompt, sizeof(prompt), "%s:%s > ",
2823 (ctxt->node->ns->prefix), ctxt->node->name);
2824 else if ((ctxt->node != NULL) && (ctxt->node->name))
2825 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
2826 else
2827 snprintf(prompt, sizeof(prompt), "? > ");
2828 prompt[sizeof(prompt) - 1] = 0;
2829
2830 /*
2831 * Get a new command line
2832 */
2833 cmdline = ctxt->input(prompt);
2834 if (cmdline == NULL)
2835 break;
2836
2837 /*
2838 * Parse the command itself
2839 */
2840 cur = cmdline;
2841 while ((*cur == ' ') || (*cur == '\t'))
2842 cur++;
2843 i = 0;
2844 while ((*cur != ' ') && (*cur != '\t') &&
2845 (*cur != '\n') && (*cur != '\r')) {
2846 if (*cur == 0)
2847 break;
2848 command[i++] = *cur++;
2849 }
2850 command[i] = 0;
2851 if (i == 0)
2852 continue;
2853
2854 /*
2855 * Parse the argument
2856 */
2857 while ((*cur == ' ') || (*cur == '\t'))
2858 cur++;
2859 i = 0;
2860 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2861 if (*cur == 0)
2862 break;
2863 arg[i++] = *cur++;
2864 }
2865 arg[i] = 0;
2866
2867 /*
2868 * start interpreting the command
2869 */
2870 if (!strcmp(command, "exit"))
2871 break;
2872 if (!strcmp(command, "quit"))
2873 break;
2874 if (!strcmp(command, "bye"))
2875 break;
2876 if (!strcmp(command, "help")) {
2877 fprintf(ctxt->output, "\tbase display XML base of the node\n");
2878 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n");
2879 fprintf(ctxt->output, "\tbye leave shell\n");
2880 fprintf(ctxt->output, "\tcat [node] display node or current node\n");
2881 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n");
2882 fprintf(ctxt->output, "\tdir [path] dumps information about the node (namespace, attributes, content)\n");
2883 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n");
2884 fprintf(ctxt->output, "\texit leave shell\n");
2885 fprintf(ctxt->output, "\thelp display this help\n");
2886 fprintf(ctxt->output, "\tfree display memory usage\n");
2887 fprintf(ctxt->output, "\tload [name] load a new document with name\n");
2888 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n");
2889 fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n");
2890 #ifdef LIBXML_XPATH_ENABLED
2891 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n");
2892 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n");
2893 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
2894 fprintf(ctxt->output, "\tsetrootns register all namespace found on the root element\n");
2895 fprintf(ctxt->output, "\t the default namespace if any uses 'defaultns' prefix\n");
2896 #endif /* LIBXML_XPATH_ENABLED */
2897 fprintf(ctxt->output, "\tpwd display current working directory\n");
2898 fprintf(ctxt->output, "\twhereis display absolute path of [path] or current working directory\n");
2899 fprintf(ctxt->output, "\tquit leave shell\n");
2900 #ifdef LIBXML_OUTPUT_ENABLED
2901 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n");
2902 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
2903 #endif /* LIBXML_OUTPUT_ENABLED */
2904 #ifdef LIBXML_VALID_ENABLED
2905 fprintf(ctxt->output, "\tvalidate check the document for errors\n");
2906 #endif /* LIBXML_VALID_ENABLED */
2907 #ifdef LIBXML_SCHEMAS_ENABLED
2908 fprintf(ctxt->output, "\trelaxng rng validate the document against the Relax-NG schemas\n");
2909 #endif
2910 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n");
2911 #ifdef LIBXML_VALID_ENABLED
2912 } else if (!strcmp(command, "validate")) {
2913 xmlShellValidate(ctxt, arg, NULL, NULL);
2914 #endif /* LIBXML_VALID_ENABLED */
2915 } else if (!strcmp(command, "load")) {
2916 xmlShellLoad(ctxt, arg, NULL, NULL);
2917 #ifdef LIBXML_SCHEMAS_ENABLED
2918 } else if (!strcmp(command, "relaxng")) {
2919 xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2920 #endif
2921 #ifdef LIBXML_OUTPUT_ENABLED
2922 } else if (!strcmp(command, "save")) {
2923 xmlShellSave(ctxt, arg, NULL, NULL);
2924 } else if (!strcmp(command, "write")) {
2925 if (arg[0] == 0)
2926 fprintf(ctxt->output,
2927 "Write command requires a filename argument\n");
2928 else
2929 xmlShellWrite(ctxt, arg, ctxt->node, NULL);
2930 #endif /* LIBXML_OUTPUT_ENABLED */
2931 } else if (!strcmp(command, "grep")) {
2932 xmlShellGrep(ctxt, arg, ctxt->node, NULL);
2933 } else if (!strcmp(command, "pwd")) {
2934 char dir[500];
2935
2936 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
2937 fprintf(ctxt->output, "%s\n", dir);
2938 } else if (!strcmp(command, "du")) {
2939 if (arg[0] == 0) {
2940 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2941 } else {
2942 ctxt->pctxt->node = ctxt->node;
2943 #ifdef LIBXML_XPATH_ENABLED
2944 ctxt->pctxt->node = ctxt->node;
2945 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2946 #else
2947 list = NULL;
2948 #endif /* LIBXML_XPATH_ENABLED */
2949 if (list != NULL) {
2950 switch (list->type) {
2951 case XPATH_UNDEFINED:
2952 fprintf(ctxt->output,
2953 "%s: no such node\n", arg);
2954 break;
2955 case XPATH_NODESET:{
2956 int indx;
2957
2958 if (list->nodesetval == NULL)
2959 break;
2960
2961 for (indx = 0;
2962 indx < list->nodesetval->nodeNr;
2963 indx++)
2964 xmlShellDu(ctxt, NULL,
2965 list->nodesetval->
2966 nodeTab[indx], NULL);
2967 break;
2968 }
2969 case XPATH_BOOLEAN:
2970 fprintf(ctxt->output,
2971 "%s is a Boolean\n", arg);
2972 break;
2973 case XPATH_NUMBER:
2974 fprintf(ctxt->output,
2975 "%s is a number\n", arg);
2976 break;
2977 case XPATH_STRING:
2978 fprintf(ctxt->output,
2979 "%s is a string\n", arg);
2980 break;
2981 case XPATH_USERS:
2982 fprintf(ctxt->output,
2983 "%s is user-defined\n", arg);
2984 break;
2985 case XPATH_XSLT_TREE:
2986 fprintf(ctxt->output,
2987 "%s is an XSLT value tree\n",
2988 arg);
2989 break;
2990 }
2991 #ifdef LIBXML_XPATH_ENABLED
2992 xmlXPathFreeObject(list);
2993 #endif
2994 } else {
2995 fprintf(ctxt->output,
2996 "%s: no such node\n", arg);
2997 }
2998 ctxt->pctxt->node = NULL;
2999 }
3000 } else if (!strcmp(command, "base")) {
3001 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
3002 } else if (!strcmp(command, "set")) {
3003 xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
3004 #ifdef LIBXML_XPATH_ENABLED
3005 } else if (!strcmp(command, "setns")) {
3006 if (arg[0] == 0) {
3007 fprintf(ctxt->output,
3008 "setns: prefix=[nsuri] required\n");
3009 } else {
3010 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
3011 }
3012 } else if (!strcmp(command, "setrootns")) {
3013 xmlNodePtr root;
3014
3015 root = xmlDocGetRootElement(ctxt->doc);
3016 xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL);
3017 } else if (!strcmp(command, "xpath")) {
3018 if (arg[0] == 0) {
3019 fprintf(ctxt->output,
3020 "xpath: expression required\n");
3021 } else {
3022 ctxt->pctxt->node = ctxt->node;
3023 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3024 xmlXPathDebugDumpObject(ctxt->output, list, 0);
3025 xmlXPathFreeObject(list);
3026 }
3027 #endif /* LIBXML_XPATH_ENABLED */
3028 #ifdef LIBXML_TREE_ENABLED
3029 } else if (!strcmp(command, "setbase")) {
3030 xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
3031 #endif
3032 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
3033 int dir = (!strcmp(command, "dir"));
3034
3035 if (arg[0] == 0) {
3036 if (dir)
3037 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
3038 else
3039 xmlShellList(ctxt, NULL, ctxt->node, NULL);
3040 } else {
3041 ctxt->pctxt->node = ctxt->node;
3042 #ifdef LIBXML_XPATH_ENABLED
3043 ctxt->pctxt->node = ctxt->node;
3044 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3045 #else
3046 list = NULL;
3047 #endif /* LIBXML_XPATH_ENABLED */
3048 if (list != NULL) {
3049 switch (list->type) {
3050 case XPATH_UNDEFINED:
3051 fprintf(ctxt->output,
3052 "%s: no such node\n", arg);
3053 break;
3054 case XPATH_NODESET:{
3055 int indx;
3056
3057 if (list->nodesetval == NULL)
3058 break;
3059
3060 for (indx = 0;
3061 indx < list->nodesetval->nodeNr;
3062 indx++) {
3063 if (dir)
3064 xmlShellDir(ctxt, NULL,
3065 list->nodesetval->
3066 nodeTab[indx], NULL);
3067 else
3068 xmlShellList(ctxt, NULL,
3069 list->nodesetval->
3070 nodeTab[indx], NULL);
3071 }
3072 break;
3073 }
3074 case XPATH_BOOLEAN:
3075 fprintf(ctxt->output,
3076 "%s is a Boolean\n", arg);
3077 break;
3078 case XPATH_NUMBER:
3079 fprintf(ctxt->output,
3080 "%s is a number\n", arg);
3081 break;
3082 case XPATH_STRING:
3083 fprintf(ctxt->output,
3084 "%s is a string\n", arg);
3085 break;
3086 case XPATH_USERS:
3087 fprintf(ctxt->output,
3088 "%s is user-defined\n", arg);
3089 break;
3090 case XPATH_XSLT_TREE:
3091 fprintf(ctxt->output,
3092 "%s is an XSLT value tree\n",
3093 arg);
3094 break;
3095 }
3096 #ifdef LIBXML_XPATH_ENABLED
3097 xmlXPathFreeObject(list);
3098 #endif
3099 } else {
3100 fprintf(ctxt->output,
3101 "%s: no such node\n", arg);
3102 }
3103 ctxt->pctxt->node = NULL;
3104 }
3105 } else if (!strcmp(command, "whereis")) {
3106 char dir[500];
3107
3108 if (arg[0] == 0) {
3109 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
3110 fprintf(ctxt->output, "%s\n", dir);
3111 } else {
3112 ctxt->pctxt->node = ctxt->node;
3113 #ifdef LIBXML_XPATH_ENABLED
3114 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3115 #else
3116 list = NULL;
3117 #endif /* LIBXML_XPATH_ENABLED */
3118 if (list != NULL) {
3119 switch (list->type) {
3120 case XPATH_UNDEFINED:
3121 fprintf(ctxt->output,
3122 "%s: no such node\n", arg);
3123 break;
3124 case XPATH_NODESET:{
3125 int indx;
3126
3127 if (list->nodesetval == NULL)
3128 break;
3129
3130 for (indx = 0;
3131 indx < list->nodesetval->nodeNr;
3132 indx++) {
3133 if (!xmlShellPwd(ctxt, dir, list->nodesetval->
3134 nodeTab[indx], NULL))
3135 fprintf(ctxt->output, "%s\n", dir);
3136 }
3137 break;
3138 }
3139 case XPATH_BOOLEAN:
3140 fprintf(ctxt->output,
3141 "%s is a Boolean\n", arg);
3142 break;
3143 case XPATH_NUMBER:
3144 fprintf(ctxt->output,
3145 "%s is a number\n", arg);
3146 break;
3147 case XPATH_STRING:
3148 fprintf(ctxt->output,
3149 "%s is a string\n", arg);
3150 break;
3151 case XPATH_USERS:
3152 fprintf(ctxt->output,
3153 "%s is user-defined\n", arg);
3154 break;
3155 case XPATH_XSLT_TREE:
3156 fprintf(ctxt->output,
3157 "%s is an XSLT value tree\n",
3158 arg);
3159 break;
3160 }
3161 #ifdef LIBXML_XPATH_ENABLED
3162 xmlXPathFreeObject(list);
3163 #endif
3164 } else {
3165 fprintf(ctxt->output,
3166 "%s: no such node\n", arg);
3167 }
3168 ctxt->pctxt->node = NULL;
3169 }
3170 } else if (!strcmp(command, "cd")) {
3171 if (arg[0] == 0) {
3172 ctxt->node = (xmlNodePtr) ctxt->doc;
3173 } else {
3174 #ifdef LIBXML_XPATH_ENABLED
3175 int l;
3176
3177 ctxt->pctxt->node = ctxt->node;
3178 l = strlen(arg);
3179 if ((l >= 2) && (arg[l - 1] == '/'))
3180 arg[l - 1] = 0;
3181 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3182 #else
3183 list = NULL;
3184 #endif /* LIBXML_XPATH_ENABLED */
3185 if (list != NULL) {
3186 switch (list->type) {
3187 case XPATH_UNDEFINED:
3188 fprintf(ctxt->output,
3189 "%s: no such node\n", arg);
3190 break;
3191 case XPATH_NODESET:
3192 if (list->nodesetval != NULL) {
3193 if (list->nodesetval->nodeNr == 1) {
3194 ctxt->node = list->nodesetval->nodeTab[0];
3195 if ((ctxt->node != NULL) &&
3196 (ctxt->node->type ==
3197 XML_NAMESPACE_DECL)) {
3198 fprintf(ctxt->output,
3199 "cannot cd to namespace\n");
3200 ctxt->node = NULL;
3201 }
3202 } else
3203 fprintf(ctxt->output,
3204 "%s is a %d Node Set\n",
3205 arg,
3206 list->nodesetval->nodeNr);
3207 } else
3208 fprintf(ctxt->output,
3209 "%s is an empty Node Set\n",
3210 arg);
3211 break;
3212 case XPATH_BOOLEAN:
3213 fprintf(ctxt->output,
3214 "%s is a Boolean\n", arg);
3215 break;
3216 case XPATH_NUMBER:
3217 fprintf(ctxt->output,
3218 "%s is a number\n", arg);
3219 break;
3220 case XPATH_STRING:
3221 fprintf(ctxt->output,
3222 "%s is a string\n", arg);
3223 break;
3224 case XPATH_USERS:
3225 fprintf(ctxt->output,
3226 "%s is user-defined\n", arg);
3227 break;
3228 case XPATH_XSLT_TREE:
3229 fprintf(ctxt->output,
3230 "%s is an XSLT value tree\n",
3231 arg);
3232 break;
3233 }
3234 #ifdef LIBXML_XPATH_ENABLED
3235 xmlXPathFreeObject(list);
3236 #endif
3237 } else {
3238 fprintf(ctxt->output,
3239 "%s: no such node\n", arg);
3240 }
3241 ctxt->pctxt->node = NULL;
3242 }
3243 #ifdef LIBXML_OUTPUT_ENABLED
3244 } else if (!strcmp(command, "cat")) {
3245 if (arg[0] == 0) {
3246 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
3247 } else {
3248 ctxt->pctxt->node = ctxt->node;
3249 #ifdef LIBXML_XPATH_ENABLED
3250 ctxt->pctxt->node = ctxt->node;
3251 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3252 #else
3253 list = NULL;
3254 #endif /* LIBXML_XPATH_ENABLED */
3255 if (list != NULL) {
3256 switch (list->type) {
3257 case XPATH_UNDEFINED:
3258 fprintf(ctxt->output,
3259 "%s: no such node\n", arg);
3260 break;
3261 case XPATH_NODESET:{
3262 int indx;
3263
3264 if (list->nodesetval == NULL)
3265 break;
3266
3267 for (indx = 0;
3268 indx < list->nodesetval->nodeNr;
3269 indx++) {
3270 if (i > 0)
3271 fprintf(ctxt->output, " -------\n");
3272 xmlShellCat(ctxt, NULL,
3273 list->nodesetval->
3274 nodeTab[indx], NULL);
3275 }
3276 break;
3277 }
3278 case XPATH_BOOLEAN:
3279 fprintf(ctxt->output,
3280 "%s is a Boolean\n", arg);
3281 break;
3282 case XPATH_NUMBER:
3283 fprintf(ctxt->output,
3284 "%s is a number\n", arg);
3285 break;
3286 case XPATH_STRING:
3287 fprintf(ctxt->output,
3288 "%s is a string\n", arg);
3289 break;
3290 case XPATH_USERS:
3291 fprintf(ctxt->output,
3292 "%s is user-defined\n", arg);
3293 break;
3294 case XPATH_XSLT_TREE:
3295 fprintf(ctxt->output,
3296 "%s is an XSLT value tree\n",
3297 arg);
3298 break;
3299 }
3300 #ifdef LIBXML_XPATH_ENABLED
3301 xmlXPathFreeObject(list);
3302 #endif
3303 } else {
3304 fprintf(ctxt->output,
3305 "%s: no such node\n", arg);
3306 }
3307 ctxt->pctxt->node = NULL;
3308 }
3309 #endif /* LIBXML_OUTPUT_ENABLED */
3310 } else {
3311 fprintf(ctxt->output,
3312 "Unknown command %s\n", command);
3313 }
3314 free(cmdline); /* not xmlFree here ! */
3315 cmdline = NULL;
3316 }
3317 #ifdef LIBXML_XPATH_ENABLED
3318 xmlXPathFreeContext(ctxt->pctxt);
3319 #endif /* LIBXML_XPATH_ENABLED */
3320 if (ctxt->loaded) {
3321 xmlFreeDoc(ctxt->doc);
3322 }
3323 if (ctxt->filename != NULL)
3324 xmlFree(ctxt->filename);
3325 xmlFree(ctxt);
3326 if (cmdline != NULL)
3327 free(cmdline); /* not xmlFree here ! */
3328 }
3329
3330 #endif /* LIBXML_XPATH_ENABLED */
3331
3332 #endif /* LIBXML_DEBUG_ENABLED */
3333