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