1 /*
2 * shell.c: The xmllint shell
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <[email protected]>
7 */
8
9 #include "libxml.h"
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #ifdef _WIN32
16 #include <io.h>
17 #else
18 #include <unistd.h>
19 #endif
20
21 #ifdef HAVE_LIBREADLINE
22 #include <readline/readline.h>
23 #ifdef HAVE_LIBHISTORY
24 #include <readline/history.h>
25 #endif
26 #endif
27
28 #include <libxml/debugXML.h>
29 #include <libxml/HTMLtree.h>
30 #include <libxml/parser.h>
31 #include <libxml/uri.h>
32 #include <libxml/xpath.h>
33 #include <libxml/xpathInternals.h>
34 #ifdef LIBXML_SCHEMAS_ENABLED
35 #include <libxml/relaxng.h>
36 #endif
37
38 #include "private/shell.h"
39
40 #ifndef STDIN_FILENO
41 #define STDIN_FILENO 0
42 #endif
43
44 /*
45 * TODO: Improvement/cleanups for the XML shell
46 * - allow to shell out an editor on a subpart
47 * - cleanup function registrations (with help) and calling
48 * - provide registration routines
49 */
50
51 typedef struct _xmllintShellCtxt xmllintShellCtxt;
52 typedef xmllintShellCtxt *xmllintShellCtxtPtr;
53 struct _xmllintShellCtxt {
54 char *filename;
55 xmlDocPtr doc;
56 xmlNodePtr node;
57 #ifdef LIBXML_XPATH_ENABLED
58 xmlXPathContextPtr pctxt;
59 #endif
60 int loaded;
61 FILE *output;
62 };
63
64 /**
65 * xmllintLsCountNode:
66 * @node: the node to count
67 *
68 * Count the children of @node.
69 *
70 * Returns the number of children of @node.
71 */
72 static int
xmllintLsCountNode(xmlNodePtr node)73 xmllintLsCountNode(xmlNodePtr node) {
74 int ret = 0;
75 xmlNodePtr list = NULL;
76
77 if (node == NULL)
78 return(0);
79
80 switch (node->type) {
81 case XML_ELEMENT_NODE:
82 list = node->children;
83 break;
84 case XML_DOCUMENT_NODE:
85 case XML_HTML_DOCUMENT_NODE:
86 list = ((xmlDocPtr) node)->children;
87 break;
88 case XML_ATTRIBUTE_NODE:
89 list = ((xmlAttrPtr) node)->children;
90 break;
91 case XML_TEXT_NODE:
92 case XML_CDATA_SECTION_NODE:
93 case XML_PI_NODE:
94 case XML_COMMENT_NODE:
95 if (node->content != NULL) {
96 ret = xmlStrlen(node->content);
97 }
98 break;
99 case XML_ENTITY_REF_NODE:
100 case XML_DOCUMENT_TYPE_NODE:
101 case XML_ENTITY_NODE:
102 case XML_DOCUMENT_FRAG_NODE:
103 case XML_NOTATION_NODE:
104 case XML_DTD_NODE:
105 case XML_ELEMENT_DECL:
106 case XML_ATTRIBUTE_DECL:
107 case XML_ENTITY_DECL:
108 case XML_NAMESPACE_DECL:
109 case XML_XINCLUDE_START:
110 case XML_XINCLUDE_END:
111 ret = 1;
112 break;
113 }
114 for (;list != NULL;ret++)
115 list = list->next;
116 return(ret);
117 }
118
119 /**
120 * xmllintLsOneNode:
121 * @output: the FILE * for the output
122 * @node: the node to dump
123 *
124 * Dump to @output the type and name of @node.
125 */
126 static void
xmllintLsOneNode(FILE * output,xmlNodePtr node)127 xmllintLsOneNode(FILE *output, xmlNodePtr node) {
128 if (output == NULL) return;
129 if (node == NULL) {
130 fprintf(output, "NULL\n");
131 return;
132 }
133 switch (node->type) {
134 case XML_ELEMENT_NODE:
135 fprintf(output, "-");
136 break;
137 case XML_ATTRIBUTE_NODE:
138 fprintf(output, "a");
139 break;
140 case XML_TEXT_NODE:
141 fprintf(output, "t");
142 break;
143 case XML_CDATA_SECTION_NODE:
144 fprintf(output, "C");
145 break;
146 case XML_ENTITY_REF_NODE:
147 fprintf(output, "e");
148 break;
149 case XML_ENTITY_NODE:
150 fprintf(output, "E");
151 break;
152 case XML_PI_NODE:
153 fprintf(output, "p");
154 break;
155 case XML_COMMENT_NODE:
156 fprintf(output, "c");
157 break;
158 case XML_DOCUMENT_NODE:
159 fprintf(output, "d");
160 break;
161 case XML_HTML_DOCUMENT_NODE:
162 fprintf(output, "h");
163 break;
164 case XML_DOCUMENT_TYPE_NODE:
165 fprintf(output, "T");
166 break;
167 case XML_DOCUMENT_FRAG_NODE:
168 fprintf(output, "F");
169 break;
170 case XML_NOTATION_NODE:
171 fprintf(output, "N");
172 break;
173 case XML_NAMESPACE_DECL:
174 fprintf(output, "n");
175 break;
176 default:
177 fprintf(output, "?");
178 }
179 if (node->type != XML_NAMESPACE_DECL) {
180 if (node->properties != NULL)
181 fprintf(output, "a");
182 else
183 fprintf(output, "-");
184 if (node->nsDef != NULL)
185 fprintf(output, "n");
186 else
187 fprintf(output, "-");
188 }
189
190 fprintf(output, " %8d ", xmllintLsCountNode(node));
191
192 switch (node->type) {
193 case XML_ELEMENT_NODE:
194 if (node->name != NULL) {
195 if ((node->ns != NULL) && (node->ns->prefix != NULL))
196 fprintf(output, "%s:", node->ns->prefix);
197 fprintf(output, "%s", (const char *) node->name);
198 }
199 break;
200 case XML_ATTRIBUTE_NODE:
201 if (node->name != NULL)
202 fprintf(output, "%s", (const char *) node->name);
203 break;
204 case XML_TEXT_NODE:
205 #ifdef LIBXML_DEBUG_ENABLED
206 if (node->content != NULL) {
207 xmlDebugDumpString(output, node->content);
208 }
209 #endif
210 break;
211 case XML_CDATA_SECTION_NODE:
212 break;
213 case XML_ENTITY_REF_NODE:
214 if (node->name != NULL)
215 fprintf(output, "%s", (const char *) node->name);
216 break;
217 case XML_ENTITY_NODE:
218 if (node->name != NULL)
219 fprintf(output, "%s", (const char *) node->name);
220 break;
221 case XML_PI_NODE:
222 if (node->name != NULL)
223 fprintf(output, "%s", (const char *) node->name);
224 break;
225 case XML_COMMENT_NODE:
226 break;
227 case XML_DOCUMENT_NODE:
228 break;
229 case XML_HTML_DOCUMENT_NODE:
230 break;
231 case XML_DOCUMENT_TYPE_NODE:
232 break;
233 case XML_DOCUMENT_FRAG_NODE:
234 break;
235 case XML_NOTATION_NODE:
236 break;
237 case XML_NAMESPACE_DECL: {
238 xmlNsPtr ns = (xmlNsPtr) node;
239
240 if (ns->prefix == NULL)
241 fprintf(output, "default -> %s", (char *)ns->href);
242 else
243 fprintf(output, "%s -> %s", (char *)ns->prefix,
244 (char *)ns->href);
245 break;
246 }
247 default:
248 if (node->name != NULL)
249 fprintf(output, "%s", (const char *) node->name);
250 }
251 fprintf(output, "\n");
252 }
253
254 /**
255 * xmllintShellList:
256 * @ctxt: the shell context
257 * @arg: unused
258 * @node: a node
259 * @node2: unused
260 *
261 * Implements the XML shell function "ls"
262 * Does an Unix like listing of the given node (like a directory)
263 *
264 * Returns 0
265 */
266 static int
xmllintShellList(xmllintShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)267 xmllintShellList(xmllintShellCtxtPtr ctxt,
268 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
269 xmlNodePtr node2 ATTRIBUTE_UNUSED)
270 {
271 xmlNodePtr cur;
272 if (!ctxt)
273 return (0);
274 if (node == NULL) {
275 fprintf(ctxt->output, "NULL\n");
276 return (0);
277 }
278 if ((node->type == XML_DOCUMENT_NODE) ||
279 (node->type == XML_HTML_DOCUMENT_NODE)) {
280 cur = ((xmlDocPtr) node)->children;
281 } else if (node->type == XML_NAMESPACE_DECL) {
282 xmllintLsOneNode(ctxt->output, node);
283 return (0);
284 } else if (node->children != NULL) {
285 cur = node->children;
286 } else {
287 xmllintLsOneNode(ctxt->output, node);
288 return (0);
289 }
290 while (cur != NULL) {
291 xmllintLsOneNode(ctxt->output, cur);
292 cur = cur->next;
293 }
294 return (0);
295 }
296
297 /**
298 * xmllintShellBase:
299 * @ctxt: the shell context
300 * @arg: unused
301 * @node: a node
302 * @node2: unused
303 *
304 * Implements the XML shell function "base"
305 * dumps the current XML base of the node
306 *
307 * Returns 0
308 */
309 static int
xmllintShellBase(xmllintShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)310 xmllintShellBase(xmllintShellCtxtPtr ctxt,
311 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
312 xmlNodePtr node2 ATTRIBUTE_UNUSED)
313 {
314 xmlChar *base;
315 if (!ctxt)
316 return 0;
317 if (node == NULL) {
318 fprintf(ctxt->output, "NULL\n");
319 return (0);
320 }
321
322 base = xmlNodeGetBase(node->doc, node);
323
324 if (base == NULL) {
325 fprintf(ctxt->output, " No base found !!!\n");
326 } else {
327 fprintf(ctxt->output, "%s\n", base);
328 xmlFree(base);
329 }
330 return (0);
331 }
332
333 /**
334 * xmllintShellSetBase:
335 * @ctxt: the shell context
336 * @arg: the new base
337 * @node: a node
338 * @node2: unused
339 *
340 * Implements the XML shell function "setbase"
341 * change the current XML base of the node
342 *
343 * Returns 0
344 */
345 static int
xmllintShellSetBase(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)346 xmllintShellSetBase(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
347 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
348 xmlNodePtr node2 ATTRIBUTE_UNUSED)
349 {
350 xmlNodeSetBase(node, (xmlChar*) arg);
351 return (0);
352 }
353
354 #ifdef LIBXML_XPATH_ENABLED
355 /**
356 * xmllintShellRegisterNamespace:
357 * @ctxt: the shell context
358 * @arg: a string in prefix=nsuri format
359 * @node: unused
360 * @node2: unused
361 *
362 * Implements the XML shell function "setns"
363 * register/unregister a prefix=namespace pair
364 * on the XPath context
365 *
366 * Returns 0 on success and a negative value otherwise.
367 */
368 static int
xmllintShellRegisterNamespace(xmllintShellCtxtPtr ctxt,char * arg,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)369 xmllintShellRegisterNamespace(xmllintShellCtxtPtr ctxt, char *arg,
370 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
371 {
372 xmlChar* nsListDup;
373 xmlChar* prefix;
374 xmlChar* href;
375 xmlChar* next;
376
377 nsListDup = xmlStrdup((xmlChar *) arg);
378 next = nsListDup;
379 while(next != NULL) {
380 /* skip spaces */
381 /*while((*next) == ' ') next++;*/
382 if((*next) == '\0') break;
383
384 /* find prefix */
385 prefix = next;
386 next = (xmlChar*)xmlStrchr(next, '=');
387 if(next == NULL) {
388 fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
389 xmlFree(nsListDup);
390 return(-1);
391 }
392 *(next++) = '\0';
393
394 /* find href */
395 href = next;
396 next = (xmlChar*)xmlStrchr(next, ' ');
397 if(next != NULL) {
398 *(next++) = '\0';
399 }
400
401 /* do register namespace */
402 if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
403 fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
404 xmlFree(nsListDup);
405 return(-1);
406 }
407 }
408
409 xmlFree(nsListDup);
410 return(0);
411 }
412 /**
413 * xmllintShellRegisterRootNamespaces:
414 * @ctxt: the shell context
415 * @arg: unused
416 * @node: the root element
417 * @node2: unused
418 *
419 * Implements the XML shell function "setrootns"
420 * which registers all namespaces declarations found on the root element.
421 *
422 * Returns 0 on success and a negative value otherwise.
423 */
424 static int
xmllintShellRegisterRootNamespaces(xmllintShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr root,xmlNodePtr node2 ATTRIBUTE_UNUSED)425 xmllintShellRegisterRootNamespaces(xmllintShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
426 xmlNodePtr root, xmlNodePtr node2 ATTRIBUTE_UNUSED)
427 {
428 xmlNsPtr ns;
429
430 if ((root == NULL) || (root->type != XML_ELEMENT_NODE) ||
431 (root->nsDef == NULL) || (ctxt == NULL) || (ctxt->pctxt == NULL))
432 return(-1);
433 ns = root->nsDef;
434 while (ns != NULL) {
435 if (ns->prefix == NULL)
436 xmlXPathRegisterNs(ctxt->pctxt, BAD_CAST "defaultns", ns->href);
437 else
438 xmlXPathRegisterNs(ctxt->pctxt, ns->prefix, ns->href);
439 ns = ns->next;
440 }
441 return(0);
442 }
443 #endif
444
445 /**
446 * xmllintShellGrep:
447 * @ctxt: the shell context
448 * @arg: the string or regular expression to find
449 * @node: a node
450 * @node2: unused
451 *
452 * Implements the XML shell function "grep"
453 * dumps information about the node (namespace, attributes, content).
454 *
455 * Returns 0
456 */
457 static int
xmllintShellGrep(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)458 xmllintShellGrep(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
459 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
460 {
461 if (!ctxt)
462 return (0);
463 if (node == NULL)
464 return (0);
465 if (arg == NULL)
466 return (0);
467 #ifdef LIBXML_REGEXP_ENABLED
468 if ((xmlStrchr((xmlChar *) arg, '?')) ||
469 (xmlStrchr((xmlChar *) arg, '*')) ||
470 (xmlStrchr((xmlChar *) arg, '.')) ||
471 (xmlStrchr((xmlChar *) arg, '['))) {
472 }
473 #endif
474 while (node != NULL) {
475 if (node->type == XML_COMMENT_NODE) {
476 if (xmlStrstr(node->content, (xmlChar *) arg)) {
477 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
478 xmllintShellList(ctxt, NULL, node, NULL);
479 }
480 } else if (node->type == XML_TEXT_NODE) {
481 if (xmlStrstr(node->content, (xmlChar *) arg)) {
482 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
483 xmllintShellList(ctxt, NULL, node->parent, NULL);
484 }
485 }
486
487 /*
488 * Browse the full subtree, deep first
489 */
490
491 if ((node->type == XML_DOCUMENT_NODE) ||
492 (node->type == XML_HTML_DOCUMENT_NODE)) {
493 node = ((xmlDocPtr) node)->children;
494 } else if ((node->children != NULL)
495 && (node->type != XML_ENTITY_REF_NODE)) {
496 /* deep first */
497 node = node->children;
498 } else if (node->next != NULL) {
499 /* then siblings */
500 node = node->next;
501 } else {
502 /* go up to parents->next if needed */
503 while (node != NULL) {
504 if (node->parent != NULL) {
505 node = node->parent;
506 }
507 if (node->next != NULL) {
508 node = node->next;
509 break;
510 }
511 if (node->parent == NULL) {
512 node = NULL;
513 break;
514 }
515 }
516 }
517 }
518 return (0);
519 }
520
521 /**
522 * xmllintShellDir:
523 * @ctxt: the shell context
524 * @arg: unused
525 * @node: a node
526 * @node2: unused
527 *
528 * Implements the XML shell function "dir"
529 * dumps information about the node (namespace, attributes, content).
530 *
531 * Returns 0
532 */
533 static int
xmllintShellDir(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)534 xmllintShellDir(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
535 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
536 xmlNodePtr node2 ATTRIBUTE_UNUSED)
537 {
538 if (!ctxt)
539 return (0);
540 if (node == NULL) {
541 fprintf(ctxt->output, "NULL\n");
542 return (0);
543 }
544 #ifdef LIBXML_DEBUG_ENABLED
545 if ((node->type == XML_DOCUMENT_NODE) ||
546 (node->type == XML_HTML_DOCUMENT_NODE)) {
547 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
548 } else if (node->type == XML_ATTRIBUTE_NODE) {
549 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
550 } else {
551 xmlDebugDumpOneNode(ctxt->output, node, 0);
552 }
553 #endif
554 return (0);
555 }
556
557 /**
558 * xmllintShellSetContent:
559 * @ctxt: the shell context
560 * @value: the content as a string
561 * @node: a node
562 * @node2: unused
563 *
564 * Implements the XML shell function "dir"
565 * dumps information about the node (namespace, attributes, content).
566 *
567 * Returns 0
568 */
569 static int
xmllintShellSetContent(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * value,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)570 xmllintShellSetContent(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
571 char *value, xmlNodePtr node,
572 xmlNodePtr node2 ATTRIBUTE_UNUSED)
573 {
574 xmlNodePtr results;
575 xmlParserErrors ret;
576
577 if (!ctxt)
578 return (0);
579 if (node == NULL) {
580 fprintf(ctxt->output, "NULL\n");
581 return (0);
582 }
583 if (value == NULL) {
584 fprintf(ctxt->output, "NULL\n");
585 return (0);
586 }
587
588 ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
589 if (ret == XML_ERR_OK) {
590 if (node->children != NULL) {
591 xmlFreeNodeList(node->children);
592 node->children = NULL;
593 node->last = NULL;
594 }
595 xmlAddChildList(node, results);
596 } else {
597 fprintf(ctxt->output, "failed to parse content\n");
598 }
599 return (0);
600 }
601
602 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
603 static void
xmllintShellPrintf(void * ctx,const char * msg,...)604 xmllintShellPrintf(void *ctx, const char *msg, ...) {
605 xmllintShellCtxtPtr sctxt = ctx;
606 va_list ap;
607
608 va_start(ap, msg);
609 vfprintf(sctxt->output, msg, ap);
610 va_end(ap);
611 }
612 #endif /* defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */
613
614 #ifdef LIBXML_SCHEMAS_ENABLED
615 /**
616 * xmllintShellRNGValidate:
617 * @ctxt: the shell context
618 * @schemas: the path to the Relax-NG schemas
619 * @node: a node
620 * @node2: unused
621 *
622 * Implements the XML shell function "relaxng"
623 * validating the instance against a Relax-NG schemas
624 *
625 * Returns 0
626 */
627 static int
xmllintShellRNGValidate(xmllintShellCtxtPtr sctxt,char * schemas,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)628 xmllintShellRNGValidate(xmllintShellCtxtPtr sctxt, char *schemas,
629 xmlNodePtr node ATTRIBUTE_UNUSED,
630 xmlNodePtr node2 ATTRIBUTE_UNUSED)
631 {
632 xmlRelaxNGPtr relaxngschemas;
633 xmlRelaxNGParserCtxtPtr ctxt;
634 xmlRelaxNGValidCtxtPtr vctxt;
635 int ret;
636
637 ctxt = xmlRelaxNGNewParserCtxt(schemas);
638 xmlRelaxNGSetParserErrors(ctxt, xmllintShellPrintf, xmllintShellPrintf, sctxt);
639 relaxngschemas = xmlRelaxNGParse(ctxt);
640 xmlRelaxNGFreeParserCtxt(ctxt);
641 if (relaxngschemas == NULL) {
642 fprintf(sctxt->output,
643 "Relax-NG schema %s failed to compile\n", schemas);
644 return(-1);
645 }
646 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
647 xmlRelaxNGSetValidErrors(vctxt, xmllintShellPrintf, xmllintShellPrintf, sctxt);
648 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
649 if (ret == 0) {
650 fprintf(sctxt->output, "%s validates\n", sctxt->filename);
651 } else if (ret > 0) {
652 fprintf(sctxt->output, "%s fails to validate\n", sctxt->filename);
653 } else {
654 fprintf(sctxt->output, "%s validation generated an internal error\n",
655 sctxt->filename);
656 }
657 xmlRelaxNGFreeValidCtxt(vctxt);
658 if (relaxngschemas != NULL)
659 xmlRelaxNGFree(relaxngschemas);
660 return(0);
661 }
662 #endif
663
664 #ifdef LIBXML_OUTPUT_ENABLED
665 /**
666 * xmllintShellCat:
667 * @ctxt: the shell context
668 * @arg: unused
669 * @node: a node
670 * @node2: unused
671 *
672 * Implements the XML shell function "cat"
673 * dumps the serialization node content (XML or HTML).
674 *
675 * Returns 0
676 */
677 static int
xmllintShellCat(xmllintShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)678 xmllintShellCat(xmllintShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
679 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
680 {
681 if (!ctxt)
682 return (0);
683 if (node == NULL) {
684 fprintf(ctxt->output, "NULL\n");
685 return (0);
686 }
687 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
688 #ifdef LIBXML_HTML_ENABLED
689 if (node->type == XML_HTML_DOCUMENT_NODE)
690 htmlDocDump(ctxt->output, (htmlDocPtr) node);
691 else
692 htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
693 #else
694 if (node->type == XML_DOCUMENT_NODE)
695 xmlDocDump(ctxt->output, (xmlDocPtr) node);
696 else
697 xmlElemDump(ctxt->output, ctxt->doc, node);
698 #endif /* LIBXML_HTML_ENABLED */
699 } else {
700 if (node->type == XML_DOCUMENT_NODE)
701 xmlDocDump(ctxt->output, (xmlDocPtr) node);
702 else
703 xmlElemDump(ctxt->output, ctxt->doc, node);
704 }
705 fprintf(ctxt->output, "\n");
706 return (0);
707 }
708 #endif /* LIBXML_OUTPUT_ENABLED */
709
710 /**
711 * xmllintShellLoad:
712 * @ctxt: the shell context
713 * @filename: the file name
714 * @node: unused
715 * @node2: unused
716 *
717 * Implements the XML shell function "load"
718 * loads a new document specified by the filename
719 *
720 * Returns 0 or -1 if loading failed
721 */
722 static int
xmllintShellLoad(xmllintShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)723 xmllintShellLoad(xmllintShellCtxtPtr ctxt, char *filename,
724 xmlNodePtr node ATTRIBUTE_UNUSED,
725 xmlNodePtr node2 ATTRIBUTE_UNUSED)
726 {
727 xmlDocPtr doc;
728 int html = 0;
729
730 if ((ctxt == NULL) || (filename == NULL)) return(-1);
731 if (ctxt->doc != NULL)
732 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
733
734 if (html) {
735 #ifdef LIBXML_HTML_ENABLED
736 doc = htmlParseFile(filename, NULL);
737 #else
738 fprintf(ctxt->output, "HTML support not compiled in\n");
739 doc = NULL;
740 #endif /* LIBXML_HTML_ENABLED */
741 } else {
742 doc = xmlReadFile(filename,NULL,0);
743 }
744 if (doc != NULL) {
745 if (ctxt->loaded == 1) {
746 xmlFreeDoc(ctxt->doc);
747 }
748 ctxt->loaded = 1;
749 #ifdef LIBXML_XPATH_ENABLED
750 xmlXPathFreeContext(ctxt->pctxt);
751 #endif /* LIBXML_XPATH_ENABLED */
752 xmlFree(ctxt->filename);
753 ctxt->doc = doc;
754 ctxt->node = (xmlNodePtr) doc;
755 #ifdef LIBXML_XPATH_ENABLED
756 ctxt->pctxt = xmlXPathNewContext(doc);
757 #endif /* LIBXML_XPATH_ENABLED */
758 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
759 } else
760 return (-1);
761 return (0);
762 }
763
764 #ifdef LIBXML_OUTPUT_ENABLED
765 /**
766 * xmllintShellWrite:
767 * @ctxt: the shell context
768 * @filename: the file name
769 * @node: a node in the tree
770 * @node2: unused
771 *
772 * Implements the XML shell function "write"
773 * Write the current node to the filename, it saves the serialization
774 * of the subtree under the @node specified
775 *
776 * Returns 0 or -1 in case of error
777 */
778 static int
xmllintShellWrite(xmllintShellCtxtPtr ctxt,char * filename,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)779 xmllintShellWrite(xmllintShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
780 xmlNodePtr node2 ATTRIBUTE_UNUSED)
781 {
782 if (node == NULL)
783 return (-1);
784 if ((filename == NULL) || (filename[0] == 0)) {
785 return (-1);
786 }
787 switch (node->type) {
788 case XML_DOCUMENT_NODE:
789 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
790 fprintf(ctxt->output,
791 "Failed to write to %s\n", filename);
792 return (-1);
793 }
794 break;
795 case XML_HTML_DOCUMENT_NODE:
796 #ifdef LIBXML_HTML_ENABLED
797 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
798 fprintf(ctxt->output,
799 "Failed to write to %s\n", filename);
800 return (-1);
801 }
802 #else
803 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
804 fprintf(ctxt->output,
805 "Failed to write to %s\n", filename);
806 return (-1);
807 }
808 #endif /* LIBXML_HTML_ENABLED */
809 break;
810 default:{
811 FILE *f;
812
813 f = fopen((char *) filename, "wb");
814 if (f == NULL) {
815 fprintf(ctxt->output,
816 "Failed to write to %s\n", filename);
817 return (-1);
818 }
819 xmlElemDump(f, ctxt->doc, node);
820 fclose(f);
821 }
822 }
823 return (0);
824 }
825
826 /**
827 * xmllintShellSave:
828 * @ctxt: the shell context
829 * @filename: the file name (optional)
830 * @node: unused
831 * @node2: unused
832 *
833 * Implements the XML shell function "save"
834 * Write the current document to the filename, or it's original name
835 *
836 * Returns 0 or -1 in case of error
837 */
838 static int
xmllintShellSave(xmllintShellCtxtPtr ctxt,char * filename,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)839 xmllintShellSave(xmllintShellCtxtPtr ctxt, char *filename,
840 xmlNodePtr node ATTRIBUTE_UNUSED,
841 xmlNodePtr node2 ATTRIBUTE_UNUSED)
842 {
843 if ((ctxt == NULL) || (ctxt->doc == NULL))
844 return (-1);
845 if ((filename == NULL) || (filename[0] == 0))
846 filename = ctxt->filename;
847 if (filename == NULL)
848 return (-1);
849 switch (ctxt->doc->type) {
850 case XML_DOCUMENT_NODE:
851 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
852 fprintf(ctxt->output,
853 "Failed to save to %s\n", filename);
854 }
855 break;
856 case XML_HTML_DOCUMENT_NODE:
857 #ifdef LIBXML_HTML_ENABLED
858 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
859 fprintf(ctxt->output,
860 "Failed to save to %s\n", filename);
861 }
862 #else
863 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
864 fprintf(ctxt->output,
865 "Failed to save to %s\n", filename);
866 }
867 #endif /* LIBXML_HTML_ENABLED */
868 break;
869 default:
870 fprintf(ctxt->output,
871 "To save to subparts of a document use the 'write' command\n");
872 return (-1);
873
874 }
875 return (0);
876 }
877 #endif /* LIBXML_OUTPUT_ENABLED */
878
879 #ifdef LIBXML_VALID_ENABLED
880 /**
881 * xmllintShellValidate:
882 * @ctxt: the shell context
883 * @dtd: the DTD URI (optional)
884 * @node: unused
885 * @node2: unused
886 *
887 * Implements the XML shell function "validate"
888 * Validate the document, if a DTD path is provided, then the validation
889 * is done against the given DTD.
890 *
891 * Returns 0 or -1 in case of error
892 */
893 static int
xmllintShellValidate(xmllintShellCtxtPtr ctxt,char * dtd,xmlNodePtr node ATTRIBUTE_UNUSED,xmlNodePtr node2 ATTRIBUTE_UNUSED)894 xmllintShellValidate(xmllintShellCtxtPtr ctxt, char *dtd,
895 xmlNodePtr node ATTRIBUTE_UNUSED,
896 xmlNodePtr node2 ATTRIBUTE_UNUSED)
897 {
898 xmlValidCtxt vctxt;
899 int res = -1;
900
901 if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1);
902 memset(&vctxt, 0, sizeof(vctxt));
903 vctxt.error = xmllintShellPrintf;
904 vctxt.warning = xmllintShellPrintf;
905 vctxt.userData = ctxt;
906
907 if ((dtd == NULL) || (dtd[0] == 0)) {
908 res = xmlValidateDocument(&vctxt, ctxt->doc);
909 } else {
910 xmlDtdPtr subset;
911
912 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
913 if (subset != NULL) {
914 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
915
916 xmlFreeDtd(subset);
917 }
918 }
919 return (res);
920 }
921 #endif /* LIBXML_VALID_ENABLED */
922
923 /**
924 * xmllintShellDu:
925 * @ctxt: the shell context
926 * @arg: unused
927 * @tree: a node defining a subtree
928 * @node2: unused
929 *
930 * Implements the XML shell function "du"
931 * show the structure of the subtree under node @tree
932 * If @tree is null, the command works on the current node.
933 *
934 * Returns 0 or -1 in case of error
935 */
936 static int
xmllintShellDu(xmllintShellCtxtPtr ctxt,char * arg ATTRIBUTE_UNUSED,xmlNodePtr tree,xmlNodePtr node2 ATTRIBUTE_UNUSED)937 xmllintShellDu(xmllintShellCtxtPtr ctxt,
938 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
939 xmlNodePtr node2 ATTRIBUTE_UNUSED)
940 {
941 xmlNodePtr node;
942 int indent = 0, i;
943
944 if (!ctxt)
945 return (-1);
946
947 if (tree == NULL)
948 return (-1);
949 node = tree;
950 while (node != NULL) {
951 if ((node->type == XML_DOCUMENT_NODE) ||
952 (node->type == XML_HTML_DOCUMENT_NODE)) {
953 fprintf(ctxt->output, "/\n");
954 } else if (node->type == XML_ELEMENT_NODE) {
955 for (i = 0; i < indent; i++)
956 fprintf(ctxt->output, " ");
957 if ((node->ns) && (node->ns->prefix))
958 fprintf(ctxt->output, "%s:", node->ns->prefix);
959 fprintf(ctxt->output, "%s\n", node->name);
960 } else {
961 }
962
963 /*
964 * Browse the full subtree, deep first
965 */
966
967 if ((node->type == XML_DOCUMENT_NODE) ||
968 (node->type == XML_HTML_DOCUMENT_NODE)) {
969 node = ((xmlDocPtr) node)->children;
970 } else if ((node->children != NULL)
971 && (node->type != XML_ENTITY_REF_NODE)) {
972 /* deep first */
973 node = node->children;
974 indent++;
975 } else if ((node != tree) && (node->next != NULL)) {
976 /* then siblings */
977 node = node->next;
978 } else if (node != tree) {
979 /* go up to parents->next if needed */
980 while (node != tree) {
981 if (node->parent != NULL) {
982 node = node->parent;
983 indent--;
984 }
985 if ((node != tree) && (node->next != NULL)) {
986 node = node->next;
987 break;
988 }
989 if (node->parent == NULL) {
990 node = NULL;
991 break;
992 }
993 if (node == tree) {
994 node = NULL;
995 break;
996 }
997 }
998 /* exit condition */
999 if (node == tree)
1000 node = NULL;
1001 } else
1002 node = NULL;
1003 }
1004 return (0);
1005 }
1006
1007 /**
1008 * xmllintShellPwd:
1009 * @ctxt: the shell context
1010 * @buffer: the output buffer
1011 * @node: a node
1012 * @node2: unused
1013 *
1014 * Implements the XML shell function "pwd"
1015 * Show the full path from the root to the node, if needed building
1016 * thumblers when similar elements exists at a given ancestor level.
1017 * The output is compatible with XPath commands.
1018 *
1019 * Returns 0 or -1 in case of error
1020 */
1021 static int
xmllintShellPwd(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED,char * buffer,xmlNodePtr node,xmlNodePtr node2 ATTRIBUTE_UNUSED)1022 xmllintShellPwd(xmllintShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
1023 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1024 {
1025 xmlChar *path;
1026
1027 if ((node == NULL) || (buffer == NULL))
1028 return (-1);
1029
1030 path = xmlGetNodePath(node);
1031 if (path == NULL)
1032 return (-1);
1033
1034 /*
1035 * This test prevents buffer overflow, because this routine
1036 * is only called by xmllintShell, in which the second argument is
1037 * 500 chars long.
1038 * It is a dirty hack before a cleaner solution is found.
1039 * Documentation should mention that the second argument must
1040 * be at least 500 chars long, and could be stripped if too long.
1041 */
1042 snprintf(buffer, 499, "%s", path);
1043 buffer[499] = '0';
1044 xmlFree(path);
1045
1046 return (0);
1047 }
1048
1049 /**
1050 * xmllintShellReadline:
1051 * @prompt: the prompt value
1052 *
1053 * Read a string
1054 *
1055 * Returns a pointer to it or NULL on EOF the caller is expected to
1056 * free the returned string.
1057 */
1058 static char *
xmllintShellReadline(char * prompt)1059 xmllintShellReadline(char *prompt) {
1060 char buf[501];
1061 char *ret;
1062 int len;
1063
1064 #ifdef HAVE_LIBREADLINE
1065 if (isatty(STDIN_FILENO)) {
1066 char *line_read;
1067
1068 /* Get a line from the user. */
1069 line_read = readline (prompt);
1070
1071 #ifdef HAVE_LIBHISTORY
1072 /* If the line has any text in it, save it on the history. */
1073 if (line_read && *line_read)
1074 add_history (line_read);
1075 #endif
1076
1077 return (line_read);
1078 }
1079 #endif
1080
1081 if (prompt != NULL)
1082 fprintf(stdout, "%s", prompt);
1083 fflush(stdout);
1084 if (!fgets(buf, 500, stdin))
1085 return(NULL);
1086 buf[500] = 0;
1087 len = strlen(buf);
1088 ret = (char *) malloc(len + 1);
1089 if (ret != NULL) {
1090 memcpy (ret, buf, len + 1);
1091 }
1092 return(ret);
1093 }
1094
1095 /**
1096 * xmllintShell:
1097 * @doc: the initial document
1098 * @filename: the output buffer
1099 * @input: the line reading function
1100 * @output: the output FILE*, defaults to stdout if NULL
1101 *
1102 * Implements the XML shell
1103 * This allow to load, validate, view, modify and save a document
1104 * using a environment similar to a UNIX commandline.
1105 */
1106 void
xmllintShell(xmlDocPtr doc,const char * filename,FILE * output)1107 xmllintShell(xmlDocPtr doc, const char *filename, FILE * output)
1108 {
1109 char prompt[500] = "/ > ";
1110 char *cmdline = NULL, *cur;
1111 char command[100];
1112 char arg[400];
1113 int i;
1114 xmllintShellCtxtPtr ctxt;
1115 #ifdef LIBXML_XPATH_ENABLED
1116 xmlXPathObjectPtr list;
1117 #endif
1118
1119 if (doc == NULL)
1120 return;
1121 if (filename == NULL)
1122 return;
1123 if (output == NULL)
1124 output = stdout;
1125 ctxt = (xmllintShellCtxtPtr) xmlMalloc(sizeof(xmllintShellCtxt));
1126 if (ctxt == NULL)
1127 return;
1128 ctxt->loaded = 0;
1129 ctxt->doc = doc;
1130 ctxt->output = output;
1131 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1132 ctxt->node = (xmlNodePtr) ctxt->doc;
1133
1134 #ifdef LIBXML_XPATH_ENABLED
1135 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1136 if (ctxt->pctxt == NULL) {
1137 xmlFree(ctxt);
1138 return;
1139 }
1140 #endif /* LIBXML_XPATH_ENABLED */
1141 while (1) {
1142 if (ctxt->node == (xmlNodePtr) ctxt->doc)
1143 snprintf(prompt, sizeof(prompt), "%s > ", "/");
1144 else if ((ctxt->node != NULL) && (ctxt->node->name) &&
1145 (ctxt->node->ns) && (ctxt->node->ns->prefix))
1146 snprintf(prompt, sizeof(prompt), "%s:%s > ",
1147 (ctxt->node->ns->prefix), ctxt->node->name);
1148 else if ((ctxt->node != NULL) && (ctxt->node->name))
1149 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
1150 else
1151 snprintf(prompt, sizeof(prompt), "? > ");
1152 prompt[sizeof(prompt) - 1] = 0;
1153
1154 /*
1155 * Get a new command line
1156 */
1157 cmdline = xmllintShellReadline(prompt);
1158 if (cmdline == NULL)
1159 break;
1160
1161 /*
1162 * Parse the command itself
1163 */
1164 cur = cmdline;
1165 while ((*cur == ' ') || (*cur == '\t'))
1166 cur++;
1167 i = 0;
1168 while ((*cur != ' ') && (*cur != '\t') &&
1169 (*cur != '\n') && (*cur != '\r')) {
1170 if (*cur == 0)
1171 break;
1172 command[i++] = *cur++;
1173 }
1174 command[i] = 0;
1175 if (i == 0)
1176 continue;
1177
1178 /*
1179 * Parse the argument
1180 */
1181 while ((*cur == ' ') || (*cur == '\t'))
1182 cur++;
1183 i = 0;
1184 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
1185 if (*cur == 0)
1186 break;
1187 arg[i++] = *cur++;
1188 }
1189 arg[i] = 0;
1190
1191 /*
1192 * start interpreting the command
1193 */
1194 if (!strcmp(command, "exit"))
1195 break;
1196 if (!strcmp(command, "quit"))
1197 break;
1198 if (!strcmp(command, "bye"))
1199 break;
1200 if (!strcmp(command, "help")) {
1201 fprintf(ctxt->output, "\tbase display XML base of the node\n");
1202 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n");
1203 fprintf(ctxt->output, "\tbye leave shell\n");
1204 fprintf(ctxt->output, "\tcat [node] display node or current node\n");
1205 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n");
1206 fprintf(ctxt->output, "\tdir [path] dumps information about the node (namespace, attributes, content)\n");
1207 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n");
1208 fprintf(ctxt->output, "\texit leave shell\n");
1209 fprintf(ctxt->output, "\thelp display this help\n");
1210 fprintf(ctxt->output, "\tfree display memory usage\n");
1211 fprintf(ctxt->output, "\tload [name] load a new document with name\n");
1212 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n");
1213 fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n");
1214 #ifdef LIBXML_XPATH_ENABLED
1215 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n");
1216 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n");
1217 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
1218 fprintf(ctxt->output, "\tsetrootns register all namespace found on the root element\n");
1219 fprintf(ctxt->output, "\t the default namespace if any uses 'defaultns' prefix\n");
1220 #endif /* LIBXML_XPATH_ENABLED */
1221 fprintf(ctxt->output, "\tpwd display current working directory\n");
1222 fprintf(ctxt->output, "\twhereis display absolute path of [path] or current working directory\n");
1223 fprintf(ctxt->output, "\tquit leave shell\n");
1224 #ifdef LIBXML_OUTPUT_ENABLED
1225 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n");
1226 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
1227 #endif /* LIBXML_OUTPUT_ENABLED */
1228 #ifdef LIBXML_VALID_ENABLED
1229 fprintf(ctxt->output, "\tvalidate check the document for errors\n");
1230 #endif /* LIBXML_VALID_ENABLED */
1231 #ifdef LIBXML_SCHEMAS_ENABLED
1232 fprintf(ctxt->output, "\trelaxng rng validate the document against the Relax-NG schemas\n");
1233 #endif
1234 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n");
1235 #ifdef LIBXML_VALID_ENABLED
1236 } else if (!strcmp(command, "validate")) {
1237 xmllintShellValidate(ctxt, arg, NULL, NULL);
1238 #endif /* LIBXML_VALID_ENABLED */
1239 } else if (!strcmp(command, "load")) {
1240 xmllintShellLoad(ctxt, arg, NULL, NULL);
1241 #ifdef LIBXML_SCHEMAS_ENABLED
1242 } else if (!strcmp(command, "relaxng")) {
1243 xmllintShellRNGValidate(ctxt, arg, NULL, NULL);
1244 #endif
1245 #ifdef LIBXML_OUTPUT_ENABLED
1246 } else if (!strcmp(command, "save")) {
1247 xmllintShellSave(ctxt, arg, NULL, NULL);
1248 } else if (!strcmp(command, "write")) {
1249 if (arg[0] == 0)
1250 fprintf(ctxt->output,
1251 "Write command requires a filename argument\n");
1252 else
1253 xmllintShellWrite(ctxt, arg, ctxt->node, NULL);
1254 #endif /* LIBXML_OUTPUT_ENABLED */
1255 } else if (!strcmp(command, "grep")) {
1256 xmllintShellGrep(ctxt, arg, ctxt->node, NULL);
1257 } else if (!strcmp(command, "pwd")) {
1258 char dir[500];
1259
1260 if (!xmllintShellPwd(ctxt, dir, ctxt->node, NULL))
1261 fprintf(ctxt->output, "%s\n", dir);
1262 } else if (!strcmp(command, "du")) {
1263 if (arg[0] == 0) {
1264 xmllintShellDu(ctxt, NULL, ctxt->node, NULL);
1265 } else {
1266 #ifdef LIBXML_XPATH_ENABLED
1267 ctxt->pctxt->node = ctxt->node;
1268 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1269 if (list != NULL) {
1270 switch (list->type) {
1271 case XPATH_UNDEFINED:
1272 fprintf(ctxt->output,
1273 "%s: no such node\n", arg);
1274 break;
1275 case XPATH_NODESET:{
1276 int indx;
1277
1278 if (list->nodesetval == NULL)
1279 break;
1280
1281 for (indx = 0;
1282 indx < list->nodesetval->nodeNr;
1283 indx++)
1284 xmllintShellDu(ctxt, NULL,
1285 list->nodesetval->
1286 nodeTab[indx], NULL);
1287 break;
1288 }
1289 case XPATH_BOOLEAN:
1290 fprintf(ctxt->output,
1291 "%s is a Boolean\n", arg);
1292 break;
1293 case XPATH_NUMBER:
1294 fprintf(ctxt->output,
1295 "%s is a number\n", arg);
1296 break;
1297 case XPATH_STRING:
1298 fprintf(ctxt->output,
1299 "%s is a string\n", arg);
1300 break;
1301 case XPATH_USERS:
1302 fprintf(ctxt->output,
1303 "%s is user-defined\n", arg);
1304 break;
1305 case XPATH_XSLT_TREE:
1306 fprintf(ctxt->output,
1307 "%s is an XSLT value tree\n",
1308 arg);
1309 break;
1310 }
1311 xmlXPathFreeObject(list);
1312 } else {
1313 fprintf(ctxt->output,
1314 "%s: no such node\n", arg);
1315 }
1316 ctxt->pctxt->node = NULL;
1317 #endif /* LIBXML_XPATH_ENABLED */
1318 }
1319 } else if (!strcmp(command, "base")) {
1320 xmllintShellBase(ctxt, NULL, ctxt->node, NULL);
1321 } else if (!strcmp(command, "set")) {
1322 xmllintShellSetContent(ctxt, arg, ctxt->node, NULL);
1323 #ifdef LIBXML_XPATH_ENABLED
1324 } else if (!strcmp(command, "setns")) {
1325 if (arg[0] == 0) {
1326 fprintf(ctxt->output,
1327 "setns: prefix=[nsuri] required\n");
1328 } else {
1329 xmllintShellRegisterNamespace(ctxt, arg, NULL, NULL);
1330 }
1331 } else if (!strcmp(command, "setrootns")) {
1332 xmlNodePtr root;
1333
1334 root = xmlDocGetRootElement(ctxt->doc);
1335 xmllintShellRegisterRootNamespaces(ctxt, NULL, root, NULL);
1336 #ifdef LIBXML_DEBUG_ENABLED
1337 } else if (!strcmp(command, "xpath")) {
1338 if (arg[0] == 0) {
1339 fprintf(ctxt->output,
1340 "xpath: expression required\n");
1341 } else {
1342 ctxt->pctxt->node = ctxt->node;
1343 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1344 xmlXPathDebugDumpObject(ctxt->output, list, 0);
1345 xmlXPathFreeObject(list);
1346 }
1347 #endif /* LIBXML_DEBUG_ENABLED */
1348 #endif /* LIBXML_XPATH_ENABLED */
1349 } else if (!strcmp(command, "setbase")) {
1350 xmllintShellSetBase(ctxt, arg, ctxt->node, NULL);
1351 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
1352 int dir = (!strcmp(command, "dir"));
1353
1354 if (arg[0] == 0) {
1355 if (dir)
1356 xmllintShellDir(ctxt, NULL, ctxt->node, NULL);
1357 else
1358 xmllintShellList(ctxt, NULL, ctxt->node, NULL);
1359 } else {
1360 #ifdef LIBXML_XPATH_ENABLED
1361 ctxt->pctxt->node = ctxt->node;
1362 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1363 if (list != NULL) {
1364 switch (list->type) {
1365 case XPATH_UNDEFINED:
1366 fprintf(ctxt->output,
1367 "%s: no such node\n", arg);
1368 break;
1369 case XPATH_NODESET:{
1370 int indx;
1371
1372 if (list->nodesetval == NULL)
1373 break;
1374
1375 for (indx = 0;
1376 indx < list->nodesetval->nodeNr;
1377 indx++) {
1378 if (dir)
1379 xmllintShellDir(ctxt, NULL,
1380 list->nodesetval->
1381 nodeTab[indx], NULL);
1382 else
1383 xmllintShellList(ctxt, NULL,
1384 list->nodesetval->
1385 nodeTab[indx], NULL);
1386 }
1387 break;
1388 }
1389 case XPATH_BOOLEAN:
1390 fprintf(ctxt->output,
1391 "%s is a Boolean\n", arg);
1392 break;
1393 case XPATH_NUMBER:
1394 fprintf(ctxt->output,
1395 "%s is a number\n", arg);
1396 break;
1397 case XPATH_STRING:
1398 fprintf(ctxt->output,
1399 "%s is a string\n", arg);
1400 break;
1401 case XPATH_USERS:
1402 fprintf(ctxt->output,
1403 "%s is user-defined\n", arg);
1404 break;
1405 case XPATH_XSLT_TREE:
1406 fprintf(ctxt->output,
1407 "%s is an XSLT value tree\n",
1408 arg);
1409 break;
1410 }
1411 xmlXPathFreeObject(list);
1412 } else {
1413 fprintf(ctxt->output,
1414 "%s: no such node\n", arg);
1415 }
1416 ctxt->pctxt->node = NULL;
1417 #endif /* LIBXML_XPATH_ENABLED */
1418 }
1419 } else if (!strcmp(command, "whereis")) {
1420 char dir[500];
1421
1422 if (arg[0] == 0) {
1423 if (!xmllintShellPwd(ctxt, dir, ctxt->node, NULL))
1424 fprintf(ctxt->output, "%s\n", dir);
1425 } else {
1426 #ifdef LIBXML_XPATH_ENABLED
1427 ctxt->pctxt->node = ctxt->node;
1428 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1429 if (list != NULL) {
1430 switch (list->type) {
1431 case XPATH_UNDEFINED:
1432 fprintf(ctxt->output,
1433 "%s: no such node\n", arg);
1434 break;
1435 case XPATH_NODESET:{
1436 int indx;
1437
1438 if (list->nodesetval == NULL)
1439 break;
1440
1441 for (indx = 0;
1442 indx < list->nodesetval->nodeNr;
1443 indx++) {
1444 if (!xmllintShellPwd(ctxt, dir, list->nodesetval->
1445 nodeTab[indx], NULL))
1446 fprintf(ctxt->output, "%s\n", dir);
1447 }
1448 break;
1449 }
1450 case XPATH_BOOLEAN:
1451 fprintf(ctxt->output,
1452 "%s is a Boolean\n", arg);
1453 break;
1454 case XPATH_NUMBER:
1455 fprintf(ctxt->output,
1456 "%s is a number\n", arg);
1457 break;
1458 case XPATH_STRING:
1459 fprintf(ctxt->output,
1460 "%s is a string\n", arg);
1461 break;
1462 case XPATH_USERS:
1463 fprintf(ctxt->output,
1464 "%s is user-defined\n", arg);
1465 break;
1466 case XPATH_XSLT_TREE:
1467 fprintf(ctxt->output,
1468 "%s is an XSLT value tree\n",
1469 arg);
1470 break;
1471 }
1472 xmlXPathFreeObject(list);
1473 } else {
1474 fprintf(ctxt->output,
1475 "%s: no such node\n", arg);
1476 }
1477 ctxt->pctxt->node = NULL;
1478 #endif /* LIBXML_XPATH_ENABLED */
1479 }
1480 } else if (!strcmp(command, "cd")) {
1481 if (arg[0] == 0) {
1482 ctxt->node = (xmlNodePtr) ctxt->doc;
1483 } else {
1484 #ifdef LIBXML_XPATH_ENABLED
1485 int l;
1486
1487 ctxt->pctxt->node = ctxt->node;
1488 l = strlen(arg);
1489 if ((l >= 2) && (arg[l - 1] == '/'))
1490 arg[l - 1] = 0;
1491 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1492 if (list != NULL) {
1493 switch (list->type) {
1494 case XPATH_UNDEFINED:
1495 fprintf(ctxt->output,
1496 "%s: no such node\n", arg);
1497 break;
1498 case XPATH_NODESET:
1499 if (list->nodesetval != NULL) {
1500 if (list->nodesetval->nodeNr == 1) {
1501 ctxt->node = list->nodesetval->nodeTab[0];
1502 if ((ctxt->node != NULL) &&
1503 (ctxt->node->type ==
1504 XML_NAMESPACE_DECL)) {
1505 fprintf(ctxt->output,
1506 "cannot cd to namespace\n");
1507 ctxt->node = NULL;
1508 }
1509 } else
1510 fprintf(ctxt->output,
1511 "%s is a %d Node Set\n",
1512 arg,
1513 list->nodesetval->nodeNr);
1514 } else
1515 fprintf(ctxt->output,
1516 "%s is an empty Node Set\n",
1517 arg);
1518 break;
1519 case XPATH_BOOLEAN:
1520 fprintf(ctxt->output,
1521 "%s is a Boolean\n", arg);
1522 break;
1523 case XPATH_NUMBER:
1524 fprintf(ctxt->output,
1525 "%s is a number\n", arg);
1526 break;
1527 case XPATH_STRING:
1528 fprintf(ctxt->output,
1529 "%s is a string\n", arg);
1530 break;
1531 case XPATH_USERS:
1532 fprintf(ctxt->output,
1533 "%s is user-defined\n", arg);
1534 break;
1535 case XPATH_XSLT_TREE:
1536 fprintf(ctxt->output,
1537 "%s is an XSLT value tree\n",
1538 arg);
1539 break;
1540 }
1541 xmlXPathFreeObject(list);
1542 } else {
1543 fprintf(ctxt->output,
1544 "%s: no such node\n", arg);
1545 }
1546 ctxt->pctxt->node = NULL;
1547 #endif /* LIBXML_XPATH_ENABLED */
1548 }
1549 #ifdef LIBXML_OUTPUT_ENABLED
1550 } else if (!strcmp(command, "cat")) {
1551 if (arg[0] == 0) {
1552 xmllintShellCat(ctxt, NULL, ctxt->node, NULL);
1553 } else {
1554 #ifdef LIBXML_XPATH_ENABLED
1555 ctxt->pctxt->node = ctxt->node;
1556 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1557 if (list != NULL) {
1558 switch (list->type) {
1559 case XPATH_UNDEFINED:
1560 fprintf(ctxt->output,
1561 "%s: no such node\n", arg);
1562 break;
1563 case XPATH_NODESET:{
1564 int indx;
1565
1566 if (list->nodesetval == NULL)
1567 break;
1568
1569 for (indx = 0;
1570 indx < list->nodesetval->nodeNr;
1571 indx++) {
1572 if (i > 0)
1573 fprintf(ctxt->output, " -------\n");
1574 xmllintShellCat(ctxt, NULL,
1575 list->nodesetval->
1576 nodeTab[indx], NULL);
1577 }
1578 break;
1579 }
1580 case XPATH_BOOLEAN:
1581 fprintf(ctxt->output,
1582 "%s is a Boolean\n", arg);
1583 break;
1584 case XPATH_NUMBER:
1585 fprintf(ctxt->output,
1586 "%s is a number\n", arg);
1587 break;
1588 case XPATH_STRING:
1589 fprintf(ctxt->output,
1590 "%s is a string\n", arg);
1591 break;
1592 case XPATH_USERS:
1593 fprintf(ctxt->output,
1594 "%s is user-defined\n", arg);
1595 break;
1596 case XPATH_XSLT_TREE:
1597 fprintf(ctxt->output,
1598 "%s is an XSLT value tree\n",
1599 arg);
1600 break;
1601 }
1602 xmlXPathFreeObject(list);
1603 } else {
1604 fprintf(ctxt->output,
1605 "%s: no such node\n", arg);
1606 }
1607 ctxt->pctxt->node = NULL;
1608 #endif /* LIBXML_XPATH_ENABLED */
1609 }
1610 #endif /* LIBXML_OUTPUT_ENABLED */
1611 } else {
1612 fprintf(ctxt->output,
1613 "Unknown command %s\n", command);
1614 }
1615 free(cmdline); /* not xmlFree here ! */
1616 cmdline = NULL;
1617 }
1618 #ifdef LIBXML_XPATH_ENABLED
1619 xmlXPathFreeContext(ctxt->pctxt);
1620 #endif /* LIBXML_XPATH_ENABLED */
1621 if (ctxt->loaded) {
1622 xmlFreeDoc(ctxt->doc);
1623 }
1624 if (ctxt->filename != NULL)
1625 xmlFree(ctxt->filename);
1626 xmlFree(ctxt);
1627 if (cmdline != NULL)
1628 free(cmdline); /* not xmlFree here ! */
1629 }
1630