Annotation of XML/debugXML.c, revision 1.28
1.1 daniel 1: /*
2: * debugXML.c : This is a set of routines used for debugging the tree
3: * produced by the XML parser.
4: *
1.2 daniel 5: * See Copyright for the status of this software.
6: *
1.1 daniel 7: * Daniel Veillard <Daniel.Veillard@w3.org>
8: */
9:
1.11 daniel 10: #ifdef WIN32
11: #include "win32config.h"
12: #else
13: #include "config.h"
14: #endif
1.23 daniel 15:
16: #include "xmlversion.h"
17: #ifdef LIBXML_DEBUG_ENABLED
18:
1.1 daniel 19: #include <stdio.h>
1.26 veillard 20: #include <string.h>
1.12 daniel 21: #ifdef HAVE_STDLIB_H
22: #include <stdlib.h>
23: #endif
1.14 daniel 24: #ifdef HAVE_STRING_H
25: #include <string.h>
26: #endif
1.23 daniel 27: #include <libxml/xmlmemory.h>
28: #include <libxml/tree.h>
29: #include <libxml/parser.h>
30: #include <libxml/valid.h>
31: #include <libxml/debugXML.h>
32: #include <libxml/HTMLtree.h>
33: #include <libxml/HTMLparser.h>
1.1 daniel 34:
35: #define IS_BLANK(c) \
36: (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
37:
1.6 daniel 38: void xmlDebugDumpString(FILE *output, const xmlChar *str) {
1.1 daniel 39: int i;
40: for (i = 0;i < 40;i++)
41: if (str[i] == 0) return;
42: else if (IS_BLANK(str[i])) fputc(' ', output);
1.27 veillard 43: else if (str[i] >= 0x80)
44: fprintf(output, "#%X", str[i]);
1.1 daniel 45: else fputc(str[i], output);
46: fprintf(output, "...");
47: }
48:
1.18 daniel 49: void xmlDebugDumpDtd(FILE *output, xmlDtdPtr dtd, int depth) {
50: int i;
51: char shift[100];
52:
53: for (i = 0;((i < depth) && (i < 25));i++)
54: shift[2 * i] = shift[2 * i + 1] = ' ';
55: shift[2 * i] = shift[2 * i + 1] = 0;
56:
57: fprintf(output, shift);
58:
59: if (dtd->type != XML_DTD_NODE) {
60: fprintf(output, "PBM: not a DTD\n");
61: return;
62: }
63: if (dtd->name != NULL)
64: fprintf(output, "DTD(%s)", dtd->name);
65: else
66: fprintf(output, "DTD");
67: if (dtd->ExternalID != NULL)
68: fprintf(output, ", PUBLIC %s", dtd->ExternalID);
69: if (dtd->SystemID != NULL)
70: fprintf(output, ", SYSTEM %s", dtd->SystemID);
71: fprintf(output, "\n");
72: /*
73: * Do a bit of checking
74: */
75: if (dtd->parent == NULL)
76: fprintf(output, "PBM: Dtd has no parent\n");
77: if (dtd->doc == NULL)
78: fprintf(output, "PBM: Dtd has no doc\n");
79: if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
80: fprintf(output, "PBM: Dtd doc differs from parent's one\n");
81: if (dtd->prev == NULL) {
82: if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
83: fprintf(output, "PBM: Dtd has no prev and not first of list\n");
84: } else {
85: if (dtd->prev->next != (xmlNodePtr) dtd)
86: fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
87: }
88: if (dtd->next == NULL) {
89: if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
90: fprintf(output, "PBM: Dtd has no next and not last of list\n");
91: } else {
92: if (dtd->next->prev != (xmlNodePtr) dtd)
93: fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
94: }
95: }
96:
97: void xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) {
98: int i;
99: char shift[100];
100:
101: for (i = 0;((i < depth) && (i < 25));i++)
102: shift[2 * i] = shift[2 * i + 1] = ' ';
103: shift[2 * i] = shift[2 * i + 1] = 0;
104:
105: fprintf(output, shift);
106:
107: if (attr->type != XML_ATTRIBUTE_DECL) {
108: fprintf(output, "PBM: not a Attr\n");
109: return;
110: }
111: if (attr->name != NULL)
112: fprintf(output, "ATTRDECL(%s)", attr->name);
113: else
114: fprintf(output, "PBM ATTRDECL noname!!!");
115: if (attr->elem != NULL)
116: fprintf(output, " for %s", attr->elem);
117: else
118: fprintf(output, " PBM noelem!!!");
119: switch (attr->atype) {
120: case XML_ATTRIBUTE_CDATA:
121: fprintf(output, " CDATA");
122: break;
123: case XML_ATTRIBUTE_ID:
124: fprintf(output, " ID");
125: break;
126: case XML_ATTRIBUTE_IDREF:
127: fprintf(output, " IDREF");
128: break;
129: case XML_ATTRIBUTE_IDREFS:
130: fprintf(output, " IDREFS");
131: break;
132: case XML_ATTRIBUTE_ENTITY:
133: fprintf(output, " ENTITY");
134: break;
135: case XML_ATTRIBUTE_ENTITIES:
136: fprintf(output, " ENTITIES");
137: break;
138: case XML_ATTRIBUTE_NMTOKEN:
139: fprintf(output, " NMTOKEN");
140: break;
141: case XML_ATTRIBUTE_NMTOKENS:
142: fprintf(output, " NMTOKENS");
143: break;
144: case XML_ATTRIBUTE_ENUMERATION:
145: fprintf(output, " ENUMERATION");
146: break;
147: case XML_ATTRIBUTE_NOTATION:
148: fprintf(output, " NOTATION ");
149: break;
150: }
151: if (attr->tree != NULL) {
152: int i;
153: xmlEnumerationPtr cur = attr->tree;
154:
155: for (i = 0;i < 5; i++) {
156: if (i != 0)
157: fprintf(output, "|%s", cur->name);
158: else
159: fprintf(output, " (%s", cur->name);
160: cur = cur->next;
161: if (cur == NULL) break;
162: }
163: if (cur == NULL)
164: fprintf(output, ")");
165: else
166: fprintf(output, "...)");
167: }
168: switch (attr->def) {
169: case XML_ATTRIBUTE_NONE:
170: break;
171: case XML_ATTRIBUTE_REQUIRED:
172: fprintf(output, " REQUIRED");
173: break;
174: case XML_ATTRIBUTE_IMPLIED:
175: fprintf(output, " IMPLIED");
176: break;
177: case XML_ATTRIBUTE_FIXED:
178: fprintf(output, " FIXED");
179: break;
180: }
181: if (attr->defaultValue != NULL) {
182: fprintf(output, "\"");
183: xmlDebugDumpString(output, attr->defaultValue);
184: fprintf(output, "\"");
185: }
186: printf("\n");
187:
188: /*
189: * Do a bit of checking
190: */
191: if (attr->parent == NULL)
192: fprintf(output, "PBM: Attr has no parent\n");
193: if (attr->doc == NULL)
194: fprintf(output, "PBM: Attr has no doc\n");
195: if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
196: fprintf(output, "PBM: Attr doc differs from parent's one\n");
197: if (attr->prev == NULL) {
198: if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr))
199: fprintf(output, "PBM: Attr has no prev and not first of list\n");
200: } else {
201: if (attr->prev->next != (xmlNodePtr) attr)
202: fprintf(output, "PBM: Attr prev->next : back link wrong\n");
203: }
204: if (attr->next == NULL) {
205: if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr))
206: fprintf(output, "PBM: Attr has no next and not last of list\n");
207: } else {
208: if (attr->next->prev != (xmlNodePtr) attr)
209: fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
210: }
211: }
212:
213: void xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) {
214: int i;
215: char shift[100];
216:
217: for (i = 0;((i < depth) && (i < 25));i++)
218: shift[2 * i] = shift[2 * i + 1] = ' ';
219: shift[2 * i] = shift[2 * i + 1] = 0;
220:
221: fprintf(output, shift);
222:
223: if (elem->type != XML_ELEMENT_DECL) {
224: fprintf(output, "PBM: not a Elem\n");
225: return;
226: }
1.27 veillard 227: if (elem->name != NULL) {
228: fprintf(output, "ELEMDECL(");
229: xmlDebugDumpString(output, elem->name);
230: fprintf(output, ")");
231: } else
1.18 daniel 232: fprintf(output, "PBM ELEMDECL noname!!!");
233: switch (elem->etype) {
234: case XML_ELEMENT_TYPE_EMPTY:
235: fprintf(output, ", EMPTY");
236: break;
237: case XML_ELEMENT_TYPE_ANY:
238: fprintf(output, ", ANY");
239: break;
240: case XML_ELEMENT_TYPE_MIXED:
241: fprintf(output, ", MIXED ");
242: break;
243: case XML_ELEMENT_TYPE_ELEMENT:
244: fprintf(output, ", MIXED ");
245: break;
246: }
247: if (elem->content != NULL) {
248: char buf[1001];
249:
250: buf[0] = 0;
251: xmlSprintfElementContent(buf, elem->content, 1);
252: buf[1000] = 0;
253: fprintf(output, "%s", buf);
254: }
255: printf("\n");
256:
257: /*
258: * Do a bit of checking
259: */
260: if (elem->parent == NULL)
261: fprintf(output, "PBM: Elem has no parent\n");
262: if (elem->doc == NULL)
263: fprintf(output, "PBM: Elem has no doc\n");
264: if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
265: fprintf(output, "PBM: Elem doc differs from parent's one\n");
266: if (elem->prev == NULL) {
267: if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem))
268: fprintf(output, "PBM: Elem has no prev and not first of list\n");
269: } else {
270: if (elem->prev->next != (xmlNodePtr) elem)
271: fprintf(output, "PBM: Elem prev->next : back link wrong\n");
272: }
273: if (elem->next == NULL) {
274: if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem))
275: fprintf(output, "PBM: Elem has no next and not last of list\n");
276: } else {
277: if (elem->next->prev != (xmlNodePtr) elem)
278: fprintf(output, "PBM: Elem next->prev : forward link wrong\n");
279: }
280: }
281:
1.20 daniel 282: void xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) {
283: int i;
284: char shift[100];
285:
286: for (i = 0;((i < depth) && (i < 25));i++)
287: shift[2 * i] = shift[2 * i + 1] = ' ';
288: shift[2 * i] = shift[2 * i + 1] = 0;
289:
290: fprintf(output, shift);
291:
292: if (ent->type != XML_ENTITY_DECL) {
293: fprintf(output, "PBM: not a Entity decl\n");
294: return;
295: }
1.27 veillard 296: if (ent->name != NULL) {
297: fprintf(output, "ENTITYDECL(");
298: xmlDebugDumpString(output, ent->name);
299: fprintf(output, ")");
300: } else
1.20 daniel 301: fprintf(output, "PBM ENTITYDECL noname!!!");
302: switch (ent->etype) {
303: case XML_INTERNAL_GENERAL_ENTITY:
304: fprintf(output, ", internal\n");
305: break;
306: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
307: fprintf(output, ", external parsed\n");
308: break;
309: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
310: fprintf(output, ", unparsed\n");
311: break;
312: case XML_INTERNAL_PARAMETER_ENTITY:
313: fprintf(output, ", parameter\n");
314: break;
315: case XML_EXTERNAL_PARAMETER_ENTITY:
316: fprintf(output, ", external parameter\n");
317: break;
318: case XML_INTERNAL_PREDEFINED_ENTITY:
319: fprintf(output, ", predefined\n");
320: break;
321: }
322: if (ent->ExternalID) {
323: fprintf(output, shift);
324: fprintf(output, "ExternalID=%s\n", ent->ExternalID);
325: }
326: if (ent->SystemID) {
327: fprintf(output, shift);
328: fprintf(output, "SystemID=%s\n", ent->SystemID);
329: }
330: if (ent->content) {
331: fprintf(output, shift);
332: fprintf(output, "content=");
333: xmlDebugDumpString(output, ent->content);
334: fprintf(output, "\n");
335: }
336:
337: /*
338: * Do a bit of checking
339: */
340: if (ent->parent == NULL)
341: fprintf(output, "PBM: Ent has no parent\n");
342: if (ent->doc == NULL)
343: fprintf(output, "PBM: Ent has no doc\n");
344: if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
345: fprintf(output, "PBM: Ent doc differs from parent's one\n");
346: if (ent->prev == NULL) {
347: if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent))
348: fprintf(output, "PBM: Ent has no prev and not first of list\n");
349: } else {
350: if (ent->prev->next != (xmlNodePtr) ent)
351: fprintf(output, "PBM: Ent prev->next : back link wrong\n");
352: }
353: if (ent->next == NULL) {
354: if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent))
355: fprintf(output, "PBM: Ent has no next and not last of list\n");
356: } else {
357: if (ent->next->prev != (xmlNodePtr) ent)
358: fprintf(output, "PBM: Ent next->prev : forward link wrong\n");
359: }
360: }
361:
1.1 daniel 362: void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
363: int i;
364: char shift[100];
365:
366: for (i = 0;((i < depth) && (i < 25));i++)
367: shift[2 * i] = shift[2 * i + 1] = ' ';
368: shift[2 * i] = shift[2 * i + 1] = 0;
369:
370: fprintf(output, shift);
371: if (ns->type == XML_GLOBAL_NAMESPACE)
372: fprintf(output, "old ");
1.10 daniel 373: if (ns->prefix != NULL)
374: fprintf(output, "namespace %s href=", ns->prefix);
375: else
1.12 daniel 376: fprintf(output, "default namespace href=");
1.10 daniel 377:
1.1 daniel 378: xmlDebugDumpString(output, ns->href);
379: fprintf(output, "\n");
380: }
381:
382: void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
383: while (ns != NULL) {
384: xmlDebugDumpNamespace(output, ns, depth);
385: ns = ns->next;
386: }
387: }
388:
389: void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
390: int i;
391: char shift[100];
392:
393: for (i = 0;((i < depth) && (i < 25));i++)
394: shift[2 * i] = shift[2 * i + 1] = ' ';
395: shift[2 * i] = shift[2 * i + 1] = 0;
396:
397: fprintf(output, shift);
1.19 daniel 398: switch (ent->etype) {
1.1 daniel 399: case XML_INTERNAL_GENERAL_ENTITY:
400: fprintf(output, "INTERNAL_GENERAL_ENTITY ");
401: break;
402: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
403: fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
404: break;
405: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
406: fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
407: break;
408: case XML_INTERNAL_PARAMETER_ENTITY:
409: fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
410: break;
411: case XML_EXTERNAL_PARAMETER_ENTITY:
412: fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
413: break;
414: default:
1.19 daniel 415: fprintf(output, "ENTITY_%d ! ", ent->etype);
1.1 daniel 416: }
417: fprintf(output, "%s\n", ent->name);
418: if (ent->ExternalID) {
419: fprintf(output, shift);
420: fprintf(output, "ExternalID=%s\n", ent->ExternalID);
421: }
422: if (ent->SystemID) {
423: fprintf(output, shift);
424: fprintf(output, "SystemID=%s\n", ent->SystemID);
425: }
426: if (ent->content) {
427: fprintf(output, shift);
428: fprintf(output, "content=");
429: xmlDebugDumpString(output, ent->content);
430: fprintf(output, "\n");
431: }
432: }
433:
434: void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
435: int i;
436: char shift[100];
437:
438: for (i = 0;((i < depth) && (i < 25));i++)
439: shift[2 * i] = shift[2 * i + 1] = ' ';
440: shift[2 * i] = shift[2 * i + 1] = 0;
441:
442: fprintf(output, shift);
1.18 daniel 443:
1.27 veillard 444: fprintf(output, "ATTRIBUTE ");
445: xmlDebugDumpString(output, attr->name);
446: fprintf(output, "\n");
1.16 daniel 447: if (attr->children != NULL)
448: xmlDebugDumpNodeList(output, attr->children, depth + 1);
1.18 daniel 449:
450: /*
451: * Do a bit of checking
452: */
453: if (attr->parent == NULL)
454: fprintf(output, "PBM: Attr has no parent\n");
455: if (attr->doc == NULL)
456: fprintf(output, "PBM: Attr has no doc\n");
457: if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
458: fprintf(output, "PBM: Attr doc differs from parent's one\n");
459: if (attr->prev == NULL) {
460: if ((attr->parent != NULL) && (attr->parent->properties != attr))
461: fprintf(output, "PBM: Attr has no prev and not first of list\n");
462: } else {
463: if (attr->prev->next != attr)
464: fprintf(output, "PBM: Attr prev->next : back link wrong\n");
465: }
466: if (attr->next != NULL) {
467: if (attr->next->prev != attr)
468: fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
469: }
1.1 daniel 470: }
471:
472: void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) {
473: while (attr != NULL) {
474: xmlDebugDumpAttr(output, attr, depth);
475: attr = attr->next;
476: }
477: }
478:
1.3 daniel 479: void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) {
1.1 daniel 480: int i;
481: char shift[100];
482:
483: for (i = 0;((i < depth) && (i < 25));i++)
484: shift[2 * i] = shift[2 * i + 1] = ' ';
485: shift[2 * i] = shift[2 * i + 1] = 0;
486:
487: switch (node->type) {
488: case XML_ELEMENT_NODE:
1.21 daniel 489: fprintf(output, shift);
1.1 daniel 490: fprintf(output, "ELEMENT ");
1.27 veillard 491: if (node->ns != NULL) {
492: xmlDebugDumpString(output, node->ns->prefix);
493: fprintf(output, ":");
494: }
495: xmlDebugDumpString(output, node->name);
496: fprintf(output, "\n");
1.1 daniel 497: break;
498: case XML_ATTRIBUTE_NODE:
1.21 daniel 499: fprintf(output, shift);
1.1 daniel 500: fprintf(output, "Error, ATTRIBUTE found here\n");
501: break;
502: case XML_TEXT_NODE:
1.21 daniel 503: fprintf(output, shift);
1.1 daniel 504: fprintf(output, "TEXT\n");
505: break;
506: case XML_CDATA_SECTION_NODE:
1.21 daniel 507: fprintf(output, shift);
1.1 daniel 508: fprintf(output, "CDATA_SECTION\n");
509: break;
510: case XML_ENTITY_REF_NODE:
1.21 daniel 511: fprintf(output, shift);
1.15 daniel 512: fprintf(output, "ENTITY_REF(%s)\n", node->name);
1.1 daniel 513: break;
514: case XML_ENTITY_NODE:
1.21 daniel 515: fprintf(output, shift);
1.1 daniel 516: fprintf(output, "ENTITY\n");
517: break;
518: case XML_PI_NODE:
1.21 daniel 519: fprintf(output, shift);
1.4 daniel 520: fprintf(output, "PI %s\n", node->name);
1.1 daniel 521: break;
522: case XML_COMMENT_NODE:
1.21 daniel 523: fprintf(output, shift);
1.1 daniel 524: fprintf(output, "COMMENT\n");
525: break;
526: case XML_DOCUMENT_NODE:
1.7 daniel 527: case XML_HTML_DOCUMENT_NODE:
1.21 daniel 528: fprintf(output, shift);
1.1 daniel 529: fprintf(output, "Error, DOCUMENT found here\n");
530: break;
531: case XML_DOCUMENT_TYPE_NODE:
1.21 daniel 532: fprintf(output, shift);
1.1 daniel 533: fprintf(output, "DOCUMENT_TYPE\n");
534: break;
535: case XML_DOCUMENT_FRAG_NODE:
1.21 daniel 536: fprintf(output, shift);
1.1 daniel 537: fprintf(output, "DOCUMENT_FRAG\n");
538: break;
539: case XML_NOTATION_NODE:
540: fprintf(output, "NOTATION\n");
541: break;
1.18 daniel 542: case XML_DTD_NODE:
1.21 daniel 543: xmlDebugDumpDtd(output, (xmlDtdPtr) node, depth);
1.18 daniel 544: return;
545: case XML_ELEMENT_DECL:
1.21 daniel 546: xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
1.18 daniel 547: return;
548: case XML_ATTRIBUTE_DECL:
1.21 daniel 549: xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
1.18 daniel 550: return;
1.20 daniel 551: case XML_ENTITY_DECL:
1.21 daniel 552: xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
1.20 daniel 553: return;
1.1 daniel 554: default:
1.21 daniel 555: fprintf(output, shift);
1.1 daniel 556: fprintf(output, "NODE_%d\n", node->type);
557: }
558: if (node->doc == NULL) {
559: fprintf(output, shift);
560: fprintf(output, "doc == NULL !!!\n");
561: }
562: if (node->nsDef != NULL)
563: xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
564: if (node->properties != NULL)
565: xmlDebugDumpAttrList(output, node->properties, depth + 1);
566: if (node->type != XML_ENTITY_REF_NODE) {
567: if (node->content != NULL) {
568: fprintf(output, shift);
569: fprintf(output, "content=");
1.8 daniel 570: #ifndef XML_USE_BUFFER_CONTENT
1.1 daniel 571: xmlDebugDumpString(output, node->content);
1.8 daniel 572: #else
573: xmlDebugDumpString(output, xmlBufferContent(node->content));
574: #endif
1.1 daniel 575: fprintf(output, "\n");
576: }
577: } else {
578: xmlEntityPtr ent;
579: ent = xmlGetDocEntity(node->doc, node->name);
580: if (ent != NULL)
581: xmlDebugDumpEntity(output, ent, depth + 1);
1.18 daniel 582: }
583: /*
584: * Do a bit of checking
585: */
586: if (node->parent == NULL)
587: fprintf(output, "PBM: Node has no parent\n");
588: if (node->doc == NULL)
589: fprintf(output, "PBM: Node has no doc\n");
590: if ((node->parent != NULL) && (node->doc != node->parent->doc))
591: fprintf(output, "PBM: Node doc differs from parent's one\n");
592: if (node->prev == NULL) {
593: if ((node->parent != NULL) && (node->parent->children != node))
594: fprintf(output, "PBM: Node has no prev and not first of list\n");
595: } else {
596: if (node->prev->next != node)
597: fprintf(output, "PBM: Node prev->next : back link wrong\n");
598: }
599: if (node->next == NULL) {
600: if ((node->parent != NULL) && (node->parent->last != node))
601: fprintf(output, "PBM: Node has no next and not last of list\n");
602: } else {
603: if (node->next->prev != node)
604: fprintf(output, "PBM: Node next->prev : forward link wrong\n");
1.1 daniel 605: }
1.3 daniel 606: }
607:
608: void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
609: xmlDebugDumpOneNode(output, node, depth);
1.16 daniel 610: if (node->children != NULL)
611: xmlDebugDumpNodeList(output, node->children, depth + 1);
1.1 daniel 612: }
613:
614: void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
615: while (node != NULL) {
616: xmlDebugDumpNode(output, node, depth);
617: node = node->next;
618: }
619: }
620:
621:
1.12 daniel 622: void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
1.1 daniel 623: if (output == NULL) output = stdout;
624: if (doc == NULL) {
625: fprintf(output, "DOCUMENT == NULL !\n");
626: return;
627: }
628:
629: switch (doc->type) {
630: case XML_ELEMENT_NODE:
631: fprintf(output, "Error, ELEMENT found here ");
632: break;
633: case XML_ATTRIBUTE_NODE:
634: fprintf(output, "Error, ATTRIBUTE found here\n");
635: break;
636: case XML_TEXT_NODE:
637: fprintf(output, "Error, TEXT\n");
638: break;
639: case XML_CDATA_SECTION_NODE:
640: fprintf(output, "Error, CDATA_SECTION\n");
641: break;
642: case XML_ENTITY_REF_NODE:
643: fprintf(output, "Error, ENTITY_REF\n");
644: break;
645: case XML_ENTITY_NODE:
646: fprintf(output, "Error, ENTITY\n");
647: break;
648: case XML_PI_NODE:
649: fprintf(output, "Error, PI\n");
650: break;
651: case XML_COMMENT_NODE:
652: fprintf(output, "Error, COMMENT\n");
653: break;
654: case XML_DOCUMENT_NODE:
655: fprintf(output, "DOCUMENT\n");
1.7 daniel 656: break;
657: case XML_HTML_DOCUMENT_NODE:
658: fprintf(output, "HTML DOCUMENT\n");
1.1 daniel 659: break;
660: case XML_DOCUMENT_TYPE_NODE:
661: fprintf(output, "Error, DOCUMENT_TYPE\n");
662: break;
663: case XML_DOCUMENT_FRAG_NODE:
664: fprintf(output, "Error, DOCUMENT_FRAG\n");
665: break;
666: case XML_NOTATION_NODE:
667: fprintf(output, "Error, NOTATION\n");
668: break;
669: default:
670: fprintf(output, "NODE_%d\n", doc->type);
671: }
672: if (doc->name != NULL) {
673: fprintf(output, "name=");
1.5 daniel 674: xmlDebugDumpString(output, BAD_CAST doc->name);
1.1 daniel 675: fprintf(output, "\n");
676: }
677: if (doc->version != NULL) {
678: fprintf(output, "version=");
679: xmlDebugDumpString(output, doc->version);
680: fprintf(output, "\n");
681: }
682: if (doc->encoding != NULL) {
683: fprintf(output, "encoding=");
684: xmlDebugDumpString(output, doc->encoding);
685: fprintf(output, "\n");
686: }
687: if (doc->standalone)
688: fprintf(output, "standalone=true\n");
689: if (doc->oldNs != NULL)
690: xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
1.12 daniel 691: }
692:
693: void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
694: if (output == NULL) output = stdout;
695: if (doc == NULL) {
696: fprintf(output, "DOCUMENT == NULL !\n");
697: return;
698: }
699: xmlDebugDumpDocumentHead(output, doc);
700: if (((doc->type == XML_DOCUMENT_NODE) ||
701: (doc->type == XML_HTML_DOCUMENT_NODE)) &&
1.16 daniel 702: (doc->children != NULL))
703: xmlDebugDumpNodeList(output, doc->children, 1);
1.12 daniel 704: }
1.9 daniel 705:
706: void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
707: int i;
708: xmlEntityPtr cur;
709:
710: if (output == NULL) output = stdout;
711: if (doc == NULL) {
712: fprintf(output, "DOCUMENT == NULL !\n");
713: return;
714: }
715:
716: switch (doc->type) {
717: case XML_ELEMENT_NODE:
718: fprintf(output, "Error, ELEMENT found here ");
719: break;
720: case XML_ATTRIBUTE_NODE:
721: fprintf(output, "Error, ATTRIBUTE found here\n");
722: break;
723: case XML_TEXT_NODE:
724: fprintf(output, "Error, TEXT\n");
725: break;
726: case XML_CDATA_SECTION_NODE:
727: fprintf(output, "Error, CDATA_SECTION\n");
728: break;
729: case XML_ENTITY_REF_NODE:
730: fprintf(output, "Error, ENTITY_REF\n");
731: break;
732: case XML_ENTITY_NODE:
733: fprintf(output, "Error, ENTITY\n");
734: break;
735: case XML_PI_NODE:
736: fprintf(output, "Error, PI\n");
737: break;
738: case XML_COMMENT_NODE:
739: fprintf(output, "Error, COMMENT\n");
740: break;
741: case XML_DOCUMENT_NODE:
742: fprintf(output, "DOCUMENT\n");
743: break;
744: case XML_HTML_DOCUMENT_NODE:
745: fprintf(output, "HTML DOCUMENT\n");
746: break;
747: case XML_DOCUMENT_TYPE_NODE:
748: fprintf(output, "Error, DOCUMENT_TYPE\n");
749: break;
750: case XML_DOCUMENT_FRAG_NODE:
751: fprintf(output, "Error, DOCUMENT_FRAG\n");
752: break;
753: case XML_NOTATION_NODE:
754: fprintf(output, "Error, NOTATION\n");
755: break;
756: default:
757: fprintf(output, "NODE_%d\n", doc->type);
758: }
759: if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
760: xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
761: doc->intSubset->entities;
762: fprintf(output, "Entities in internal subset\n");
1.28 ! veillard 763: for (i = 0;i < table->max_entities;i++) {
1.20 daniel 764: cur = table->table[i];
1.28 ! veillard 765: while (cur != NULL) {
! 766: fprintf(output, "%d : %s : ", i, cur->name);
! 767: switch (cur->etype) {
! 768: case XML_INTERNAL_GENERAL_ENTITY:
! 769: fprintf(output, "INTERNAL GENERAL, ");
! 770: break;
! 771: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
! 772: fprintf(output, "EXTERNAL PARSED, ");
! 773: break;
! 774: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
! 775: fprintf(output, "EXTERNAL UNPARSED, ");
! 776: break;
! 777: case XML_INTERNAL_PARAMETER_ENTITY:
! 778: fprintf(output, "INTERNAL PARAMETER, ");
! 779: break;
! 780: case XML_EXTERNAL_PARAMETER_ENTITY:
! 781: fprintf(output, "EXTERNAL PARAMETER, ");
! 782: break;
! 783: default:
! 784: fprintf(output, "UNKNOWN TYPE %d",
! 785: cur->etype);
! 786: }
! 787: if (cur->ExternalID != NULL)
! 788: fprintf(output, "ID \"%s\"", cur->ExternalID);
! 789: if (cur->SystemID != NULL)
! 790: fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
! 791: if (cur->orig != NULL)
! 792: fprintf(output, "\n orig \"%s\"", cur->orig);
! 793: if (cur->content != NULL)
! 794: fprintf(output, "\n content \"%s\"", cur->content);
! 795: fprintf(output, "\n");
! 796: cur = cur->nexte;
1.9 daniel 797: }
798: }
799: } else
800: fprintf(output, "No entities in internal subset\n");
801: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
802: xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
803: doc->extSubset->entities;
804: fprintf(output, "Entities in external subset\n");
1.28 ! veillard 805: for (i = 0;i < table->max_entities;i++) {
1.20 daniel 806: cur = table->table[i];
1.28 ! veillard 807: while (cur != NULL) {
! 808: fprintf(output, "%d : %s : ", i, cur->name);
! 809: switch (cur->etype) {
! 810: case XML_INTERNAL_GENERAL_ENTITY:
! 811: fprintf(output, "INTERNAL GENERAL, ");
! 812: break;
! 813: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
! 814: fprintf(output, "EXTERNAL PARSED, ");
! 815: break;
! 816: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
! 817: fprintf(output, "EXTERNAL UNPARSED, ");
! 818: break;
! 819: case XML_INTERNAL_PARAMETER_ENTITY:
! 820: fprintf(output, "INTERNAL PARAMETER, ");
! 821: break;
! 822: case XML_EXTERNAL_PARAMETER_ENTITY:
! 823: fprintf(output, "EXTERNAL PARAMETER, ");
! 824: break;
! 825: default:
! 826: fprintf(output, "UNKNOWN TYPE %d",
! 827: cur->etype);
! 828: }
! 829: if (cur->ExternalID != NULL)
! 830: fprintf(output, "ID \"%s\"", cur->ExternalID);
! 831: if (cur->SystemID != NULL)
! 832: fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
! 833: if (cur->orig != NULL)
! 834: fprintf(output, "\n orig \"%s\"", cur->orig);
! 835: if (cur->content != NULL)
! 836: fprintf(output, "\n content \"%s\"", cur->content);
! 837: fprintf(output, "\n");
! 838: cur = cur->nexte;
1.9 daniel 839: }
840: }
841: } else
842: fprintf(output, "No entities in external subset\n");
843: }
1.12 daniel 844:
845: static int xmlLsCountNode(xmlNodePtr node) {
846: int ret = 0;
847: xmlNodePtr list = NULL;
848:
849: switch (node->type) {
850: case XML_ELEMENT_NODE:
1.16 daniel 851: list = node->children;
1.12 daniel 852: break;
853: case XML_DOCUMENT_NODE:
854: case XML_HTML_DOCUMENT_NODE:
1.16 daniel 855: list = ((xmlDocPtr) node)->children;
1.12 daniel 856: break;
857: case XML_ATTRIBUTE_NODE:
1.16 daniel 858: list = ((xmlAttrPtr) node)->children;
1.12 daniel 859: break;
860: case XML_TEXT_NODE:
861: case XML_CDATA_SECTION_NODE:
862: case XML_PI_NODE:
863: case XML_COMMENT_NODE:
864: if (node->content != NULL) {
865: #ifndef XML_USE_BUFFER_CONTENT
866: ret = xmlStrlen(node->content);
867: #else
868: ret = xmlBufferLength(node->content);
869: #endif
870: }
871: break;
872: case XML_ENTITY_REF_NODE:
873: case XML_DOCUMENT_TYPE_NODE:
874: case XML_ENTITY_NODE:
875: case XML_DOCUMENT_FRAG_NODE:
876: case XML_NOTATION_NODE:
1.16 daniel 877: case XML_DTD_NODE:
1.17 daniel 878: case XML_ELEMENT_DECL:
879: case XML_ATTRIBUTE_DECL:
1.20 daniel 880: case XML_ENTITY_DECL:
1.12 daniel 881: ret = 1;
882: break;
883: }
884: for (;list != NULL;ret++)
885: list = list->next;
886: return(ret);
887: }
888:
889: void xmlLsOneNode(FILE *output, xmlNodePtr node) {
890: switch (node->type) {
891: case XML_ELEMENT_NODE:
892: fprintf(output, "-");
893: break;
894: case XML_ATTRIBUTE_NODE:
895: fprintf(output, "a");
896: break;
897: case XML_TEXT_NODE:
898: fprintf(output, "t");
899: break;
900: case XML_CDATA_SECTION_NODE:
901: fprintf(output, "c");
902: break;
903: case XML_ENTITY_REF_NODE:
904: fprintf(output, "e");
905: break;
906: case XML_ENTITY_NODE:
907: fprintf(output, "E");
908: break;
909: case XML_PI_NODE:
910: fprintf(output, "p");
911: break;
912: case XML_COMMENT_NODE:
913: fprintf(output, "c");
914: break;
915: case XML_DOCUMENT_NODE:
916: fprintf(output, "d");
917: break;
918: case XML_HTML_DOCUMENT_NODE:
919: fprintf(output, "h");
920: break;
921: case XML_DOCUMENT_TYPE_NODE:
922: fprintf(output, "T");
923: break;
924: case XML_DOCUMENT_FRAG_NODE:
925: fprintf(output, "F");
926: break;
927: case XML_NOTATION_NODE:
928: fprintf(output, "N");
929: break;
930: default:
931: fprintf(output, "?");
932: }
933: if (node->properties != NULL)
934: fprintf(output, "a");
935: else
936: fprintf(output, "-");
937: if (node->nsDef != NULL)
938: fprintf(output, "n");
939: else
940: fprintf(output, "-");
941:
942: fprintf(output, " %8d ", xmlLsCountNode(node));
943:
944: switch (node->type) {
945: case XML_ELEMENT_NODE:
946: if (node->name != NULL)
947: fprintf(output, "%s", node->name);
948: break;
949: case XML_ATTRIBUTE_NODE:
950: if (node->name != NULL)
951: fprintf(output, "%s", node->name);
952: break;
953: case XML_TEXT_NODE:
954: if (node->content != NULL) {
955: #ifndef XML_USE_BUFFER_CONTENT
956: xmlDebugDumpString(output, node->content);
957: #else
958: xmlDebugDumpString(output, xmlBufferContent(node->content));
959: #endif
960: }
961: break;
962: case XML_CDATA_SECTION_NODE:
963: break;
964: case XML_ENTITY_REF_NODE:
965: if (node->name != NULL)
966: fprintf(output, "%s", node->name);
967: break;
968: case XML_ENTITY_NODE:
969: if (node->name != NULL)
970: fprintf(output, "%s", node->name);
971: break;
972: case XML_PI_NODE:
973: if (node->name != NULL)
974: fprintf(output, "%s", node->name);
975: break;
976: case XML_COMMENT_NODE:
977: break;
978: case XML_DOCUMENT_NODE:
979: break;
980: case XML_HTML_DOCUMENT_NODE:
981: break;
982: case XML_DOCUMENT_TYPE_NODE:
983: break;
984: case XML_DOCUMENT_FRAG_NODE:
985: break;
986: case XML_NOTATION_NODE:
987: break;
988: default:
989: if (node->name != NULL)
990: fprintf(output, "%s", node->name);
991: }
992: fprintf(output, "\n");
993: }
994:
995: /****************************************************************
996: * *
997: * The XML shell related functions *
998: * *
999: ****************************************************************/
1000:
1001: /*
1002: * TODO: Improvement/cleanups for the XML shell
1003: * - allow to shell out an editor on a subpart
1004: * - cleanup function registrations (with help) and calling
1005: * - provide registration routines
1006: */
1007:
1008: /**
1009: * xmlShellList:
1010: * @ctxt: the shell context
1011: * @arg: unused
1012: * @node: a node
1013: * @node2: unused
1014: *
1015: * Implements the XML shell function "ls"
1016: * Does an Unix like listing of the given node (like a directory)
1017: *
1018: * Returns 0
1019: */
1020: int
1021: xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1022: xmlNodePtr node2) {
1023: xmlNodePtr cur;
1024:
1025: if ((node->type == XML_DOCUMENT_NODE) ||
1026: (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16 daniel 1027: cur = ((xmlDocPtr) node)->children;
1028: } else if (node->children != NULL) {
1029: cur = node->children;
1.12 daniel 1030: } else {
1031: xmlLsOneNode(stdout, node);
1032: return(0);
1033: }
1034: while (cur != NULL) {
1035: xmlLsOneNode(stdout, cur);
1036: cur = cur->next;
1037: }
1038: return(0);
1039: }
1040:
1041: /**
1042: * xmlShellDir:
1043: * @ctxt: the shell context
1044: * @arg: unused
1045: * @node: a node
1046: * @node2: unused
1047: *
1048: * Implements the XML shell function "dir"
1049: * dumps informations about the node (namespace, attributes, content).
1050: *
1051: * Returns 0
1052: */
1053: int
1054: xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1055: xmlNodePtr node2) {
1056: if ((node->type == XML_DOCUMENT_NODE) ||
1057: (node->type == XML_HTML_DOCUMENT_NODE)) {
1058: xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
1059: } else if (node->type == XML_ATTRIBUTE_NODE) {
1060: xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
1061: } else {
1062: xmlDebugDumpOneNode(stdout, node, 0);
1063: }
1064: return(0);
1065: }
1066:
1067: /**
1068: * xmlShellCat:
1069: * @ctxt: the shell context
1070: * @arg: unused
1071: * @node: a node
1072: * @node2: unused
1073: *
1074: * Implements the XML shell function "cat"
1075: * dumps the serialization node content (XML or HTML).
1076: *
1077: * Returns 0
1078: */
1079: int
1080: xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1081: xmlNodePtr node2) {
1.13 daniel 1082: if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1.23 daniel 1083: #ifdef LIBXML_HTML_ENABLED
1.13 daniel 1084: if (node->type == XML_HTML_DOCUMENT_NODE)
1085: htmlDocDump(stdout, (htmlDocPtr) node);
1086: else
1.14 daniel 1087: htmlNodeDumpFile(stdout, ctxt->doc, node);
1.23 daniel 1088: #else
1089: if (node->type == XML_DOCUMENT_NODE)
1090: xmlDocDump(stdout, (xmlDocPtr) node);
1091: else
1092: xmlElemDump(stdout, ctxt->doc, node);
1093: #endif /* LIBXML_HTML_ENABLED */
1.13 daniel 1094: } else {
1095: if (node->type == XML_DOCUMENT_NODE)
1096: xmlDocDump(stdout, (xmlDocPtr) node);
1097: else
1098: xmlElemDump(stdout, ctxt->doc, node);
1099: }
1.12 daniel 1100: printf("\n");
1101: return(0);
1102: }
1103:
1104: /**
1105: * xmlShellLoad:
1106: * @ctxt: the shell context
1107: * @filename: the file name
1108: * @node: unused
1109: * @node2: unused
1110: *
1111: * Implements the XML shell function "load"
1112: * loads a new document specified by the filename
1113: *
1114: * Returns 0 or -1 if loading failed
1115: */
1116: int
1117: xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1118: xmlNodePtr node2) {
1119: xmlDocPtr doc;
1120: int html = 0;
1121:
1122: if (ctxt->doc != NULL)
1123: html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
1124:
1125: if (html) {
1.23 daniel 1126: #ifdef LIBXML_HTML_ENABLED
1.12 daniel 1127: doc = htmlParseFile(filename, NULL);
1.23 daniel 1128: #else
1129: printf("HTML support not compiled in\n");
1130: doc = NULL;
1131: #endif /* LIBXML_HTML_ENABLED */
1.12 daniel 1132: } else {
1133: doc = xmlParseFile(filename);
1134: }
1135: if (doc != NULL) {
1136: if (ctxt->loaded == 1) {
1137: xmlFreeDoc(ctxt->doc);
1138: }
1139: ctxt->loaded = 1;
1.23 daniel 1140: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1141: xmlXPathFreeContext(ctxt->pctxt);
1.23 daniel 1142: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1143: xmlFree(ctxt->filename);
1144: ctxt->doc = doc;
1145: ctxt->node = (xmlNodePtr) doc;
1.23 daniel 1146: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1147: ctxt->pctxt = xmlXPathNewContext(doc);
1.23 daniel 1148: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1149: ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1150: } else
1151: return(-1);
1152: return(0);
1153: }
1154:
1155: /**
1156: * xmlShellWrite:
1157: * @ctxt: the shell context
1158: * @filename: the file name
1159: * @node: a node in the tree
1160: * @node2: unused
1161: *
1162: * Implements the XML shell function "write"
1163: * Write the current node to the filename, it saves the serailization
1164: * of the subtree under the @node specified
1165: *
1166: * Returns 0 or -1 in case of error
1167: */
1168: int
1169: xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1170: xmlNodePtr node2) {
1171: if (node == NULL)
1172: return(-1);
1173: if ((filename == NULL) || (filename[0] == 0)) {
1174: fprintf(stderr, "Write command requires a filename argument\n");
1175: return(-1);
1176: }
1177: #ifdef W_OK
1178: if (access((char *) filename, W_OK)) {
1179: fprintf(stderr, "Cannot write to %s\n", filename);
1180: return(-1);
1181: }
1182: #endif
1183: switch(node->type) {
1184: case XML_DOCUMENT_NODE:
1185: if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1186: fprintf(stderr, "Failed to write to %s\n", filename);
1187: return(-1);
1188: }
1189: break;
1190: case XML_HTML_DOCUMENT_NODE:
1.23 daniel 1191: #ifdef LIBXML_HTML_ENABLED
1.12 daniel 1192: if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1193: fprintf(stderr, "Failed to write to %s\n", filename);
1194: return(-1);
1195: }
1.23 daniel 1196: #else
1197: if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1198: fprintf(stderr, "Failed to write to %s\n", filename);
1199: return(-1);
1200: }
1201: #endif /* LIBXML_HTML_ENABLED */
1.12 daniel 1202: break;
1203: default: {
1204: FILE *f;
1205:
1206: f = fopen((char *) filename, "w");
1207: if (f == NULL) {
1208: fprintf(stderr, "Failed to write to %s\n", filename);
1209: return(-1);
1210: }
1211: xmlElemDump(f, ctxt->doc, node);
1212: fclose(f);
1213: }
1214: }
1215: return(0);
1216: }
1217:
1218: /**
1219: * xmlShellSave:
1220: * @ctxt: the shell context
1221: * @filename: the file name (optionnal)
1222: * @node: unused
1223: * @node2: unused
1224: *
1225: * Implements the XML shell function "save"
1226: * Write the current document to the filename, or it's original name
1227: *
1228: * Returns 0 or -1 in case of error
1229: */
1230: int
1231: xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1232: xmlNodePtr node2) {
1233: if (ctxt->doc == NULL)
1234: return(-1);
1235: if ((filename == NULL) || (filename[0] == 0))
1236: filename = ctxt->filename;
1237: #ifdef W_OK
1238: if (access((char *) filename, W_OK)) {
1239: fprintf(stderr, "Cannot save to %s\n", filename);
1240: return(-1);
1241: }
1242: #endif
1243: switch(ctxt->doc->type) {
1244: case XML_DOCUMENT_NODE:
1245: if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1246: fprintf(stderr, "Failed to save to %s\n", filename);
1247: }
1248: break;
1249: case XML_HTML_DOCUMENT_NODE:
1.23 daniel 1250: #ifdef LIBXML_HTML_ENABLED
1.12 daniel 1251: if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1252: fprintf(stderr, "Failed to save to %s\n", filename);
1253: }
1.23 daniel 1254: #else
1255: if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1256: fprintf(stderr, "Failed to save to %s\n", filename);
1257: }
1258: #endif /* LIBXML_HTML_ENABLED */
1.12 daniel 1259: break;
1260: default:
1261: fprintf(stderr,
1262: "To save to subparts of a document use the 'write' command\n");
1263: return(-1);
1264:
1265: }
1266: return(0);
1267: }
1268:
1269: /**
1270: * xmlShellValidate:
1271: * @ctxt: the shell context
1272: * @dtd: the DTD URI (optionnal)
1273: * @node: unused
1274: * @node2: unused
1275: *
1276: * Implements the XML shell function "validate"
1277: * Validate the document, if a DTD path is provided, then the validation
1278: * is done against the given DTD.
1279: *
1280: * Returns 0 or -1 in case of error
1281: */
1282: int
1283: xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
1284: xmlNodePtr node2) {
1285: xmlValidCtxt vctxt;
1286: int res = -1;
1287:
1288: vctxt.userData = stderr;
1289: vctxt.error = (xmlValidityErrorFunc) fprintf;
1290: vctxt.warning = (xmlValidityWarningFunc) fprintf;
1291:
1292: if ((dtd == NULL) || (dtd[0] == 0)) {
1293: res = xmlValidateDocument(&vctxt, ctxt->doc);
1294: } else {
1295: xmlDtdPtr subset;
1296:
1297: subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1298: if (subset != NULL) {
1299: res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1300:
1301: xmlFreeDtd(subset);
1302: }
1303: }
1304: return(res);
1305: }
1306:
1307: /**
1308: * xmlShellDu:
1309: * @ctxt: the shell context
1310: * @arg: unused
1311: * @tree: a node defining a subtree
1312: * @node2: unused
1313: *
1314: * Implements the XML shell function "du"
1315: * show the structure of the subtree under node @tree
1316: * If @tree is null, the command works on the current node.
1317: *
1318: * Returns 0 or -1 in case of error
1319: */
1320: int
1321: xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
1322: xmlNodePtr node2) {
1323: xmlNodePtr node;
1324: int indent = 0,i;
1325:
1326: if (tree == NULL) return(-1);
1327: node = tree;
1328: while (node != NULL) {
1329: if ((node->type == XML_DOCUMENT_NODE) ||
1330: (node->type == XML_HTML_DOCUMENT_NODE)) {
1331: printf("/\n");
1332: } else if (node->type == XML_ELEMENT_NODE) {
1333: for (i = 0;i < indent;i++)
1334: printf(" ");
1335: printf("%s\n", node->name);
1336: } else {
1337: }
1338:
1339: /*
1340: * Browse the full subtree, deep first
1341: */
1342:
1343: if ((node->type == XML_DOCUMENT_NODE) ||
1344: (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16 daniel 1345: node = ((xmlDocPtr) node)->children;
1.25 daniel 1346: } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1.12 daniel 1347: /* deep first */
1.16 daniel 1348: node = node->children;
1.12 daniel 1349: indent++;
1350: } else if ((node != tree) && (node->next != NULL)) {
1351: /* then siblings */
1352: node = node->next;
1353: } else if (node != tree) {
1354: /* go up to parents->next if needed */
1355: while (node != tree) {
1356: if (node->parent != NULL) {
1357: node = node->parent;
1358: indent--;
1359: }
1360: if ((node != tree) && (node->next != NULL)) {
1361: node = node->next;
1362: break;
1363: }
1364: if (node->parent == NULL) {
1365: node = NULL;
1366: break;
1367: }
1368: if (node == tree) {
1369: node = NULL;
1370: break;
1371: }
1372: }
1373: /* exit condition */
1374: if (node == tree)
1375: node = NULL;
1376: } else
1377: node = NULL;
1378: }
1379: return(0);
1380: }
1381:
1382: /**
1383: * xmlShellPwd:
1384: * @ctxt: the shell context
1385: * @buffer: the output buffer
1386: * @tree: a node
1387: * @node2: unused
1388: *
1389: * Implements the XML shell function "pwd"
1390: * Show the full path from the root to the node, if needed building
1391: * thumblers when similar elements exists at a given ancestor level.
1392: * The output is compatible with XPath commands.
1393: *
1394: * Returns 0 or -1 in case of error
1395: */
1396: int
1397: xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
1398: xmlNodePtr node2) {
1399: xmlNodePtr cur, tmp, next;
1400: char buf[500];
1401: char sep;
1402: const char *name;
1403: int occur = 0;
1404:
1405: buffer[0] = 0;
1406: if (node == NULL) return(-1);
1407: cur = node;
1408: do {
1409: name = "";
1410: sep= '?';
1411: occur = 0;
1412: if ((cur->type == XML_DOCUMENT_NODE) ||
1413: (cur->type == XML_HTML_DOCUMENT_NODE)) {
1414: sep = '/';
1415: next = NULL;
1416: } else if (cur->type == XML_ELEMENT_NODE) {
1417: sep = '/';
1418: name = (const char *)cur->name;
1419: next = cur->parent;
1420:
1421: /*
1422: * Thumbler index computation
1423: */
1424: tmp = cur->prev;
1425: while (tmp != NULL) {
1426: if (!xmlStrcmp(cur->name, tmp->name))
1427: occur++;
1428: tmp = tmp->prev;
1429: }
1430: if (occur == 0) {
1431: tmp = cur->next;
1432: while (tmp != NULL) {
1433: if (!xmlStrcmp(cur->name, tmp->name))
1434: occur++;
1435: tmp = tmp->next;
1436: }
1437: if (occur != 0) occur = 1;
1438: } else
1439: occur++;
1440: } else if (cur->type == XML_ATTRIBUTE_NODE) {
1441: sep = '@';
1442: name = (const char *) (((xmlAttrPtr) cur)->name);
1.16 daniel 1443: next = ((xmlAttrPtr) cur)->parent;
1.12 daniel 1444: } else {
1445: next = cur->parent;
1446: }
1447: if (occur == 0)
1448: sprintf(buf, "%c%s%s", sep, name, buffer);
1449: else
1450: sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
1451: strcpy(buffer, buf);
1452: cur = next;
1453: } while (cur != NULL);
1454: return(0);
1455: }
1456:
1457: /**
1458: * xmlShell
1459: * @doc: the initial document
1460: * @filename: the output buffer
1461: * @input: the line reading function
1462: * @output: the output FILE*
1463: *
1464: * Implements the XML shell
1465: * This allow to load, validate, view, modify and save a document
1466: * using a environment similar to a UNIX commandline.
1467: */
1468: void
1469: xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1470: FILE *output) {
1471: char prompt[500] = "/ > ";
1472: char *cmdline = NULL;
1473: int nbargs;
1474: char command[100];
1475: char arg[400];
1476: xmlShellCtxtPtr ctxt;
1477: xmlXPathObjectPtr list;
1478:
1479: if (doc == NULL)
1480: return;
1481: if (filename == NULL)
1482: return;
1483: if (input == NULL)
1484: return;
1485: if (output == NULL)
1486: return;
1487: ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1488: if (ctxt == NULL)
1489: return;
1490: ctxt->loaded = 0;
1491: ctxt->doc = doc;
1492: ctxt->input = input;
1493: ctxt->output = output;
1494: ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1495: ctxt->node = (xmlNodePtr) ctxt->doc;
1496:
1.23 daniel 1497: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1498: ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1499: if (ctxt->pctxt == NULL) {
1500: xmlFree(ctxt);
1501: return;
1502: }
1.23 daniel 1503: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1504: while (1) {
1505: if (ctxt->node == (xmlNodePtr) ctxt->doc)
1506: sprintf(prompt, "%s > ", "/");
1507: else if (ctxt->node->name)
1508: sprintf(prompt, "%s > ", ctxt->node->name);
1509: else
1510: sprintf(prompt, "? > ");
1511:
1512: cmdline = ctxt->input(prompt);
1513: if (cmdline == NULL) break;
1514:
1515: command[0] = 0;
1516: arg[0] = 0;
1517: nbargs = sscanf(cmdline, "%s %s", command, arg);
1518:
1519: if (command[0] == 0) continue;
1520: if (!strcmp(command, "exit"))
1521: break;
1522: if (!strcmp(command, "quit"))
1523: break;
1524: if (!strcmp(command, "bye"))
1525: break;
1526: if (!strcmp(command, "validate")) {
1527: xmlShellValidate(ctxt, arg, NULL, NULL);
1528: } else if (!strcmp(command, "load")) {
1529: xmlShellLoad(ctxt, arg, NULL, NULL);
1530: } else if (!strcmp(command, "save")) {
1531: xmlShellSave(ctxt, arg, NULL, NULL);
1532: } else if (!strcmp(command, "write")) {
1533: xmlShellWrite(ctxt, arg, NULL, NULL);
1534: } else if (!strcmp(command, "free")) {
1535: if (arg[0] == 0) {
1536: xmlMemShow(stdout, 0);
1537: } else {
1538: int len = 0;
1539: sscanf(arg, "%d", &len);
1540: xmlMemShow(stdout, len);
1541: }
1542: } else if (!strcmp(command, "pwd")) {
1543: char dir[500];
1544: if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
1545: printf("%s\n", dir);
1546: } else if (!strcmp(command, "du")) {
1547: xmlShellDu(ctxt, NULL, ctxt->node, NULL);
1548: } else if ((!strcmp(command, "ls")) ||
1549: (!strcmp(command, "dir"))) {
1550: int dir = (!strcmp(command, "dir"));
1551: if (arg[0] == 0) {
1552: if (dir)
1553: xmlShellDir(ctxt, NULL, ctxt->node, NULL);
1554: else
1555: xmlShellList(ctxt, NULL, ctxt->node, NULL);
1556: } else {
1557: ctxt->pctxt->node = ctxt->node;
1.23 daniel 1558: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1559: if (ctxt->pctxt->nodelist != NULL)
1560: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1561: ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1562: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23 daniel 1563: #else
1564: list = NULL;
1565: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1566: if (list != NULL) {
1567: switch (list->type) {
1568: case XPATH_UNDEFINED:
1569: fprintf(stderr, "%s: no such node\n", arg);
1570: break;
1571: case XPATH_NODESET: {
1572: int i;
1573:
1574: for (i = 0;i < list->nodesetval->nodeNr;i++) {
1575: if (dir)
1576: xmlShellDir(ctxt, NULL,
1577: list->nodesetval->nodeTab[i], NULL);
1578: else
1579: xmlShellList(ctxt, NULL,
1580: list->nodesetval->nodeTab[i], NULL);
1581: }
1582: break;
1583: }
1584: case XPATH_BOOLEAN:
1585: fprintf(stderr, "%s is a Boolean\n", arg);
1586: break;
1587: case XPATH_NUMBER:
1588: fprintf(stderr, "%s is a number\n", arg);
1589: break;
1590: case XPATH_STRING:
1591: fprintf(stderr, "%s is a string\n", arg);
1592: break;
1593: }
1594: xmlXPathFreeNodeSetList(list);
1595: } else {
1596: fprintf(stderr, "%s: no such node\n", arg);
1597: }
1.23 daniel 1598: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1599: if (ctxt->pctxt->nodelist != NULL)
1600: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1.23 daniel 1601: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1602: ctxt->pctxt->nodelist = NULL;
1603: }
1604: } else if (!strcmp(command, "cd")) {
1605: if (arg[0] == 0) {
1606: ctxt->node = (xmlNodePtr) ctxt->doc;
1607: } else {
1608: ctxt->pctxt->node = ctxt->node;
1.23 daniel 1609: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1610: if (ctxt->pctxt->nodelist != NULL)
1611: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1612: ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1613: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23 daniel 1614: #else
1615: list = NULL;
1616: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1617: if (list != NULL) {
1618: switch (list->type) {
1619: case XPATH_UNDEFINED:
1620: fprintf(stderr, "%s: no such node\n", arg);
1621: break;
1622: case XPATH_NODESET:
1623: if (list->nodesetval->nodeNr == 1) {
1624: ctxt->node = list->nodesetval->nodeTab[0];
1625: } else
1626: fprintf(stderr, "%s is a %d Node Set\n",
1627: arg, list->nodesetval->nodeNr);
1628: break;
1629: case XPATH_BOOLEAN:
1630: fprintf(stderr, "%s is a Boolean\n", arg);
1631: break;
1632: case XPATH_NUMBER:
1633: fprintf(stderr, "%s is a number\n", arg);
1634: break;
1635: case XPATH_STRING:
1636: fprintf(stderr, "%s is a string\n", arg);
1637: break;
1638: }
1639: xmlXPathFreeNodeSetList(list);
1640: } else {
1641: fprintf(stderr, "%s: no such node\n", arg);
1642: }
1.23 daniel 1643: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1644: if (ctxt->pctxt->nodelist != NULL)
1645: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1.23 daniel 1646: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1647: ctxt->pctxt->nodelist = NULL;
1648: }
1649: } else if (!strcmp(command, "cat")) {
1650: if (arg[0] == 0) {
1651: xmlShellCat(ctxt, NULL, ctxt->node, NULL);
1652: } else {
1653: ctxt->pctxt->node = ctxt->node;
1.23 daniel 1654: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1655: if (ctxt->pctxt->nodelist != NULL)
1656: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1657: ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1658: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23 daniel 1659: #else
1660: list = NULL;
1661: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1662: if (list != NULL) {
1663: switch (list->type) {
1664: case XPATH_UNDEFINED:
1665: fprintf(stderr, "%s: no such node\n", arg);
1666: break;
1667: case XPATH_NODESET: {
1668: int i;
1669:
1670: for (i = 0;i < list->nodesetval->nodeNr;i++) {
1671: if (i > 0) printf(" -------\n");
1672: xmlShellCat(ctxt, NULL,
1673: list->nodesetval->nodeTab[i], NULL);
1674: }
1675: break;
1676: }
1677: case XPATH_BOOLEAN:
1678: fprintf(stderr, "%s is a Boolean\n", arg);
1679: break;
1680: case XPATH_NUMBER:
1681: fprintf(stderr, "%s is a number\n", arg);
1682: break;
1683: case XPATH_STRING:
1684: fprintf(stderr, "%s is a string\n", arg);
1685: break;
1686: }
1687: xmlXPathFreeNodeSetList(list);
1688: } else {
1689: fprintf(stderr, "%s: no such node\n", arg);
1690: }
1.23 daniel 1691: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1692: if (ctxt->pctxt->nodelist != NULL)
1693: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1.23 daniel 1694: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1695: ctxt->pctxt->nodelist = NULL;
1696: }
1697: } else {
1698: fprintf(stderr, "Unknown command %s\n", command);
1699: }
1700: free(cmdline); /* not xmlFree here ! */
1701: }
1.23 daniel 1702: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1703: xmlXPathFreeContext(ctxt->pctxt);
1.23 daniel 1704: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1705: if (ctxt->loaded) {
1706: xmlFreeDoc(ctxt->doc);
1707: }
1708: xmlFree(ctxt);
1709: if (cmdline != NULL)
1710: free(cmdline); /* not xmlFree here ! */
1711: }
1712:
1.23 daniel 1713: #endif /* LIBXML_DEBUG_ENABLED */
Webmaster