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