debugXML.c revision 7db3871bf58553461563241db0fffe71bf611c5e
1/*
2 * debugXML.c : This is a set of routines used for debugging the tree
3 *              produced by the XML parser.
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <daniel@veillard.com>
8 */
9
10#include "libxml.h"
11#ifdef LIBXML_DEBUG_ENABLED
12
13#include <string.h>
14#ifdef HAVE_STDLIB_H
15#include <stdlib.h>
16#endif
17#ifdef HAVE_STRING_H
18#include <string.h>
19#endif
20#include <libxml/xmlmemory.h>
21#include <libxml/tree.h>
22#include <libxml/parser.h>
23#include <libxml/parserInternals.h>
24#include <libxml/valid.h>
25#include <libxml/debugXML.h>
26#include <libxml/HTMLtree.h>
27#include <libxml/HTMLparser.h>
28#include <libxml/xmlerror.h>
29#include <libxml/globals.h>
30
31/**
32 * xmlDebugDumpString:
33 * @output:  the FILE * for the output
34 * @str:  the string
35 *
36 * Dumps informations about the string, shorten it if necessary
37 */
38void
39xmlDebugDumpString(FILE * output, const xmlChar * str)
40{
41    int i;
42
43    if (output == NULL)
44	output = stdout;
45    if (str == NULL) {
46        fprintf(output, "(NULL)");
47        return;
48    }
49    for (i = 0; i < 40; i++)
50        if (str[i] == 0)
51            return;
52        else if (IS_BLANK(str[i]))
53            fputc(' ', output);
54        else if (str[i] >= 0x80)
55            fprintf(output, "#%X", str[i]);
56        else
57            fputc(str[i], output);
58    fprintf(output, "...");
59}
60
61static void
62xmlDebugDumpDtdNode(FILE *output, xmlDtdPtr dtd, int depth) {
63    int i;
64    char shift[100];
65
66    for (i = 0;((i < depth) && (i < 25));i++)
67        shift[2 * i] = shift[2 * i + 1] = ' ';
68    shift[2 * i] = shift[2 * i + 1] = 0;
69
70    fprintf(output, shift);
71
72    if (dtd == NULL) {
73	fprintf(output, "DTD node is NULL\n");
74	return;
75    }
76
77    if (dtd->type != XML_DTD_NODE) {
78	fprintf(output, "PBM: not a DTD\n");
79	return;
80    }
81    if (dtd->name != NULL)
82	fprintf(output, "DTD(%s)", dtd->name);
83    else
84	fprintf(output, "DTD");
85    if (dtd->ExternalID != NULL)
86	fprintf(output, ", PUBLIC %s", dtd->ExternalID);
87    if (dtd->SystemID != NULL)
88	fprintf(output, ", SYSTEM %s", dtd->SystemID);
89    fprintf(output, "\n");
90    /*
91     * Do a bit of checking
92     */
93    if (dtd->parent == NULL)
94	fprintf(output, "PBM: DTD has no parent\n");
95    if (dtd->doc == NULL)
96	fprintf(output, "PBM: DTD has no doc\n");
97    if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
98	fprintf(output, "PBM: DTD doc differs from parent's one\n");
99    if (dtd->prev == NULL) {
100	if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
101	    fprintf(output, "PBM: DTD has no prev and not first of list\n");
102    } else {
103	if (dtd->prev->next != (xmlNodePtr) dtd)
104	    fprintf(output, "PBM: DTD prev->next : back link wrong\n");
105    }
106    if (dtd->next == NULL) {
107	if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
108	    fprintf(output, "PBM: DTD has no next and not last of list\n");
109    } else {
110	if (dtd->next->prev != (xmlNodePtr) dtd)
111	    fprintf(output, "PBM: DTD next->prev : forward link wrong\n");
112    }
113}
114
115static void
116xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) {
117    int i;
118    char shift[100];
119
120    for (i = 0;((i < depth) && (i < 25));i++)
121        shift[2 * i] = shift[2 * i + 1] = ' ';
122    shift[2 * i] = shift[2 * i + 1] = 0;
123
124    fprintf(output, shift);
125
126    if (attr == NULL) {
127	fprintf(output, "Attribute declaration is NULL\n");
128	return;
129    }
130    if (attr->type != XML_ATTRIBUTE_DECL) {
131	fprintf(output, "PBM: not a Attr\n");
132	return;
133    }
134    if (attr->name != NULL)
135	fprintf(output, "ATTRDECL(%s)", attr->name);
136    else
137	fprintf(output, "PBM ATTRDECL noname!!!");
138    if (attr->elem != NULL)
139	fprintf(output, " for %s", attr->elem);
140    else
141	fprintf(output, " PBM noelem!!!");
142    switch (attr->atype) {
143        case XML_ATTRIBUTE_CDATA:
144	    fprintf(output, " CDATA");
145	    break;
146        case XML_ATTRIBUTE_ID:
147	    fprintf(output, " ID");
148	    break;
149        case XML_ATTRIBUTE_IDREF:
150	    fprintf(output, " IDREF");
151	    break;
152        case XML_ATTRIBUTE_IDREFS:
153	    fprintf(output, " IDREFS");
154	    break;
155        case XML_ATTRIBUTE_ENTITY:
156	    fprintf(output, " ENTITY");
157	    break;
158        case XML_ATTRIBUTE_ENTITIES:
159	    fprintf(output, " ENTITIES");
160	    break;
161        case XML_ATTRIBUTE_NMTOKEN:
162	    fprintf(output, " NMTOKEN");
163	    break;
164        case XML_ATTRIBUTE_NMTOKENS:
165	    fprintf(output, " NMTOKENS");
166	    break;
167        case XML_ATTRIBUTE_ENUMERATION:
168	    fprintf(output, " ENUMERATION");
169	    break;
170        case XML_ATTRIBUTE_NOTATION:
171	    fprintf(output, " NOTATION ");
172	    break;
173    }
174    if (attr->tree != NULL) {
175	int indx;
176	xmlEnumerationPtr cur = attr->tree;
177
178	for (indx = 0;indx < 5; indx++) {
179	    if (indx != 0)
180		fprintf(output, "|%s", cur->name);
181	    else
182		fprintf(output, " (%s", cur->name);
183	    cur = cur->next;
184	    if (cur == NULL) break;
185	}
186	if (cur == NULL)
187	    fprintf(output, ")");
188	else
189	    fprintf(output, "...)");
190    }
191    switch (attr->def) {
192        case XML_ATTRIBUTE_NONE:
193	    break;
194        case XML_ATTRIBUTE_REQUIRED:
195	    fprintf(output, " REQUIRED");
196	    break;
197        case XML_ATTRIBUTE_IMPLIED:
198	    fprintf(output, " IMPLIED");
199	    break;
200        case XML_ATTRIBUTE_FIXED:
201	    fprintf(output, " FIXED");
202	    break;
203    }
204    if (attr->defaultValue != NULL) {
205	fprintf(output, "\"");
206	xmlDebugDumpString(output, attr->defaultValue);
207	fprintf(output, "\"");
208    }
209    fprintf(output, "\n");
210
211    /*
212     * Do a bit of checking
213     */
214    if (attr->parent == NULL)
215	fprintf(output, "PBM: Attr has no parent\n");
216    if (attr->doc == NULL)
217	fprintf(output, "PBM: Attr has no doc\n");
218    if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
219	fprintf(output, "PBM: Attr doc differs from parent's one\n");
220    if (attr->prev == NULL) {
221	if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr))
222	    fprintf(output, "PBM: Attr has no prev and not first of list\n");
223    } else {
224	if (attr->prev->next != (xmlNodePtr) attr)
225	    fprintf(output, "PBM: Attr prev->next : back link wrong\n");
226    }
227    if (attr->next == NULL) {
228	if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr))
229	    fprintf(output, "PBM: Attr has no next and not last of list\n");
230    } else {
231	if (attr->next->prev != (xmlNodePtr) attr)
232	    fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
233    }
234}
235
236static void
237xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) {
238    int i;
239    char shift[100];
240
241    for (i = 0;((i < depth) && (i < 25));i++)
242        shift[2 * i] = shift[2 * i + 1] = ' ';
243    shift[2 * i] = shift[2 * i + 1] = 0;
244
245    fprintf(output, shift);
246
247    if (elem == NULL) {
248	fprintf(output, "Element declaration is NULL\n");
249	return;
250    }
251    if (elem->type != XML_ELEMENT_DECL) {
252	fprintf(output, "PBM: not a Elem\n");
253	return;
254    }
255    if (elem->name != NULL) {
256	fprintf(output, "ELEMDECL(");
257	xmlDebugDumpString(output, elem->name);
258	fprintf(output, ")");
259    } else
260	fprintf(output, "PBM ELEMDECL noname!!!");
261    switch (elem->etype) {
262	case XML_ELEMENT_TYPE_UNDEFINED:
263	    fprintf(output, ", UNDEFINED");
264	    break;
265	case XML_ELEMENT_TYPE_EMPTY:
266	    fprintf(output, ", EMPTY");
267	    break;
268	case XML_ELEMENT_TYPE_ANY:
269	    fprintf(output, ", ANY");
270	    break;
271	case XML_ELEMENT_TYPE_MIXED:
272	    fprintf(output, ", MIXED ");
273	    break;
274	case XML_ELEMENT_TYPE_ELEMENT:
275	    fprintf(output, ", MIXED ");
276	    break;
277    }
278    if ((elem->type != XML_ELEMENT_NODE) &&
279	(elem->content != NULL)) {
280	char buf[5001];
281
282	buf[0] = 0;
283	xmlSnprintfElementContent(buf, 5000, elem->content, 1);
284	buf[5000] = 0;
285	fprintf(output, "%s", buf);
286    }
287    fprintf(output, "\n");
288
289    /*
290     * Do a bit of checking
291     */
292    if (elem->parent == NULL)
293	fprintf(output, "PBM: Elem has no parent\n");
294    if (elem->doc == NULL)
295	fprintf(output, "PBM: Elem has no doc\n");
296    if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
297	fprintf(output, "PBM: Elem doc differs from parent's one\n");
298    if (elem->prev == NULL) {
299	if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem))
300	    fprintf(output, "PBM: Elem has no prev and not first of list\n");
301    } else {
302	if (elem->prev->next != (xmlNodePtr) elem)
303	    fprintf(output, "PBM: Elem prev->next : back link wrong\n");
304    }
305    if (elem->next == NULL) {
306	if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem))
307	    fprintf(output, "PBM: Elem has no next and not last of list\n");
308    } else {
309	if (elem->next->prev != (xmlNodePtr) elem)
310	    fprintf(output, "PBM: Elem next->prev : forward link wrong\n");
311    }
312}
313
314static void
315xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) {
316    int i;
317    char shift[100];
318
319    for (i = 0;((i < depth) && (i < 25));i++)
320        shift[2 * i] = shift[2 * i + 1] = ' ';
321    shift[2 * i] = shift[2 * i + 1] = 0;
322
323    fprintf(output, shift);
324
325    if (ent == NULL) {
326	fprintf(output, "Entity declaration is NULL\n");
327	return;
328    }
329    if (ent->type != XML_ENTITY_DECL) {
330	fprintf(output, "PBM: not a Entity decl\n");
331	return;
332    }
333    if (ent->name != NULL) {
334	fprintf(output, "ENTITYDECL(");
335	xmlDebugDumpString(output, ent->name);
336	fprintf(output, ")");
337    } else
338	fprintf(output, "PBM ENTITYDECL noname!!!");
339    switch (ent->etype) {
340	case XML_INTERNAL_GENERAL_ENTITY:
341	    fprintf(output, ", internal\n");
342	    break;
343	case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
344	    fprintf(output, ", external parsed\n");
345	    break;
346	case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
347	    fprintf(output, ", unparsed\n");
348	    break;
349	case XML_INTERNAL_PARAMETER_ENTITY:
350	    fprintf(output, ", parameter\n");
351	    break;
352	case XML_EXTERNAL_PARAMETER_ENTITY:
353	    fprintf(output, ", external parameter\n");
354	    break;
355	case XML_INTERNAL_PREDEFINED_ENTITY:
356	    fprintf(output, ", predefined\n");
357	    break;
358    }
359    if (ent->ExternalID) {
360        fprintf(output, shift);
361        fprintf(output, " ExternalID=%s\n", ent->ExternalID);
362    }
363    if (ent->SystemID) {
364        fprintf(output, shift);
365        fprintf(output, " SystemID=%s\n", ent->SystemID);
366    }
367    if (ent->URI != NULL) {
368        fprintf(output, shift);
369        fprintf(output, " URI=%s\n", ent->URI);
370    }
371    if (ent->content) {
372        fprintf(output, shift);
373	fprintf(output, " content=");
374	xmlDebugDumpString(output, ent->content);
375	fprintf(output, "\n");
376    }
377
378    /*
379     * Do a bit of checking
380     */
381    if (ent->parent == NULL)
382	fprintf(output, "PBM: Ent has no parent\n");
383    if (ent->doc == NULL)
384	fprintf(output, "PBM: Ent has no doc\n");
385    if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
386	fprintf(output, "PBM: Ent doc differs from parent's one\n");
387    if (ent->prev == NULL) {
388	if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent))
389	    fprintf(output, "PBM: Ent has no prev and not first of list\n");
390    } else {
391	if (ent->prev->next != (xmlNodePtr) ent)
392	    fprintf(output, "PBM: Ent prev->next : back link wrong\n");
393    }
394    if (ent->next == NULL) {
395	if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent))
396	    fprintf(output, "PBM: Ent has no next and not last of list\n");
397    } else {
398	if (ent->next->prev != (xmlNodePtr) ent)
399	    fprintf(output, "PBM: Ent next->prev : forward link wrong\n");
400    }
401}
402
403static void
404xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
405    int i;
406    char shift[100];
407
408    for (i = 0;((i < depth) && (i < 25));i++)
409        shift[2 * i] = shift[2 * i + 1] = ' ';
410    shift[2 * i] = shift[2 * i + 1] = 0;
411
412    fprintf(output, shift);
413
414    if (ns == NULL) {
415	fprintf(output, "namespace node is NULL\n");
416	return;
417    }
418    if (ns->type != XML_NAMESPACE_DECL) {
419        fprintf(output, "invalid namespace node %d\n", ns->type);
420	return;
421    }
422    if (ns->href == NULL) {
423	if (ns->prefix != NULL)
424	    fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix);
425	else
426	    fprintf(output, "incomplete default namespace href=NULL\n");
427    } else {
428	if (ns->prefix != NULL)
429	    fprintf(output, "namespace %s href=", ns->prefix);
430	else
431	    fprintf(output, "default namespace href=");
432
433	xmlDebugDumpString(output, ns->href);
434	fprintf(output, "\n");
435    }
436}
437
438static void
439xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
440    while (ns != NULL) {
441        xmlDebugDumpNamespace(output, ns, depth);
442	ns = ns->next;
443    }
444}
445
446static void
447xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
448    int i;
449    char shift[100];
450
451    for (i = 0;((i < depth) && (i < 25));i++)
452        shift[2 * i] = shift[2 * i + 1] = ' ';
453    shift[2 * i] = shift[2 * i + 1] = 0;
454
455    fprintf(output, shift);
456
457    if (ent == NULL) {
458	fprintf(output, "Entity is NULL\n");
459	return;
460    }
461    switch (ent->etype) {
462        case XML_INTERNAL_GENERAL_ENTITY:
463	    fprintf(output, "INTERNAL_GENERAL_ENTITY ");
464	    break;
465        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
466	    fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
467	    break;
468        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
469	    fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
470	    break;
471        case XML_INTERNAL_PARAMETER_ENTITY:
472	    fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
473	    break;
474        case XML_EXTERNAL_PARAMETER_ENTITY:
475	    fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
476	    break;
477	default:
478	    fprintf(output, "ENTITY_%d ! ", ent->etype);
479    }
480    fprintf(output, "%s\n", ent->name);
481    if (ent->ExternalID) {
482        fprintf(output, shift);
483        fprintf(output, "ExternalID=%s\n", ent->ExternalID);
484    }
485    if (ent->SystemID) {
486        fprintf(output, shift);
487        fprintf(output, "SystemID=%s\n", ent->SystemID);
488    }
489    if (ent->URI) {
490        fprintf(output, shift);
491        fprintf(output, "URI=%s\n", ent->URI);
492    }
493    if (ent->content) {
494        fprintf(output, shift);
495	fprintf(output, "content=");
496	xmlDebugDumpString(output, ent->content);
497	fprintf(output, "\n");
498    }
499}
500
501/**
502 * xmlDebugDumpAttr:
503 * @output:  the FILE * for the output
504 * @attr:  the attribute
505 * @depth:  the indentation level.
506 *
507 * Dumps debug information for the attribute
508 */
509void
510xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
511    int i;
512    char shift[100];
513
514    for (i = 0;((i < depth) && (i < 25));i++)
515        shift[2 * i] = shift[2 * i + 1] = ' ';
516    shift[2 * i] = shift[2 * i + 1] = 0;
517
518    fprintf(output, shift);
519
520    if (attr == NULL) {
521	fprintf(output, "Attr is NULL");
522	return;
523    }
524    fprintf(output, "ATTRIBUTE ");
525    xmlDebugDumpString(output, attr->name);
526    fprintf(output, "\n");
527    if (attr->children != NULL)
528        xmlDebugDumpNodeList(output, attr->children, depth + 1);
529
530    /*
531     * Do a bit of checking
532     */
533    if (attr->parent == NULL)
534	fprintf(output, "PBM: Attr has no parent\n");
535    if (attr->doc == NULL)
536	fprintf(output, "PBM: Attr has no doc\n");
537    if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
538	fprintf(output, "PBM: Attr doc differs from parent's one\n");
539    if (attr->prev == NULL) {
540	if ((attr->parent != NULL) && (attr->parent->properties != attr))
541	    fprintf(output, "PBM: Attr has no prev and not first of list\n");
542    } else {
543	if (attr->prev->next != attr)
544	    fprintf(output, "PBM: Attr prev->next : back link wrong\n");
545    }
546    if (attr->next != NULL) {
547	if (attr->next->prev != attr)
548	    fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
549    }
550}
551
552/**
553 * xmlDebugDumpAttrList:
554 * @output:  the FILE * for the output
555 * @attr:  the attribute list
556 * @depth:  the indentation level.
557 *
558 * Dumps debug information for the attribute list
559 */
560void
561xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
562{
563    if (output == NULL)
564	output = stdout;
565    while (attr != NULL) {
566        xmlDebugDumpAttr(output, attr, depth);
567        attr = attr->next;
568    }
569}
570
571/**
572 * xmlDebugDumpOneNode:
573 * @output:  the FILE * for the output
574 * @node:  the node
575 * @depth:  the indentation level.
576 *
577 * Dumps debug information for the element node, it is not recursive
578 */
579void
580xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
581{
582    int i;
583    char shift[100];
584
585    if (output == NULL)
586	output = stdout;
587    for (i = 0; ((i < depth) && (i < 25)); i++)
588        shift[2 * i] = shift[2 * i + 1] = ' ';
589    shift[2 * i] = shift[2 * i + 1] = 0;
590
591    if (node == NULL) {
592	fprintf(output, shift);
593	fprintf(output, "node is NULL\n");
594	return;
595    }
596    switch (node->type) {
597        case XML_ELEMENT_NODE:
598            fprintf(output, shift);
599            fprintf(output, "ELEMENT ");
600            if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
601                xmlDebugDumpString(output, node->ns->prefix);
602                fprintf(output, ":");
603            }
604            xmlDebugDumpString(output, node->name);
605            fprintf(output, "\n");
606            break;
607        case XML_ATTRIBUTE_NODE:
608            fprintf(output, shift);
609            fprintf(output, "Error, ATTRIBUTE found here\n");
610            break;
611        case XML_TEXT_NODE:
612            fprintf(output, shift);
613	    if (node->name == (const xmlChar *) xmlStringTextNoenc)
614		fprintf(output, "TEXT no enc\n");
615	    else
616		fprintf(output, "TEXT\n");
617            break;
618        case XML_CDATA_SECTION_NODE:
619            fprintf(output, shift);
620            fprintf(output, "CDATA_SECTION\n");
621            break;
622        case XML_ENTITY_REF_NODE:
623            fprintf(output, shift);
624            fprintf(output, "ENTITY_REF(%s)\n", node->name);
625            break;
626        case XML_ENTITY_NODE:
627            fprintf(output, shift);
628            fprintf(output, "ENTITY\n");
629            break;
630        case XML_PI_NODE:
631            fprintf(output, shift);
632            fprintf(output, "PI %s\n", node->name);
633            break;
634        case XML_COMMENT_NODE:
635            fprintf(output, shift);
636            fprintf(output, "COMMENT\n");
637            break;
638        case XML_DOCUMENT_NODE:
639        case XML_HTML_DOCUMENT_NODE:
640            fprintf(output, shift);
641            fprintf(output, "Error, DOCUMENT found here\n");
642            break;
643        case XML_DOCUMENT_TYPE_NODE:
644            fprintf(output, shift);
645            fprintf(output, "DOCUMENT_TYPE\n");
646            break;
647        case XML_DOCUMENT_FRAG_NODE:
648            fprintf(output, shift);
649            fprintf(output, "DOCUMENT_FRAG\n");
650            break;
651        case XML_NOTATION_NODE:
652            fprintf(output, shift);
653            fprintf(output, "NOTATION\n");
654            break;
655        case XML_DTD_NODE:
656            xmlDebugDumpDtdNode(output, (xmlDtdPtr) node, depth);
657            return;
658        case XML_ELEMENT_DECL:
659            xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
660            return;
661        case XML_ATTRIBUTE_DECL:
662            xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
663            return;
664        case XML_ENTITY_DECL:
665            xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
666            return;
667        case XML_NAMESPACE_DECL:
668            xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
669            return;
670        case XML_XINCLUDE_START:
671            fprintf(output, shift);
672            fprintf(output, "INCLUDE START\n");
673            return;
674        case XML_XINCLUDE_END:
675            fprintf(output, shift);
676            fprintf(output, "INCLUDE END\n");
677            return;
678        default:
679            fprintf(output, shift);
680            fprintf(output, "NODE_%d !!!\n", node->type);
681            return;
682    }
683    if (node->doc == NULL) {
684        fprintf(output, shift);
685        fprintf(output, "doc == NULL !!!\n");
686    }
687    if (node->nsDef != NULL)
688        xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
689    if (node->properties != NULL)
690        xmlDebugDumpAttrList(output, node->properties, depth + 1);
691    if (node->type != XML_ENTITY_REF_NODE) {
692        if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
693            shift[2 * i] = shift[2 * i + 1] = ' ';
694            shift[2 * i + 2] = shift[2 * i + 3] = 0;
695            fprintf(output, shift);
696            fprintf(output, "content=");
697#ifndef XML_USE_BUFFER_CONTENT
698            xmlDebugDumpString(output, node->content);
699#else
700            xmlDebugDumpString(output, xmlBufferContent(node->content));
701#endif
702            fprintf(output, "\n");
703        }
704    } else {
705        xmlEntityPtr ent;
706
707        ent = xmlGetDocEntity(node->doc, node->name);
708        if (ent != NULL)
709            xmlDebugDumpEntity(output, ent, depth + 1);
710    }
711    /*
712     * Do a bit of checking
713     */
714    if (node->parent == NULL)
715        fprintf(output, "PBM: Node has no parent\n");
716    if (node->doc == NULL)
717        fprintf(output, "PBM: Node has no doc\n");
718    if ((node->parent != NULL) && (node->doc != node->parent->doc))
719        fprintf(output, "PBM: Node doc differs from parent's one\n");
720    if (node->prev == NULL) {
721        if ((node->parent != NULL) && (node->parent->children != node))
722            fprintf(output,
723                    "PBM: Node has no prev and not first of list\n");
724    } else {
725        if (node->prev->next != node)
726            fprintf(output, "PBM: Node prev->next : back link wrong\n");
727    }
728    if (node->next == NULL) {
729        if ((node->parent != NULL) && (node->parent->last != node))
730            fprintf(output,
731                    "PBM: Node has no next and not last of list\n");
732    } else {
733        if (node->next->prev != node)
734            fprintf(output, "PBM: Node next->prev : forward link wrong\n");
735    }
736}
737
738/**
739 * xmlDebugDumpNode:
740 * @output:  the FILE * for the output
741 * @node:  the node
742 * @depth:  the indentation level.
743 *
744 * Dumps debug information for the element node, it is recursive
745 */
746void
747xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
748{
749    if (output == NULL)
750	output = stdout;
751    if (node == NULL) {
752	int i;
753	char shift[100];
754
755	for (i = 0; ((i < depth) && (i < 25)); i++)
756	    shift[2 * i] = shift[2 * i + 1] = ' ';
757	shift[2 * i] = shift[2 * i + 1] = 0;
758
759	fprintf(output, shift);
760	fprintf(output, "node is NULL\n");
761	return;
762    }
763    xmlDebugDumpOneNode(output, node, depth);
764    if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
765        xmlDebugDumpNodeList(output, node->children, depth + 1);
766}
767
768/**
769 * xmlDebugDumpNodeList:
770 * @output:  the FILE * for the output
771 * @node:  the node list
772 * @depth:  the indentation level.
773 *
774 * Dumps debug information for the list of element node, it is recursive
775 */
776void
777xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
778{
779    if (output == NULL)
780	output = stdout;
781    while (node != NULL) {
782        xmlDebugDumpNode(output, node, depth);
783        node = node->next;
784    }
785}
786
787
788/**
789 * xmlDebugDumpDocumentHead:
790 * @output:  the FILE * for the output
791 * @doc:  the document
792 *
793 * Dumps debug information cncerning the document, not recursive
794 */
795void
796xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
797{
798    if (output == NULL)
799        output = stdout;
800    if (doc == NULL) {
801        fprintf(output, "DOCUMENT == NULL !\n");
802        return;
803    }
804
805    switch (doc->type) {
806        case XML_ELEMENT_NODE:
807            fprintf(output, "Error, ELEMENT found here ");
808            break;
809        case XML_ATTRIBUTE_NODE:
810            fprintf(output, "Error, ATTRIBUTE found here\n");
811            break;
812        case XML_TEXT_NODE:
813            fprintf(output, "Error, TEXT\n");
814            break;
815        case XML_CDATA_SECTION_NODE:
816            fprintf(output, "Error, CDATA_SECTION\n");
817            break;
818        case XML_ENTITY_REF_NODE:
819            fprintf(output, "Error, ENTITY_REF\n");
820            break;
821        case XML_ENTITY_NODE:
822            fprintf(output, "Error, ENTITY\n");
823            break;
824        case XML_PI_NODE:
825            fprintf(output, "Error, PI\n");
826            break;
827        case XML_COMMENT_NODE:
828            fprintf(output, "Error, COMMENT\n");
829            break;
830        case XML_DOCUMENT_NODE:
831            fprintf(output, "DOCUMENT\n");
832            break;
833        case XML_HTML_DOCUMENT_NODE:
834            fprintf(output, "HTML DOCUMENT\n");
835            break;
836        case XML_DOCUMENT_TYPE_NODE:
837            fprintf(output, "Error, DOCUMENT_TYPE\n");
838            break;
839        case XML_DOCUMENT_FRAG_NODE:
840            fprintf(output, "Error, DOCUMENT_FRAG\n");
841            break;
842        case XML_NOTATION_NODE:
843            fprintf(output, "Error, NOTATION\n");
844            break;
845        default:
846            fprintf(output, "NODE_%d\n", doc->type);
847    }
848    if (doc->name != NULL) {
849        fprintf(output, "name=");
850        xmlDebugDumpString(output, BAD_CAST doc->name);
851        fprintf(output, "\n");
852    }
853    if (doc->version != NULL) {
854        fprintf(output, "version=");
855        xmlDebugDumpString(output, doc->version);
856        fprintf(output, "\n");
857    }
858    if (doc->encoding != NULL) {
859        fprintf(output, "encoding=");
860        xmlDebugDumpString(output, doc->encoding);
861        fprintf(output, "\n");
862    }
863    if (doc->URL != NULL) {
864        fprintf(output, "URL=");
865        xmlDebugDumpString(output, doc->URL);
866        fprintf(output, "\n");
867    }
868    if (doc->standalone)
869        fprintf(output, "standalone=true\n");
870    if (doc->oldNs != NULL)
871        xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
872}
873
874/**
875 * xmlDebugDumpDocument:
876 * @output:  the FILE * for the output
877 * @doc:  the document
878 *
879 * Dumps debug information for the document, it's recursive
880 */
881void
882xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
883{
884    if (output == NULL)
885        output = stdout;
886    if (doc == NULL) {
887        fprintf(output, "DOCUMENT == NULL !\n");
888        return;
889    }
890    xmlDebugDumpDocumentHead(output, doc);
891    if (((doc->type == XML_DOCUMENT_NODE) ||
892         (doc->type == XML_HTML_DOCUMENT_NODE)) && (doc->children != NULL))
893        xmlDebugDumpNodeList(output, doc->children, 1);
894}
895
896/**
897 * xmlDebugDumpDTD:
898 * @output:  the FILE * for the output
899 * @dtd:  the DTD
900 *
901 * Dumps debug information for the DTD
902 */
903void
904xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
905{
906    if (output == NULL)
907	output = stdout;
908    if (dtd == NULL) {
909	fprintf(output, "DTD is NULL\n");
910        return;
911    }
912    if (dtd->type != XML_DTD_NODE) {
913        fprintf(output, "PBM: not a DTD\n");
914        return;
915    }
916    if (dtd->name != NULL)
917        fprintf(output, "DTD(%s)", dtd->name);
918    else
919        fprintf(output, "DTD");
920    if (dtd->ExternalID != NULL)
921        fprintf(output, ", PUBLIC %s", dtd->ExternalID);
922    if (dtd->SystemID != NULL)
923        fprintf(output, ", SYSTEM %s", dtd->SystemID);
924    fprintf(output, "\n");
925    /*
926     * Do a bit of checking
927     */
928    if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
929        fprintf(output, "PBM: DTD doc differs from parent's one\n");
930    if (dtd->prev == NULL) {
931        if ((dtd->parent != NULL)
932            && (dtd->parent->children != (xmlNodePtr) dtd))
933            fprintf(output,
934                    "PBM: DTD has no prev and not first of list\n");
935    } else {
936        if (dtd->prev->next != (xmlNodePtr) dtd)
937            fprintf(output, "PBM: DTD prev->next : back link wrong\n");
938    }
939    if (dtd->next == NULL) {
940        if ((dtd->parent != NULL)
941            && (dtd->parent->last != (xmlNodePtr) dtd))
942            fprintf(output, "PBM: DTD has no next and not last of list\n");
943    } else {
944        if (dtd->next->prev != (xmlNodePtr) dtd)
945            fprintf(output, "PBM: DTD next->prev : forward link wrong\n");
946    }
947    if (dtd->children == NULL)
948        fprintf(output, "    DTD is empty\n");
949    else
950        xmlDebugDumpNodeList(output, dtd->children, 1);
951}
952
953static void
954xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output) {
955    if (cur == NULL) {
956	fprintf(output, "Entity is NULL");
957	return;
958    }
959    fprintf(output, "%s : ", cur->name);
960    switch (cur->etype) {
961	case XML_INTERNAL_GENERAL_ENTITY:
962	    fprintf(output, "INTERNAL GENERAL, ");
963	    break;
964	case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
965	    fprintf(output, "EXTERNAL PARSED, ");
966	    break;
967	case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
968	    fprintf(output, "EXTERNAL UNPARSED, ");
969	    break;
970	case XML_INTERNAL_PARAMETER_ENTITY:
971	    fprintf(output, "INTERNAL PARAMETER, ");
972	    break;
973	case XML_EXTERNAL_PARAMETER_ENTITY:
974	    fprintf(output, "EXTERNAL PARAMETER, ");
975	    break;
976	default:
977	    fprintf(output, "UNKNOWN TYPE %d",
978		    cur->etype);
979    }
980    if (cur->ExternalID != NULL)
981	fprintf(output, "ID \"%s\"", cur->ExternalID);
982    if (cur->SystemID != NULL)
983	fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
984    if (cur->orig != NULL)
985	fprintf(output, "\n orig \"%s\"", cur->orig);
986    if ((cur->type != XML_ELEMENT_NODE) &&
987	(cur->content != NULL))
988	fprintf(output, "\n content \"%s\"", cur->content);
989    fprintf(output, "\n");
990}
991
992/**
993 * xmlDebugDumpEntities:
994 * @output:  the FILE * for the output
995 * @doc:  the document
996 *
997 * Dumps debug information for all the entities in use by the document
998 */
999void
1000xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1001{
1002    if (output == NULL)
1003        output = stdout;
1004    if (doc == NULL) {
1005        fprintf(output, "DOCUMENT == NULL !\n");
1006        return;
1007    }
1008
1009    switch (doc->type) {
1010        case XML_ELEMENT_NODE:
1011            fprintf(output, "Error, ELEMENT found here ");
1012            break;
1013        case XML_ATTRIBUTE_NODE:
1014            fprintf(output, "Error, ATTRIBUTE found here\n");
1015            break;
1016        case XML_TEXT_NODE:
1017            fprintf(output, "Error, TEXT\n");
1018            break;
1019        case XML_CDATA_SECTION_NODE:
1020            fprintf(output, "Error, CDATA_SECTION\n");
1021            break;
1022        case XML_ENTITY_REF_NODE:
1023            fprintf(output, "Error, ENTITY_REF\n");
1024            break;
1025        case XML_ENTITY_NODE:
1026            fprintf(output, "Error, ENTITY\n");
1027            break;
1028        case XML_PI_NODE:
1029            fprintf(output, "Error, PI\n");
1030            break;
1031        case XML_COMMENT_NODE:
1032            fprintf(output, "Error, COMMENT\n");
1033            break;
1034        case XML_DOCUMENT_NODE:
1035            fprintf(output, "DOCUMENT\n");
1036            break;
1037        case XML_HTML_DOCUMENT_NODE:
1038            fprintf(output, "HTML DOCUMENT\n");
1039            break;
1040        case XML_DOCUMENT_TYPE_NODE:
1041            fprintf(output, "Error, DOCUMENT_TYPE\n");
1042            break;
1043        case XML_DOCUMENT_FRAG_NODE:
1044            fprintf(output, "Error, DOCUMENT_FRAG\n");
1045            break;
1046        case XML_NOTATION_NODE:
1047            fprintf(output, "Error, NOTATION\n");
1048            break;
1049        default:
1050            fprintf(output, "NODE_%d\n", doc->type);
1051    }
1052    if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1053        xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1054            doc->intSubset->entities;
1055
1056        fprintf(output, "Entities in internal subset\n");
1057        xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
1058                    output);
1059    } else
1060        fprintf(output, "No entities in internal subset\n");
1061    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1062        xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1063            doc->extSubset->entities;
1064
1065        fprintf(output, "Entities in external subset\n");
1066        xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
1067                    output);
1068    } else
1069        fprintf(output, "No entities in external subset\n");
1070}
1071
1072/**
1073 * xmlLsCountNode:
1074 * @node:  the node to count
1075 *
1076 * Count the children of @node.
1077 *
1078 * Returns the number of children of @node.
1079 */
1080int
1081xmlLsCountNode(xmlNodePtr node) {
1082    int ret = 0;
1083    xmlNodePtr list = NULL;
1084
1085    if (node == NULL)
1086	return(0);
1087
1088    switch (node->type) {
1089	case XML_ELEMENT_NODE:
1090	    list = node->children;
1091	    break;
1092	case XML_DOCUMENT_NODE:
1093	case XML_HTML_DOCUMENT_NODE:
1094#ifdef LIBXML_DOCB_ENABLED
1095	case XML_DOCB_DOCUMENT_NODE:
1096#endif
1097	    list = ((xmlDocPtr) node)->children;
1098	    break;
1099	case XML_ATTRIBUTE_NODE:
1100	    list = ((xmlAttrPtr) node)->children;
1101	    break;
1102	case XML_TEXT_NODE:
1103	case XML_CDATA_SECTION_NODE:
1104	case XML_PI_NODE:
1105	case XML_COMMENT_NODE:
1106	    if (node->content != NULL) {
1107#ifndef XML_USE_BUFFER_CONTENT
1108		ret = xmlStrlen(node->content);
1109#else
1110		ret = xmlBufferLength(node->content);
1111#endif
1112            }
1113	    break;
1114	case XML_ENTITY_REF_NODE:
1115	case XML_DOCUMENT_TYPE_NODE:
1116	case XML_ENTITY_NODE:
1117	case XML_DOCUMENT_FRAG_NODE:
1118	case XML_NOTATION_NODE:
1119	case XML_DTD_NODE:
1120        case XML_ELEMENT_DECL:
1121        case XML_ATTRIBUTE_DECL:
1122        case XML_ENTITY_DECL:
1123	case XML_NAMESPACE_DECL:
1124	case XML_XINCLUDE_START:
1125	case XML_XINCLUDE_END:
1126	    ret = 1;
1127	    break;
1128    }
1129    for (;list != NULL;ret++)
1130        list = list->next;
1131    return(ret);
1132}
1133
1134/**
1135 * xmlLsOneNode:
1136 * @output:  the FILE * for the output
1137 * @node:  the node to dump
1138 *
1139 * Dump to @output the type and name of @node.
1140 */
1141void
1142xmlLsOneNode(FILE *output, xmlNodePtr node) {
1143    if (node == NULL) {
1144	fprintf(output, "NULL\n");
1145	return;
1146    }
1147    switch (node->type) {
1148	case XML_ELEMENT_NODE:
1149	    fprintf(output, "-");
1150	    break;
1151	case XML_ATTRIBUTE_NODE:
1152	    fprintf(output, "a");
1153	    break;
1154	case XML_TEXT_NODE:
1155	    fprintf(output, "t");
1156	    break;
1157	case XML_CDATA_SECTION_NODE:
1158	    fprintf(output, "c");
1159	    break;
1160	case XML_ENTITY_REF_NODE:
1161	    fprintf(output, "e");
1162	    break;
1163	case XML_ENTITY_NODE:
1164	    fprintf(output, "E");
1165	    break;
1166	case XML_PI_NODE:
1167	    fprintf(output, "p");
1168	    break;
1169	case XML_COMMENT_NODE:
1170	    fprintf(output, "c");
1171	    break;
1172	case XML_DOCUMENT_NODE:
1173	    fprintf(output, "d");
1174	    break;
1175	case XML_HTML_DOCUMENT_NODE:
1176	    fprintf(output, "h");
1177	    break;
1178	case XML_DOCUMENT_TYPE_NODE:
1179	    fprintf(output, "T");
1180	    break;
1181	case XML_DOCUMENT_FRAG_NODE:
1182	    fprintf(output, "F");
1183	    break;
1184	case XML_NOTATION_NODE:
1185	    fprintf(output, "N");
1186	    break;
1187	case XML_NAMESPACE_DECL:
1188	    fprintf(output, "n");
1189	    break;
1190	default:
1191	    fprintf(output, "?");
1192    }
1193    if (node->type != XML_NAMESPACE_DECL) {
1194	if (node->properties != NULL)
1195	    fprintf(output, "a");
1196	else
1197	    fprintf(output, "-");
1198	if (node->nsDef != NULL)
1199	    fprintf(output, "n");
1200	else
1201	    fprintf(output, "-");
1202    }
1203
1204    fprintf(output, " %8d ", xmlLsCountNode(node));
1205
1206    switch (node->type) {
1207	case XML_ELEMENT_NODE:
1208	    if (node->name != NULL)
1209		fprintf(output, "%s", node->name);
1210	    break;
1211	case XML_ATTRIBUTE_NODE:
1212	    if (node->name != NULL)
1213		fprintf(output, "%s", node->name);
1214	    break;
1215	case XML_TEXT_NODE:
1216	    if (node->content != NULL) {
1217#ifndef XML_USE_BUFFER_CONTENT
1218		xmlDebugDumpString(output, node->content);
1219#else
1220		xmlDebugDumpString(output, xmlBufferContent(node->content));
1221#endif
1222            }
1223	    break;
1224	case XML_CDATA_SECTION_NODE:
1225	    break;
1226	case XML_ENTITY_REF_NODE:
1227	    if (node->name != NULL)
1228		fprintf(output, "%s", node->name);
1229	    break;
1230	case XML_ENTITY_NODE:
1231	    if (node->name != NULL)
1232		fprintf(output, "%s", node->name);
1233	    break;
1234	case XML_PI_NODE:
1235	    if (node->name != NULL)
1236		fprintf(output, "%s", node->name);
1237	    break;
1238	case XML_COMMENT_NODE:
1239	    break;
1240	case XML_DOCUMENT_NODE:
1241	    break;
1242	case XML_HTML_DOCUMENT_NODE:
1243	    break;
1244	case XML_DOCUMENT_TYPE_NODE:
1245	    break;
1246	case XML_DOCUMENT_FRAG_NODE:
1247	    break;
1248	case XML_NOTATION_NODE:
1249	    break;
1250	case XML_NAMESPACE_DECL: {
1251	    xmlNsPtr ns = (xmlNsPtr) node;
1252
1253	    if (ns->prefix == NULL)
1254		fprintf(output, "default -> %s", ns->href);
1255	    else
1256		fprintf(output, "%s -> %s", ns->prefix, ns->href);
1257	    break;
1258	}
1259	default:
1260	    if (node->name != NULL)
1261		fprintf(output, "%s", node->name);
1262    }
1263    fprintf(output, "\n");
1264}
1265
1266/**
1267 * xmlBoolToText:
1268 * @boolval: a bool to turn into text
1269 *
1270 * Convenient way to turn bool into text
1271 *
1272 * Returns a pointer to either "True" or "False"
1273 */
1274const char *
1275xmlBoolToText(int boolval)
1276{
1277    if (boolval)
1278        return("True");
1279    else
1280        return("False");
1281}
1282
1283/****************************************************************
1284 *								*
1285 *	 	The XML shell related functions			*
1286 *								*
1287 ****************************************************************/
1288
1289
1290
1291/*
1292 * TODO: Improvement/cleanups for the XML shell
1293 *     - allow to shell out an editor on a subpart
1294 *     - cleanup function registrations (with help) and calling
1295 *     - provide registration routines
1296 */
1297
1298/**
1299 * xmlShellPrintXPathError:
1300 * @errorType: valid xpath error id
1301 * @arg: the argument that cause xpath to fail
1302 *
1303 * Print the xpath error to libxml default error channel
1304 */
1305void
1306xmlShellPrintXPathError(int errorType, const char *arg)
1307{
1308    const char *default_arg = "Result";
1309
1310    if (!arg)
1311        arg = default_arg;
1312
1313    switch (errorType) {
1314        case XPATH_UNDEFINED:
1315            xmlGenericError(xmlGenericErrorContext,
1316                            "%s: no such node\n", arg);
1317            break;
1318
1319        case XPATH_BOOLEAN:
1320            xmlGenericError(xmlGenericErrorContext,
1321                            "%s is a Boolean\n", arg);
1322            break;
1323        case XPATH_NUMBER:
1324            xmlGenericError(xmlGenericErrorContext,
1325                            "%s is a number\n", arg);
1326            break;
1327        case XPATH_STRING:
1328            xmlGenericError(xmlGenericErrorContext,
1329                            "%s is a string\n", arg);
1330            break;
1331        case XPATH_POINT:
1332            xmlGenericError(xmlGenericErrorContext,
1333                            "%s is a point\n", arg);
1334            break;
1335        case XPATH_RANGE:
1336            xmlGenericError(xmlGenericErrorContext,
1337                            "%s is a range\n", arg);
1338            break;
1339        case XPATH_LOCATIONSET:
1340            xmlGenericError(xmlGenericErrorContext,
1341                            "%s is a range\n", arg);
1342            break;
1343        case XPATH_USERS:
1344            xmlGenericError(xmlGenericErrorContext,
1345                            "%s is user-defined\n", arg);
1346            break;
1347        case XPATH_XSLT_TREE:
1348            xmlGenericError(xmlGenericErrorContext,
1349                            "%s is an XSLT value tree\n", arg);
1350            break;
1351    }
1352    xmlGenericError(xmlGenericErrorContext,
1353                    "Try casting the result string function (xpath builtin)\n",
1354                    arg);
1355}
1356
1357
1358/**
1359 * xmlShellPrintNode:
1360 * @node : a non-null node to print to stdout
1361 *
1362 * Print node to stdout
1363 */
1364void
1365xmlShellPrintNode(xmlNodePtr node)
1366{
1367    if (!node)
1368        return;
1369
1370    if (node->type == XML_DOCUMENT_NODE)
1371        xmlDocDump(stdout, (xmlDocPtr) node);
1372    else if (node->type == XML_ATTRIBUTE_NODE)
1373        xmlDebugDumpAttrList(stdout, (xmlAttrPtr) node, 0);
1374    else
1375        xmlElemDump(stdout, node->doc, node);
1376
1377    fprintf(stdout, "\n");
1378}
1379
1380
1381/**
1382 * xmlShellPrintXPathResult:
1383 * @list: a valid result generated by an xpath evaluation
1384 *
1385 * Prints result to stdout
1386 */
1387void
1388xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1389{
1390    int i = 0;
1391
1392    if (list != NULL) {
1393        switch (list->type) {
1394            case XPATH_NODESET:{
1395                    int indx;
1396
1397                    if (list->nodesetval) {
1398                        for (indx = 0; indx < list->nodesetval->nodeNr;
1399                             indx++) {
1400                            if (i > 0)
1401                                fprintf(stderr, " -------\n");
1402                            xmlShellPrintNode(list->nodesetval->
1403                                              nodeTab[indx]);
1404                        }
1405                    } else {
1406                        xmlGenericError(xmlGenericErrorContext,
1407                                        "Empty node set\n");
1408                    }
1409                    break;
1410                }
1411            case XPATH_BOOLEAN:
1412                xmlGenericError(xmlGenericErrorContext,
1413                                "Is a Boolean:%s\n",
1414                                xmlBoolToText(list->boolval));
1415                break;
1416            case XPATH_NUMBER:
1417                xmlGenericError(xmlGenericErrorContext,
1418                                "Is a number:%0g\n", list->floatval);
1419                break;
1420            case XPATH_STRING:
1421                xmlGenericError(xmlGenericErrorContext,
1422                                "Is a string:%s\n", list->stringval);
1423                break;
1424
1425            default:
1426                xmlShellPrintXPathError(list->type, NULL);
1427        }
1428    }
1429}
1430
1431/**
1432 * xmlShellList:
1433 * @ctxt:  the shell context
1434 * @arg:  unused
1435 * @node:  a node
1436 * @node2:  unused
1437 *
1438 * Implements the XML shell function "ls"
1439 * Does an Unix like listing of the given node (like a directory)
1440 *
1441 * Returns 0
1442 */
1443int
1444xmlShellList(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1445             char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1446             xmlNodePtr node2 ATTRIBUTE_UNUSED)
1447{
1448    xmlNodePtr cur;
1449    if (node == NULL) {
1450	fprintf(stdout, "NULL\n");
1451	return (0);
1452    }
1453    if ((node->type == XML_DOCUMENT_NODE) ||
1454        (node->type == XML_HTML_DOCUMENT_NODE)) {
1455        cur = ((xmlDocPtr) node)->children;
1456    } else if (node->type == XML_NAMESPACE_DECL) {
1457        xmlLsOneNode(stdout, node);
1458        return (0);
1459    } else if (node->children != NULL) {
1460        cur = node->children;
1461    } else {
1462        xmlLsOneNode(stdout, node);
1463        return (0);
1464    }
1465    while (cur != NULL) {
1466        xmlLsOneNode(stdout, cur);
1467        cur = cur->next;
1468    }
1469    return (0);
1470}
1471
1472/**
1473 * xmlShellBase:
1474 * @ctxt:  the shell context
1475 * @arg:  unused
1476 * @node:  a node
1477 * @node2:  unused
1478 *
1479 * Implements the XML shell function "base"
1480 * dumps the current XML base of the node
1481 *
1482 * Returns 0
1483 */
1484int
1485xmlShellBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1486             char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1487             xmlNodePtr node2 ATTRIBUTE_UNUSED)
1488{
1489    xmlChar *base;
1490    if (node == NULL) {
1491	fprintf(stdout, "NULL\n");
1492	return (0);
1493    }
1494
1495    base = xmlNodeGetBase(node->doc, node);
1496
1497    if (base == NULL) {
1498        fprintf(stdout, " No base found !!!\n");
1499    } else {
1500        fprintf(stdout, "%s\n", base);
1501        xmlFree(base);
1502    }
1503    return (0);
1504}
1505
1506/**
1507 * xmlShellSetBase:
1508 * @ctxt:  the shell context
1509 * @arg:  the new base
1510 * @node:  a node
1511 * @node2:  unused
1512 *
1513 * Implements the XML shell function "setbase"
1514 * change the current XML base of the node
1515 *
1516 * Returns 0
1517 */
1518static int
1519xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1520             char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1521             xmlNodePtr node2 ATTRIBUTE_UNUSED)
1522{
1523    xmlNodeSetBase(node, (xmlChar*) arg);
1524    return (0);
1525}
1526
1527/**
1528 * xmlShellDir:
1529 * @ctxt:  the shell context
1530 * @arg:  unused
1531 * @node:  a node
1532 * @node2:  unused
1533 *
1534 * Implements the XML shell function "dir"
1535 * dumps informations about the node (namespace, attributes, content).
1536 *
1537 * Returns 0
1538 */
1539int
1540xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1541            char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1542            xmlNodePtr node2 ATTRIBUTE_UNUSED)
1543{
1544    if (node == NULL) {
1545	fprintf(stdout, "NULL\n");
1546	return (0);
1547    }
1548    if ((node->type == XML_DOCUMENT_NODE) ||
1549        (node->type == XML_HTML_DOCUMENT_NODE)) {
1550        xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
1551    } else if (node->type == XML_ATTRIBUTE_NODE) {
1552        xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
1553    } else {
1554        xmlDebugDumpOneNode(stdout, node, 0);
1555    }
1556    return (0);
1557}
1558
1559/**
1560 * xmlShellCat:
1561 * @ctxt:  the shell context
1562 * @arg:  unused
1563 * @node:  a node
1564 * @node2:  unused
1565 *
1566 * Implements the XML shell function "cat"
1567 * dumps the serialization node content (XML or HTML).
1568 *
1569 * Returns 0
1570 */
1571int
1572xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
1573            xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1574{
1575    if (node == NULL) {
1576	fprintf(stdout, "NULL\n");
1577	return (0);
1578    }
1579    if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1580#ifdef LIBXML_HTML_ENABLED
1581        if (node->type == XML_HTML_DOCUMENT_NODE)
1582            htmlDocDump(stdout, (htmlDocPtr) node);
1583        else
1584            htmlNodeDumpFile(stdout, ctxt->doc, node);
1585#else
1586        if (node->type == XML_DOCUMENT_NODE)
1587            xmlDocDump(stdout, (xmlDocPtr) node);
1588        else
1589            xmlElemDump(stdout, ctxt->doc, node);
1590#endif /* LIBXML_HTML_ENABLED */
1591    } else {
1592        if (node->type == XML_DOCUMENT_NODE)
1593            xmlDocDump(stdout, (xmlDocPtr) node);
1594        else
1595            xmlElemDump(stdout, ctxt->doc, node);
1596    }
1597    fprintf(stdout, "\n");
1598    return (0);
1599}
1600
1601/**
1602 * xmlShellLoad:
1603 * @ctxt:  the shell context
1604 * @filename:  the file name
1605 * @node:  unused
1606 * @node2:  unused
1607 *
1608 * Implements the XML shell function "load"
1609 * loads a new document specified by the filename
1610 *
1611 * Returns 0 or -1 if loading failed
1612 */
1613int
1614xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
1615             xmlNodePtr node ATTRIBUTE_UNUSED,
1616             xmlNodePtr node2 ATTRIBUTE_UNUSED)
1617{
1618    xmlDocPtr doc;
1619    int html = 0;
1620
1621    if (ctxt->doc != NULL)
1622        html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
1623
1624    if (html) {
1625#ifdef LIBXML_HTML_ENABLED
1626        doc = htmlParseFile(filename, NULL);
1627#else
1628        fprintf(stdout, "HTML support not compiled in\n");
1629        doc = NULL;
1630#endif /* LIBXML_HTML_ENABLED */
1631    } else {
1632        doc = xmlParseFile(filename);
1633    }
1634    if (doc != NULL) {
1635        if (ctxt->loaded == 1) {
1636            xmlFreeDoc(ctxt->doc);
1637        }
1638        ctxt->loaded = 1;
1639#ifdef LIBXML_XPATH_ENABLED
1640        xmlXPathFreeContext(ctxt->pctxt);
1641#endif /* LIBXML_XPATH_ENABLED */
1642        xmlFree(ctxt->filename);
1643        ctxt->doc = doc;
1644        ctxt->node = (xmlNodePtr) doc;
1645#ifdef LIBXML_XPATH_ENABLED
1646        ctxt->pctxt = xmlXPathNewContext(doc);
1647#endif /* LIBXML_XPATH_ENABLED */
1648        ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1649    } else
1650        return (-1);
1651    return (0);
1652}
1653
1654/**
1655 * xmlShellWrite:
1656 * @ctxt:  the shell context
1657 * @filename:  the file name
1658 * @node:  a node in the tree
1659 * @node2:  unused
1660 *
1661 * Implements the XML shell function "write"
1662 * Write the current node to the filename, it saves the serialization
1663 * of the subtree under the @node specified
1664 *
1665 * Returns 0 or -1 in case of error
1666 */
1667int
1668xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1669              xmlNodePtr node2 ATTRIBUTE_UNUSED)
1670{
1671    if (node == NULL)
1672        return (-1);
1673    if ((filename == NULL) || (filename[0] == 0)) {
1674        xmlGenericError(xmlGenericErrorContext,
1675                        "Write command requires a filename argument\n");
1676        return (-1);
1677    }
1678#ifdef W_OK
1679    if (access((char *) filename, W_OK)) {
1680        xmlGenericError(xmlGenericErrorContext,
1681                        "Cannot write to %s\n", filename);
1682        return (-1);
1683    }
1684#endif
1685    switch (node->type) {
1686        case XML_DOCUMENT_NODE:
1687            if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1688                xmlGenericError(xmlGenericErrorContext,
1689                                "Failed to write to %s\n", filename);
1690                return (-1);
1691            }
1692            break;
1693        case XML_HTML_DOCUMENT_NODE:
1694#ifdef LIBXML_HTML_ENABLED
1695            if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1696                xmlGenericError(xmlGenericErrorContext,
1697                                "Failed to write to %s\n", filename);
1698                return (-1);
1699            }
1700#else
1701            if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1702                xmlGenericError(xmlGenericErrorContext,
1703                                "Failed to write to %s\n", filename);
1704                return (-1);
1705            }
1706#endif /* LIBXML_HTML_ENABLED */
1707            break;
1708        default:{
1709                FILE *f;
1710
1711                f = fopen((char *) filename, "w");
1712                if (f == NULL) {
1713                    xmlGenericError(xmlGenericErrorContext,
1714                                    "Failed to write to %s\n", filename);
1715                    return (-1);
1716                }
1717                xmlElemDump(f, ctxt->doc, node);
1718                fclose(f);
1719            }
1720    }
1721    return (0);
1722}
1723
1724/**
1725 * xmlShellSave:
1726 * @ctxt:  the shell context
1727 * @filename:  the file name (optional)
1728 * @node:  unused
1729 * @node2:  unused
1730 *
1731 * Implements the XML shell function "save"
1732 * Write the current document to the filename, or it's original name
1733 *
1734 * Returns 0 or -1 in case of error
1735 */
1736int
1737xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
1738             xmlNodePtr node ATTRIBUTE_UNUSED,
1739             xmlNodePtr node2 ATTRIBUTE_UNUSED)
1740{
1741    if (ctxt->doc == NULL)
1742        return (-1);
1743    if ((filename == NULL) || (filename[0] == 0))
1744        filename = ctxt->filename;
1745#ifdef W_OK
1746    if (access((char *) filename, W_OK)) {
1747        xmlGenericError(xmlGenericErrorContext,
1748                        "Cannot save to %s\n", filename);
1749        return (-1);
1750    }
1751#endif
1752    switch (ctxt->doc->type) {
1753        case XML_DOCUMENT_NODE:
1754            if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1755                xmlGenericError(xmlGenericErrorContext,
1756                                "Failed to save to %s\n", filename);
1757            }
1758            break;
1759        case XML_HTML_DOCUMENT_NODE:
1760#ifdef LIBXML_HTML_ENABLED
1761            if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1762                xmlGenericError(xmlGenericErrorContext,
1763                                "Failed to save to %s\n", filename);
1764            }
1765#else
1766            if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1767                xmlGenericError(xmlGenericErrorContext,
1768                                "Failed to save to %s\n", filename);
1769            }
1770#endif /* LIBXML_HTML_ENABLED */
1771            break;
1772        default:
1773            xmlGenericError(xmlGenericErrorContext,
1774	    "To save to subparts of a document use the 'write' command\n");
1775            return (-1);
1776
1777    }
1778    return (0);
1779}
1780
1781/**
1782 * xmlShellValidate:
1783 * @ctxt:  the shell context
1784 * @dtd:  the DTD URI (optional)
1785 * @node:  unused
1786 * @node2:  unused
1787 *
1788 * Implements the XML shell function "validate"
1789 * Validate the document, if a DTD path is provided, then the validation
1790 * is done against the given DTD.
1791 *
1792 * Returns 0 or -1 in case of error
1793 */
1794int
1795xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
1796                 xmlNodePtr node ATTRIBUTE_UNUSED,
1797                 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1798{
1799    xmlValidCtxt vctxt;
1800    int res = -1;
1801
1802    vctxt.userData = stderr;
1803    vctxt.error = (xmlValidityErrorFunc) fprintf;
1804    vctxt.warning = (xmlValidityWarningFunc) fprintf;
1805
1806    if ((dtd == NULL) || (dtd[0] == 0)) {
1807        res = xmlValidateDocument(&vctxt, ctxt->doc);
1808    } else {
1809        xmlDtdPtr subset;
1810
1811        subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1812        if (subset != NULL) {
1813            res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1814
1815            xmlFreeDtd(subset);
1816        }
1817    }
1818    return (res);
1819}
1820
1821/**
1822 * xmlShellDu:
1823 * @ctxt:  the shell context
1824 * @arg:  unused
1825 * @tree:  a node defining a subtree
1826 * @node2:  unused
1827 *
1828 * Implements the XML shell function "du"
1829 * show the structure of the subtree under node @tree
1830 * If @tree is null, the command works on the current node.
1831 *
1832 * Returns 0 or -1 in case of error
1833 */
1834int
1835xmlShellDu(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1836           char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
1837           xmlNodePtr node2 ATTRIBUTE_UNUSED)
1838{
1839    xmlNodePtr node;
1840    int indent = 0, i;
1841
1842    if (tree == NULL)
1843        return (-1);
1844    node = tree;
1845    while (node != NULL) {
1846        if ((node->type == XML_DOCUMENT_NODE) ||
1847            (node->type == XML_HTML_DOCUMENT_NODE)) {
1848            fprintf(stdout, "/\n");
1849        } else if (node->type == XML_ELEMENT_NODE) {
1850            for (i = 0; i < indent; i++)
1851                fprintf(stdout, "  ");
1852            fprintf(stdout, "%s\n", node->name);
1853        } else {
1854        }
1855
1856        /*
1857         * Browse the full subtree, deep first
1858         */
1859
1860        if ((node->type == XML_DOCUMENT_NODE) ||
1861            (node->type == XML_HTML_DOCUMENT_NODE)) {
1862            node = ((xmlDocPtr) node)->children;
1863        } else if ((node->children != NULL)
1864                   && (node->type != XML_ENTITY_REF_NODE)) {
1865            /* deep first */
1866            node = node->children;
1867            indent++;
1868        } else if ((node != tree) && (node->next != NULL)) {
1869            /* then siblings */
1870            node = node->next;
1871        } else if (node != tree) {
1872            /* go up to parents->next if needed */
1873            while (node != tree) {
1874                if (node->parent != NULL) {
1875                    node = node->parent;
1876                    indent--;
1877                }
1878                if ((node != tree) && (node->next != NULL)) {
1879                    node = node->next;
1880                    break;
1881                }
1882                if (node->parent == NULL) {
1883                    node = NULL;
1884                    break;
1885                }
1886                if (node == tree) {
1887                    node = NULL;
1888                    break;
1889                }
1890            }
1891            /* exit condition */
1892            if (node == tree)
1893                node = NULL;
1894        } else
1895            node = NULL;
1896    }
1897    return (0);
1898}
1899
1900/**
1901 * xmlShellPwd:
1902 * @ctxt:  the shell context
1903 * @buffer:  the output buffer
1904 * @node:  a node
1905 * @node2:  unused
1906 *
1907 * Implements the XML shell function "pwd"
1908 * Show the full path from the root to the node, if needed building
1909 * thumblers when similar elements exists at a given ancestor level.
1910 * The output is compatible with XPath commands.
1911 *
1912 * Returns 0 or -1 in case of error
1913 */
1914int
1915xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
1916            xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1917{
1918    xmlChar *path;
1919
1920    if (node == NULL)
1921        return (-1);
1922
1923    path = xmlGetNodePath(node);
1924    if (path == NULL)
1925	return (-1);
1926
1927    /*
1928     * This test prevents buffer overflow, because this routine
1929     * is only called by xmlShell, in which the second argument is
1930     * 500 chars long.
1931     * It is a dirty hack before a cleaner solution is found.
1932     * Documentation should mention that the second argument must
1933     * be at least 500 chars long, and could be stripped if too long.
1934     */
1935    snprintf(buffer, 499, "%s", path);
1936    buffer[499] = '0';
1937    xmlFree(path);
1938
1939    return (0);
1940}
1941
1942/**
1943 * xmlShell
1944 * @doc:  the initial document
1945 * @filename:  the output buffer
1946 * @input:  the line reading function
1947 * @output:  the output FILE*
1948 *
1949 * Implements the XML shell
1950 * This allow to load, validate, view, modify and save a document
1951 * using a environment similar to a UNIX commandline.
1952 */
1953void
1954xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1955         FILE * output)
1956{
1957    char prompt[500] = "/ > ";
1958    char *cmdline = NULL, *cur;
1959    int nbargs;
1960    char command[100];
1961    char arg[400];
1962    int i;
1963    xmlShellCtxtPtr ctxt;
1964    xmlXPathObjectPtr list;
1965
1966    if (doc == NULL)
1967        return;
1968    if (filename == NULL)
1969        return;
1970    if (input == NULL)
1971        return;
1972    if (output == NULL)
1973        return;
1974    ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1975    if (ctxt == NULL)
1976        return;
1977    ctxt->loaded = 0;
1978    ctxt->doc = doc;
1979    ctxt->input = input;
1980    ctxt->output = output;
1981    ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1982    ctxt->node = (xmlNodePtr) ctxt->doc;
1983
1984#ifdef LIBXML_XPATH_ENABLED
1985    ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1986    if (ctxt->pctxt == NULL) {
1987        xmlFree(ctxt);
1988        return;
1989    }
1990#endif /* LIBXML_XPATH_ENABLED */
1991    while (1) {
1992        if (ctxt->node == (xmlNodePtr) ctxt->doc)
1993            sprintf(prompt, "%s > ", "/");
1994        else if (ctxt->node->name)
1995            snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
1996        else
1997            sprintf(prompt, "? > ");
1998        prompt[sizeof(prompt) - 1] = 0;
1999
2000        /*
2001         * Get a new command line
2002         */
2003        cmdline = ctxt->input(prompt);
2004        if (cmdline == NULL)
2005            break;
2006
2007        /*
2008         * Parse the command itself
2009         */
2010        cur = cmdline;
2011        nbargs = 0;
2012        while ((*cur == ' ') || (*cur == '\t'))
2013            cur++;
2014        i = 0;
2015        while ((*cur != ' ') && (*cur != '\t') &&
2016               (*cur != '\n') && (*cur != '\r')) {
2017            if (*cur == 0)
2018                break;
2019            command[i++] = *cur++;
2020        }
2021        command[i] = 0;
2022        if (i == 0)
2023            continue;
2024        nbargs++;
2025
2026        /*
2027         * Parse the argument
2028         */
2029        while ((*cur == ' ') || (*cur == '\t'))
2030            cur++;
2031        i = 0;
2032        while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2033            if (*cur == 0)
2034                break;
2035            arg[i++] = *cur++;
2036        }
2037        arg[i] = 0;
2038        if (i != 0)
2039            nbargs++;
2040
2041        /*
2042         * start interpreting the command
2043         */
2044        if (!strcmp(command, "exit"))
2045            break;
2046        if (!strcmp(command, "quit"))
2047            break;
2048        if (!strcmp(command, "bye"))
2049            break;
2050		if (!strcmp(command, "help")) {
2051		  fprintf(stdout, "\tbase         display XML base of the node\n");
2052		  fprintf(stdout, "\tsetbase URI  change the XML base of the node\n");
2053		  fprintf(stdout, "\tbye          leave shell\n");
2054		  fprintf(stdout, "\tcat [node]   display node or current node\n");
2055		  fprintf(stdout, "\tcd [path]    change directory to path or to root\n");
2056		  fprintf(stdout, "\tdir [path]   dumps informations about the node (namespace, attributes, content)\n");
2057		  fprintf(stdout, "\tdu [path]    show the structure of the subtree under path or the current node\n");
2058		  fprintf(stdout, "\texit         leave shell\n");
2059		  fprintf(stdout, "\thelp         display this help\n");
2060		  fprintf(stdout, "\tfree         display memory usage\n");
2061		  fprintf(stdout, "\tload [name]  load a new document with name\n");
2062		  fprintf(stdout, "\tls [path]    list contents of path or the current directory\n");
2063#ifdef LIBXML_XPATH_ENABLED
2064		  fprintf(stdout, "\txpath expr   evaluate the XPath expression in that context and print the result\n");
2065#endif /* LIBXML_XPATH_ENABLED */
2066		  fprintf(stdout, "\tpwd          display current working directory\n");
2067		  fprintf(stdout, "\tquit         leave shell\n");
2068		  fprintf(stdout, "\tsave [name]  save this document to name or the original name\n");
2069		  fprintf(stdout, "\tvalidate     check the document for errors\n");
2070		  fprintf(stdout, "\twrite [name] write the current node to the filename\n");
2071        } else if (!strcmp(command, "validate")) {
2072            xmlShellValidate(ctxt, arg, NULL, NULL);
2073        } else if (!strcmp(command, "load")) {
2074            xmlShellLoad(ctxt, arg, NULL, NULL);
2075        } else if (!strcmp(command, "save")) {
2076            xmlShellSave(ctxt, arg, NULL, NULL);
2077        } else if (!strcmp(command, "write")) {
2078            xmlShellWrite(ctxt, arg, NULL, NULL);
2079        } else if (!strcmp(command, "free")) {
2080            if (arg[0] == 0) {
2081                xmlMemShow(stdout, 0);
2082            } else {
2083                int len = 0;
2084
2085                sscanf(arg, "%d", &len);
2086                xmlMemShow(stdout, len);
2087            }
2088        } else if (!strcmp(command, "pwd")) {
2089            char dir[500];
2090
2091            if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
2092                fprintf(stdout, "%s\n", dir);
2093        } else if (!strcmp(command, "du")) {
2094            xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2095        } else if (!strcmp(command, "base")) {
2096            xmlShellBase(ctxt, NULL, ctxt->node, NULL);
2097#ifdef LIBXML_XPATH_ENABLED
2098        } else if (!strcmp(command, "xpath")) {
2099            if (arg[0] == 0) {
2100		xmlGenericError(xmlGenericErrorContext,
2101				"xpath: expression required\n");
2102	    } else {
2103                ctxt->pctxt->node = ctxt->node;
2104                list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2105		xmlXPathDebugDumpObject(stdout, list, 0);
2106		xmlXPathFreeObject(list);
2107	    }
2108#endif /* LIBXML_XPATH_ENABLED */
2109        } else if (!strcmp(command, "setbase")) {
2110            xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
2111        } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2112            int dir = (!strcmp(command, "dir"));
2113
2114            if (arg[0] == 0) {
2115                if (dir)
2116                    xmlShellDir(ctxt, NULL, ctxt->node, NULL);
2117                else
2118                    xmlShellList(ctxt, NULL, ctxt->node, NULL);
2119            } else {
2120                ctxt->pctxt->node = ctxt->node;
2121#ifdef LIBXML_XPATH_ENABLED
2122                ctxt->pctxt->node = ctxt->node;
2123                list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2124#else
2125                list = NULL;
2126#endif /* LIBXML_XPATH_ENABLED */
2127                if (list != NULL) {
2128                    switch (list->type) {
2129                        case XPATH_UNDEFINED:
2130                            xmlGenericError(xmlGenericErrorContext,
2131                                            "%s: no such node\n", arg);
2132                            break;
2133                        case XPATH_NODESET:{
2134                                int indx;
2135
2136				if (list->nodesetval == NULL)
2137				    break;
2138
2139                                for (indx = 0;
2140                                     indx < list->nodesetval->nodeNr;
2141                                     indx++) {
2142                                    if (dir)
2143                                        xmlShellDir(ctxt, NULL,
2144                                                    list->nodesetval->
2145                                                    nodeTab[indx], NULL);
2146                                    else
2147                                        xmlShellList(ctxt, NULL,
2148                                                     list->nodesetval->
2149                                                     nodeTab[indx], NULL);
2150                                }
2151                                break;
2152                            }
2153                        case XPATH_BOOLEAN:
2154                            xmlGenericError(xmlGenericErrorContext,
2155                                            "%s is a Boolean\n", arg);
2156                            break;
2157                        case XPATH_NUMBER:
2158                            xmlGenericError(xmlGenericErrorContext,
2159                                            "%s is a number\n", arg);
2160                            break;
2161                        case XPATH_STRING:
2162                            xmlGenericError(xmlGenericErrorContext,
2163                                            "%s is a string\n", arg);
2164                            break;
2165                        case XPATH_POINT:
2166                            xmlGenericError(xmlGenericErrorContext,
2167                                            "%s is a point\n", arg);
2168                            break;
2169                        case XPATH_RANGE:
2170                            xmlGenericError(xmlGenericErrorContext,
2171                                            "%s is a range\n", arg);
2172                            break;
2173                        case XPATH_LOCATIONSET:
2174                            xmlGenericError(xmlGenericErrorContext,
2175                                            "%s is a range\n", arg);
2176                            break;
2177                        case XPATH_USERS:
2178                            xmlGenericError(xmlGenericErrorContext,
2179                                            "%s is user-defined\n", arg);
2180                            break;
2181                        case XPATH_XSLT_TREE:
2182                            xmlGenericError(xmlGenericErrorContext,
2183                                            "%s is an XSLT value tree\n",
2184                                            arg);
2185                            break;
2186                    }
2187#ifdef LIBXML_XPATH_ENABLED
2188                    xmlXPathFreeObject(list);
2189#endif
2190                } else {
2191                    xmlGenericError(xmlGenericErrorContext,
2192                                    "%s: no such node\n", arg);
2193                }
2194                ctxt->pctxt->node = NULL;
2195            }
2196        } else if (!strcmp(command, "cd")) {
2197            if (arg[0] == 0) {
2198                ctxt->node = (xmlNodePtr) ctxt->doc;
2199            } else {
2200#ifdef LIBXML_XPATH_ENABLED
2201                ctxt->pctxt->node = ctxt->node;
2202                list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2203#else
2204                list = NULL;
2205#endif /* LIBXML_XPATH_ENABLED */
2206                if (list != NULL) {
2207                    switch (list->type) {
2208                        case XPATH_UNDEFINED:
2209                            xmlGenericError(xmlGenericErrorContext,
2210                                            "%s: no such node\n", arg);
2211                            break;
2212                        case XPATH_NODESET:
2213                            if (list->nodesetval != NULL) {
2214				if (list->nodesetval->nodeNr == 1) {
2215				    ctxt->node = list->nodesetval->nodeTab[0];
2216				} else
2217				    xmlGenericError(xmlGenericErrorContext,
2218						    "%s is a %d Node Set\n",
2219						    arg,
2220						    list->nodesetval->nodeNr);
2221                            } else
2222                                xmlGenericError(xmlGenericErrorContext,
2223                                                "%s is an empty Node Set\n",
2224                                                arg);
2225                            break;
2226                        case XPATH_BOOLEAN:
2227                            xmlGenericError(xmlGenericErrorContext,
2228                                            "%s is a Boolean\n", arg);
2229                            break;
2230                        case XPATH_NUMBER:
2231                            xmlGenericError(xmlGenericErrorContext,
2232                                            "%s is a number\n", arg);
2233                            break;
2234                        case XPATH_STRING:
2235                            xmlGenericError(xmlGenericErrorContext,
2236                                            "%s is a string\n", arg);
2237                            break;
2238                        case XPATH_POINT:
2239                            xmlGenericError(xmlGenericErrorContext,
2240                                            "%s is a point\n", arg);
2241                            break;
2242                        case XPATH_RANGE:
2243                            xmlGenericError(xmlGenericErrorContext,
2244                                            "%s is a range\n", arg);
2245                            break;
2246                        case XPATH_LOCATIONSET:
2247                            xmlGenericError(xmlGenericErrorContext,
2248                                            "%s is a range\n", arg);
2249                            break;
2250                        case XPATH_USERS:
2251                            xmlGenericError(xmlGenericErrorContext,
2252                                            "%s is user-defined\n", arg);
2253                            break;
2254                        case XPATH_XSLT_TREE:
2255                            xmlGenericError(xmlGenericErrorContext,
2256                                            "%s is an XSLT value tree\n",
2257                                            arg);
2258                            break;
2259                    }
2260#ifdef LIBXML_XPATH_ENABLED
2261                    xmlXPathFreeObject(list);
2262#endif
2263                } else {
2264                    xmlGenericError(xmlGenericErrorContext,
2265                                    "%s: no such node\n", arg);
2266                }
2267                ctxt->pctxt->node = NULL;
2268            }
2269        } else if (!strcmp(command, "cat")) {
2270            if (arg[0] == 0) {
2271                xmlShellCat(ctxt, NULL, ctxt->node, NULL);
2272            } else {
2273                ctxt->pctxt->node = ctxt->node;
2274#ifdef LIBXML_XPATH_ENABLED
2275                ctxt->pctxt->node = ctxt->node;
2276                list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2277#else
2278                list = NULL;
2279#endif /* LIBXML_XPATH_ENABLED */
2280                if (list != NULL) {
2281                    switch (list->type) {
2282                        case XPATH_UNDEFINED:
2283                            xmlGenericError(xmlGenericErrorContext,
2284                                            "%s: no such node\n", arg);
2285                            break;
2286                        case XPATH_NODESET:{
2287                                int indx;
2288
2289				if (list->nodesetval == NULL)
2290				    break;
2291
2292                                for (indx = 0;
2293                                     indx < list->nodesetval->nodeNr;
2294                                     indx++) {
2295                                    if (i > 0)
2296                                        fprintf(stdout, " -------\n");
2297                                    xmlShellCat(ctxt, NULL,
2298                                                list->nodesetval->
2299                                                nodeTab[indx], NULL);
2300                                }
2301                                break;
2302                            }
2303                        case XPATH_BOOLEAN:
2304                            xmlGenericError(xmlGenericErrorContext,
2305                                            "%s is a Boolean\n", arg);
2306                            break;
2307                        case XPATH_NUMBER:
2308                            xmlGenericError(xmlGenericErrorContext,
2309                                            "%s is a number\n", arg);
2310                            break;
2311                        case XPATH_STRING:
2312                            xmlGenericError(xmlGenericErrorContext,
2313                                            "%s is a string\n", arg);
2314                            break;
2315                        case XPATH_POINT:
2316                            xmlGenericError(xmlGenericErrorContext,
2317                                            "%s is a point\n", arg);
2318                            break;
2319                        case XPATH_RANGE:
2320                            xmlGenericError(xmlGenericErrorContext,
2321                                            "%s is a range\n", arg);
2322                            break;
2323                        case XPATH_LOCATIONSET:
2324                            xmlGenericError(xmlGenericErrorContext,
2325                                            "%s is a range\n", arg);
2326                            break;
2327                        case XPATH_USERS:
2328                            xmlGenericError(xmlGenericErrorContext,
2329                                            "%s is user-defined\n", arg);
2330                            break;
2331                        case XPATH_XSLT_TREE:
2332                            xmlGenericError(xmlGenericErrorContext,
2333                                            "%s is an XSLT value tree\n",
2334                                            arg);
2335                            break;
2336                    }
2337#ifdef LIBXML_XPATH_ENABLED
2338                    xmlXPathFreeObject(list);
2339#endif
2340                } else {
2341                    xmlGenericError(xmlGenericErrorContext,
2342                                    "%s: no such node\n", arg);
2343                }
2344                ctxt->pctxt->node = NULL;
2345            }
2346        } else {
2347            xmlGenericError(xmlGenericErrorContext,
2348                            "Unknown command %s\n", command);
2349        }
2350        free(cmdline);          /* not xmlFree here ! */
2351    }
2352#ifdef LIBXML_XPATH_ENABLED
2353    xmlXPathFreeContext(ctxt->pctxt);
2354#endif /* LIBXML_XPATH_ENABLED */
2355    if (ctxt->loaded) {
2356        xmlFreeDoc(ctxt->doc);
2357    }
2358    if (ctxt->filename != NULL)
2359        xmlFree(ctxt->filename);
2360    xmlFree(ctxt);
2361    if (cmdline != NULL)
2362        free(cmdline);          /* not xmlFree here ! */
2363}
2364
2365#endif /* LIBXML_DEBUG_ENABLED */
2366