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