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