Annotation of XML/debugXML.c, revision 1.37
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) {
587: fprintf(output, shift);
588: fprintf(output, "content=");
1.8 daniel 589: #ifndef XML_USE_BUFFER_CONTENT
1.1 daniel 590: xmlDebugDumpString(output, node->content);
1.8 daniel 591: #else
592: xmlDebugDumpString(output, xmlBufferContent(node->content));
593: #endif
1.1 daniel 594: fprintf(output, "\n");
595: }
596: } else {
597: xmlEntityPtr ent;
598: ent = xmlGetDocEntity(node->doc, node->name);
599: if (ent != NULL)
600: xmlDebugDumpEntity(output, ent, depth + 1);
1.18 daniel 601: }
602: /*
603: * Do a bit of checking
604: */
605: if (node->parent == NULL)
606: fprintf(output, "PBM: Node has no parent\n");
607: if (node->doc == NULL)
608: fprintf(output, "PBM: Node has no doc\n");
609: if ((node->parent != NULL) && (node->doc != node->parent->doc))
610: fprintf(output, "PBM: Node doc differs from parent's one\n");
611: if (node->prev == NULL) {
612: if ((node->parent != NULL) && (node->parent->children != node))
613: fprintf(output, "PBM: Node has no prev and not first of list\n");
614: } else {
615: if (node->prev->next != node)
616: fprintf(output, "PBM: Node prev->next : back link wrong\n");
617: }
618: if (node->next == NULL) {
619: if ((node->parent != NULL) && (node->parent->last != node))
620: fprintf(output, "PBM: Node has no next and not last of list\n");
621: } else {
622: if (node->next->prev != node)
623: fprintf(output, "PBM: Node next->prev : forward link wrong\n");
1.1 daniel 624: }
1.3 daniel 625: }
626:
627: void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
628: xmlDebugDumpOneNode(output, node, depth);
1.32 veillard 629: if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
1.16 daniel 630: xmlDebugDumpNodeList(output, node->children, depth + 1);
1.1 daniel 631: }
632:
633: void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
634: while (node != NULL) {
635: xmlDebugDumpNode(output, node, depth);
636: node = node->next;
637: }
638: }
639:
640:
1.12 daniel 641: void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
1.1 daniel 642: if (output == NULL) output = stdout;
643: if (doc == NULL) {
644: fprintf(output, "DOCUMENT == NULL !\n");
645: return;
646: }
647:
648: switch (doc->type) {
649: case XML_ELEMENT_NODE:
650: fprintf(output, "Error, ELEMENT found here ");
651: break;
652: case XML_ATTRIBUTE_NODE:
653: fprintf(output, "Error, ATTRIBUTE found here\n");
654: break;
655: case XML_TEXT_NODE:
656: fprintf(output, "Error, TEXT\n");
657: break;
658: case XML_CDATA_SECTION_NODE:
659: fprintf(output, "Error, CDATA_SECTION\n");
660: break;
661: case XML_ENTITY_REF_NODE:
662: fprintf(output, "Error, ENTITY_REF\n");
663: break;
664: case XML_ENTITY_NODE:
665: fprintf(output, "Error, ENTITY\n");
666: break;
667: case XML_PI_NODE:
668: fprintf(output, "Error, PI\n");
669: break;
670: case XML_COMMENT_NODE:
671: fprintf(output, "Error, COMMENT\n");
672: break;
673: case XML_DOCUMENT_NODE:
674: fprintf(output, "DOCUMENT\n");
1.7 daniel 675: break;
676: case XML_HTML_DOCUMENT_NODE:
677: fprintf(output, "HTML DOCUMENT\n");
1.1 daniel 678: break;
679: case XML_DOCUMENT_TYPE_NODE:
680: fprintf(output, "Error, DOCUMENT_TYPE\n");
681: break;
682: case XML_DOCUMENT_FRAG_NODE:
683: fprintf(output, "Error, DOCUMENT_FRAG\n");
684: break;
685: case XML_NOTATION_NODE:
686: fprintf(output, "Error, NOTATION\n");
687: break;
688: default:
689: fprintf(output, "NODE_%d\n", doc->type);
690: }
691: if (doc->name != NULL) {
692: fprintf(output, "name=");
1.5 daniel 693: xmlDebugDumpString(output, BAD_CAST doc->name);
1.1 daniel 694: fprintf(output, "\n");
695: }
696: if (doc->version != NULL) {
697: fprintf(output, "version=");
698: xmlDebugDumpString(output, doc->version);
699: fprintf(output, "\n");
700: }
701: if (doc->encoding != NULL) {
702: fprintf(output, "encoding=");
703: xmlDebugDumpString(output, doc->encoding);
1.32 veillard 704: fprintf(output, "\n");
705: }
706: if (doc->URL != NULL) {
707: fprintf(output, "URL=");
708: xmlDebugDumpString(output, doc->URL);
1.1 daniel 709: fprintf(output, "\n");
710: }
711: if (doc->standalone)
712: fprintf(output, "standalone=true\n");
713: if (doc->oldNs != NULL)
714: xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
1.12 daniel 715: }
716:
717: void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
718: if (output == NULL) output = stdout;
719: if (doc == NULL) {
720: fprintf(output, "DOCUMENT == NULL !\n");
721: return;
722: }
723: xmlDebugDumpDocumentHead(output, doc);
724: if (((doc->type == XML_DOCUMENT_NODE) ||
725: (doc->type == XML_HTML_DOCUMENT_NODE)) &&
1.16 daniel 726: (doc->children != NULL))
727: xmlDebugDumpNodeList(output, doc->children, 1);
1.12 daniel 728: }
1.30 veillard 729:
730: void xmlDebugDumpDTD(FILE *output, xmlDtdPtr dtd) {
731: if (dtd == NULL)
732: return;
733: if (dtd->type != XML_DTD_NODE) {
734: fprintf(output, "PBM: not a DTD\n");
735: return;
736: }
737: if (dtd->name != NULL)
738: fprintf(output, "DTD(%s)", dtd->name);
739: else
740: fprintf(output, "DTD");
741: if (dtd->ExternalID != NULL)
742: fprintf(output, ", PUBLIC %s", dtd->ExternalID);
743: if (dtd->SystemID != NULL)
744: fprintf(output, ", SYSTEM %s", dtd->SystemID);
745: fprintf(output, "\n");
746: /*
747: * Do a bit of checking
748: */
749: if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
750: fprintf(output, "PBM: Dtd doc differs from parent's one\n");
751: if (dtd->prev == NULL) {
752: if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
753: fprintf(output, "PBM: Dtd has no prev and not first of list\n");
754: } else {
755: if (dtd->prev->next != (xmlNodePtr) dtd)
756: fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
757: }
758: if (dtd->next == NULL) {
759: if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
760: fprintf(output, "PBM: Dtd has no next and not last of list\n");
761: } else {
762: if (dtd->next->prev != (xmlNodePtr) dtd)
763: fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
764: }
765: if (dtd->children == NULL)
766: fprintf(output, " DTD is empty\n");
767: else
768: xmlDebugDumpNodeList(output, dtd->children, 1);
769: }
1.9 daniel 770:
771: void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
772: int i;
773: xmlEntityPtr cur;
774:
775: if (output == NULL) output = stdout;
776: if (doc == NULL) {
777: fprintf(output, "DOCUMENT == NULL !\n");
778: return;
779: }
780:
781: switch (doc->type) {
782: case XML_ELEMENT_NODE:
783: fprintf(output, "Error, ELEMENT found here ");
784: break;
785: case XML_ATTRIBUTE_NODE:
786: fprintf(output, "Error, ATTRIBUTE found here\n");
787: break;
788: case XML_TEXT_NODE:
789: fprintf(output, "Error, TEXT\n");
790: break;
791: case XML_CDATA_SECTION_NODE:
792: fprintf(output, "Error, CDATA_SECTION\n");
793: break;
794: case XML_ENTITY_REF_NODE:
795: fprintf(output, "Error, ENTITY_REF\n");
796: break;
797: case XML_ENTITY_NODE:
798: fprintf(output, "Error, ENTITY\n");
799: break;
800: case XML_PI_NODE:
801: fprintf(output, "Error, PI\n");
802: break;
803: case XML_COMMENT_NODE:
804: fprintf(output, "Error, COMMENT\n");
805: break;
806: case XML_DOCUMENT_NODE:
807: fprintf(output, "DOCUMENT\n");
808: break;
809: case XML_HTML_DOCUMENT_NODE:
810: fprintf(output, "HTML DOCUMENT\n");
811: break;
812: case XML_DOCUMENT_TYPE_NODE:
813: fprintf(output, "Error, DOCUMENT_TYPE\n");
814: break;
815: case XML_DOCUMENT_FRAG_NODE:
816: fprintf(output, "Error, DOCUMENT_FRAG\n");
817: break;
818: case XML_NOTATION_NODE:
819: fprintf(output, "Error, NOTATION\n");
820: break;
821: default:
822: fprintf(output, "NODE_%d\n", doc->type);
823: }
824: if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
825: xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
826: doc->intSubset->entities;
827: fprintf(output, "Entities in internal subset\n");
1.28 veillard 828: for (i = 0;i < table->max_entities;i++) {
1.20 daniel 829: cur = table->table[i];
1.28 veillard 830: while (cur != NULL) {
831: fprintf(output, "%d : %s : ", i, cur->name);
832: switch (cur->etype) {
833: case XML_INTERNAL_GENERAL_ENTITY:
834: fprintf(output, "INTERNAL GENERAL, ");
835: break;
836: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
837: fprintf(output, "EXTERNAL PARSED, ");
838: break;
839: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
840: fprintf(output, "EXTERNAL UNPARSED, ");
841: break;
842: case XML_INTERNAL_PARAMETER_ENTITY:
843: fprintf(output, "INTERNAL PARAMETER, ");
844: break;
845: case XML_EXTERNAL_PARAMETER_ENTITY:
846: fprintf(output, "EXTERNAL PARAMETER, ");
847: break;
848: default:
849: fprintf(output, "UNKNOWN TYPE %d",
850: cur->etype);
851: }
852: if (cur->ExternalID != NULL)
853: fprintf(output, "ID \"%s\"", cur->ExternalID);
854: if (cur->SystemID != NULL)
855: fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
856: if (cur->orig != NULL)
857: fprintf(output, "\n orig \"%s\"", cur->orig);
858: if (cur->content != NULL)
859: fprintf(output, "\n content \"%s\"", cur->content);
860: fprintf(output, "\n");
861: cur = cur->nexte;
1.9 daniel 862: }
863: }
864: } else
865: fprintf(output, "No entities in internal subset\n");
866: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
867: xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
868: doc->extSubset->entities;
869: fprintf(output, "Entities in external subset\n");
1.28 veillard 870: for (i = 0;i < table->max_entities;i++) {
1.20 daniel 871: cur = table->table[i];
1.28 veillard 872: while (cur != NULL) {
873: fprintf(output, "%d : %s : ", i, cur->name);
874: switch (cur->etype) {
875: case XML_INTERNAL_GENERAL_ENTITY:
876: fprintf(output, "INTERNAL GENERAL, ");
877: break;
878: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
879: fprintf(output, "EXTERNAL PARSED, ");
880: break;
881: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
882: fprintf(output, "EXTERNAL UNPARSED, ");
883: break;
884: case XML_INTERNAL_PARAMETER_ENTITY:
885: fprintf(output, "INTERNAL PARAMETER, ");
886: break;
887: case XML_EXTERNAL_PARAMETER_ENTITY:
888: fprintf(output, "EXTERNAL PARAMETER, ");
889: break;
890: default:
891: fprintf(output, "UNKNOWN TYPE %d",
892: cur->etype);
893: }
894: if (cur->ExternalID != NULL)
895: fprintf(output, "ID \"%s\"", cur->ExternalID);
896: if (cur->SystemID != NULL)
897: fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
898: if (cur->orig != NULL)
899: fprintf(output, "\n orig \"%s\"", cur->orig);
900: if (cur->content != NULL)
901: fprintf(output, "\n content \"%s\"", cur->content);
902: fprintf(output, "\n");
903: cur = cur->nexte;
1.9 daniel 904: }
905: }
906: } else
907: fprintf(output, "No entities in external subset\n");
908: }
1.12 daniel 909:
910: static int xmlLsCountNode(xmlNodePtr node) {
911: int ret = 0;
912: xmlNodePtr list = NULL;
913:
914: switch (node->type) {
915: case XML_ELEMENT_NODE:
1.16 daniel 916: list = node->children;
1.12 daniel 917: break;
918: case XML_DOCUMENT_NODE:
919: case XML_HTML_DOCUMENT_NODE:
1.33 veillard 920: #ifdef LIBXML_SGML_ENABLED
921: case XML_SGML_DOCUMENT_NODE:
922: #endif
1.16 daniel 923: list = ((xmlDocPtr) node)->children;
1.12 daniel 924: break;
925: case XML_ATTRIBUTE_NODE:
1.16 daniel 926: list = ((xmlAttrPtr) node)->children;
1.12 daniel 927: break;
928: case XML_TEXT_NODE:
929: case XML_CDATA_SECTION_NODE:
930: case XML_PI_NODE:
931: case XML_COMMENT_NODE:
932: if (node->content != NULL) {
933: #ifndef XML_USE_BUFFER_CONTENT
934: ret = xmlStrlen(node->content);
935: #else
936: ret = xmlBufferLength(node->content);
937: #endif
938: }
939: break;
940: case XML_ENTITY_REF_NODE:
941: case XML_DOCUMENT_TYPE_NODE:
942: case XML_ENTITY_NODE:
943: case XML_DOCUMENT_FRAG_NODE:
944: case XML_NOTATION_NODE:
1.16 daniel 945: case XML_DTD_NODE:
1.17 daniel 946: case XML_ELEMENT_DECL:
947: case XML_ATTRIBUTE_DECL:
1.20 daniel 948: case XML_ENTITY_DECL:
1.12 daniel 949: ret = 1;
950: break;
951: }
952: for (;list != NULL;ret++)
953: list = list->next;
954: return(ret);
955: }
956:
957: void xmlLsOneNode(FILE *output, xmlNodePtr node) {
958: switch (node->type) {
959: case XML_ELEMENT_NODE:
960: fprintf(output, "-");
961: break;
962: case XML_ATTRIBUTE_NODE:
963: fprintf(output, "a");
964: break;
965: case XML_TEXT_NODE:
966: fprintf(output, "t");
967: break;
968: case XML_CDATA_SECTION_NODE:
969: fprintf(output, "c");
970: break;
971: case XML_ENTITY_REF_NODE:
972: fprintf(output, "e");
973: break;
974: case XML_ENTITY_NODE:
975: fprintf(output, "E");
976: break;
977: case XML_PI_NODE:
978: fprintf(output, "p");
979: break;
980: case XML_COMMENT_NODE:
981: fprintf(output, "c");
982: break;
983: case XML_DOCUMENT_NODE:
984: fprintf(output, "d");
985: break;
986: case XML_HTML_DOCUMENT_NODE:
987: fprintf(output, "h");
988: break;
989: case XML_DOCUMENT_TYPE_NODE:
990: fprintf(output, "T");
991: break;
992: case XML_DOCUMENT_FRAG_NODE:
993: fprintf(output, "F");
994: break;
995: case XML_NOTATION_NODE:
996: fprintf(output, "N");
997: break;
998: default:
999: fprintf(output, "?");
1000: }
1001: if (node->properties != NULL)
1002: fprintf(output, "a");
1003: else
1004: fprintf(output, "-");
1005: if (node->nsDef != NULL)
1006: fprintf(output, "n");
1007: else
1008: fprintf(output, "-");
1009:
1010: fprintf(output, " %8d ", xmlLsCountNode(node));
1011:
1012: switch (node->type) {
1013: case XML_ELEMENT_NODE:
1014: if (node->name != NULL)
1015: fprintf(output, "%s", node->name);
1016: break;
1017: case XML_ATTRIBUTE_NODE:
1018: if (node->name != NULL)
1019: fprintf(output, "%s", node->name);
1020: break;
1021: case XML_TEXT_NODE:
1022: if (node->content != NULL) {
1023: #ifndef XML_USE_BUFFER_CONTENT
1024: xmlDebugDumpString(output, node->content);
1025: #else
1026: xmlDebugDumpString(output, xmlBufferContent(node->content));
1027: #endif
1028: }
1029: break;
1030: case XML_CDATA_SECTION_NODE:
1031: break;
1032: case XML_ENTITY_REF_NODE:
1033: if (node->name != NULL)
1034: fprintf(output, "%s", node->name);
1035: break;
1036: case XML_ENTITY_NODE:
1037: if (node->name != NULL)
1038: fprintf(output, "%s", node->name);
1039: break;
1040: case XML_PI_NODE:
1041: if (node->name != NULL)
1042: fprintf(output, "%s", node->name);
1043: break;
1044: case XML_COMMENT_NODE:
1045: break;
1046: case XML_DOCUMENT_NODE:
1047: break;
1048: case XML_HTML_DOCUMENT_NODE:
1049: break;
1050: case XML_DOCUMENT_TYPE_NODE:
1051: break;
1052: case XML_DOCUMENT_FRAG_NODE:
1053: break;
1054: case XML_NOTATION_NODE:
1055: break;
1056: default:
1057: if (node->name != NULL)
1058: fprintf(output, "%s", node->name);
1059: }
1060: fprintf(output, "\n");
1061: }
1062:
1063: /****************************************************************
1064: * *
1065: * The XML shell related functions *
1066: * *
1067: ****************************************************************/
1068:
1069: /*
1070: * TODO: Improvement/cleanups for the XML shell
1071: * - allow to shell out an editor on a subpart
1072: * - cleanup function registrations (with help) and calling
1073: * - provide registration routines
1074: */
1075:
1076: /**
1077: * xmlShellList:
1078: * @ctxt: the shell context
1079: * @arg: unused
1080: * @node: a node
1081: * @node2: unused
1082: *
1083: * Implements the XML shell function "ls"
1084: * Does an Unix like listing of the given node (like a directory)
1085: *
1086: * Returns 0
1087: */
1088: int
1089: xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1090: xmlNodePtr node2) {
1091: xmlNodePtr cur;
1092:
1093: if ((node->type == XML_DOCUMENT_NODE) ||
1094: (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16 daniel 1095: cur = ((xmlDocPtr) node)->children;
1096: } else if (node->children != NULL) {
1097: cur = node->children;
1.12 daniel 1098: } else {
1099: xmlLsOneNode(stdout, node);
1100: return(0);
1101: }
1102: while (cur != NULL) {
1103: xmlLsOneNode(stdout, cur);
1104: cur = cur->next;
1105: }
1106: return(0);
1107: }
1108:
1109: /**
1110: * xmlShellDir:
1111: * @ctxt: the shell context
1112: * @arg: unused
1113: * @node: a node
1114: * @node2: unused
1115: *
1116: * Implements the XML shell function "dir"
1117: * dumps informations about the node (namespace, attributes, content).
1118: *
1119: * Returns 0
1120: */
1121: int
1122: xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1123: xmlNodePtr node2) {
1124: if ((node->type == XML_DOCUMENT_NODE) ||
1125: (node->type == XML_HTML_DOCUMENT_NODE)) {
1126: xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
1127: } else if (node->type == XML_ATTRIBUTE_NODE) {
1128: xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
1129: } else {
1130: xmlDebugDumpOneNode(stdout, node, 0);
1131: }
1132: return(0);
1133: }
1134:
1135: /**
1136: * xmlShellCat:
1137: * @ctxt: the shell context
1138: * @arg: unused
1139: * @node: a node
1140: * @node2: unused
1141: *
1142: * Implements the XML shell function "cat"
1143: * dumps the serialization node content (XML or HTML).
1144: *
1145: * Returns 0
1146: */
1147: int
1148: xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1149: xmlNodePtr node2) {
1.13 daniel 1150: if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1.23 daniel 1151: #ifdef LIBXML_HTML_ENABLED
1.13 daniel 1152: if (node->type == XML_HTML_DOCUMENT_NODE)
1153: htmlDocDump(stdout, (htmlDocPtr) node);
1154: else
1.14 daniel 1155: htmlNodeDumpFile(stdout, ctxt->doc, node);
1.23 daniel 1156: #else
1157: if (node->type == XML_DOCUMENT_NODE)
1158: xmlDocDump(stdout, (xmlDocPtr) node);
1159: else
1160: xmlElemDump(stdout, ctxt->doc, node);
1161: #endif /* LIBXML_HTML_ENABLED */
1.13 daniel 1162: } else {
1163: if (node->type == XML_DOCUMENT_NODE)
1164: xmlDocDump(stdout, (xmlDocPtr) node);
1165: else
1166: xmlElemDump(stdout, ctxt->doc, node);
1167: }
1.12 daniel 1168: printf("\n");
1169: return(0);
1170: }
1171:
1172: /**
1173: * xmlShellLoad:
1174: * @ctxt: the shell context
1175: * @filename: the file name
1176: * @node: unused
1177: * @node2: unused
1178: *
1179: * Implements the XML shell function "load"
1180: * loads a new document specified by the filename
1181: *
1182: * Returns 0 or -1 if loading failed
1183: */
1184: int
1185: xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1186: xmlNodePtr node2) {
1187: xmlDocPtr doc;
1188: int html = 0;
1189:
1190: if (ctxt->doc != NULL)
1191: html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
1192:
1193: if (html) {
1.23 daniel 1194: #ifdef LIBXML_HTML_ENABLED
1.12 daniel 1195: doc = htmlParseFile(filename, NULL);
1.23 daniel 1196: #else
1197: printf("HTML support not compiled in\n");
1198: doc = NULL;
1199: #endif /* LIBXML_HTML_ENABLED */
1.12 daniel 1200: } else {
1201: doc = xmlParseFile(filename);
1202: }
1203: if (doc != NULL) {
1204: if (ctxt->loaded == 1) {
1205: xmlFreeDoc(ctxt->doc);
1206: }
1207: ctxt->loaded = 1;
1.23 daniel 1208: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1209: xmlXPathFreeContext(ctxt->pctxt);
1.23 daniel 1210: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1211: xmlFree(ctxt->filename);
1212: ctxt->doc = doc;
1213: ctxt->node = (xmlNodePtr) doc;
1.23 daniel 1214: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1215: ctxt->pctxt = xmlXPathNewContext(doc);
1.23 daniel 1216: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1217: ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1218: } else
1219: return(-1);
1220: return(0);
1221: }
1222:
1223: /**
1224: * xmlShellWrite:
1225: * @ctxt: the shell context
1226: * @filename: the file name
1227: * @node: a node in the tree
1228: * @node2: unused
1229: *
1230: * Implements the XML shell function "write"
1231: * Write the current node to the filename, it saves the serailization
1232: * of the subtree under the @node specified
1233: *
1234: * Returns 0 or -1 in case of error
1235: */
1236: int
1237: xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1238: xmlNodePtr node2) {
1239: if (node == NULL)
1240: return(-1);
1241: if ((filename == NULL) || (filename[0] == 0)) {
1242: fprintf(stderr, "Write command requires a filename argument\n");
1243: return(-1);
1244: }
1245: #ifdef W_OK
1246: if (access((char *) filename, W_OK)) {
1247: fprintf(stderr, "Cannot write to %s\n", filename);
1248: return(-1);
1249: }
1250: #endif
1251: switch(node->type) {
1252: case XML_DOCUMENT_NODE:
1253: if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1254: fprintf(stderr, "Failed to write to %s\n", filename);
1255: return(-1);
1256: }
1257: break;
1258: case XML_HTML_DOCUMENT_NODE:
1.23 daniel 1259: #ifdef LIBXML_HTML_ENABLED
1.12 daniel 1260: if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1261: fprintf(stderr, "Failed to write to %s\n", filename);
1262: return(-1);
1263: }
1.23 daniel 1264: #else
1265: if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1266: fprintf(stderr, "Failed to write to %s\n", filename);
1267: return(-1);
1268: }
1269: #endif /* LIBXML_HTML_ENABLED */
1.12 daniel 1270: break;
1271: default: {
1272: FILE *f;
1273:
1274: f = fopen((char *) filename, "w");
1275: if (f == NULL) {
1276: fprintf(stderr, "Failed to write to %s\n", filename);
1277: return(-1);
1278: }
1279: xmlElemDump(f, ctxt->doc, node);
1280: fclose(f);
1281: }
1282: }
1283: return(0);
1284: }
1285:
1286: /**
1287: * xmlShellSave:
1288: * @ctxt: the shell context
1289: * @filename: the file name (optionnal)
1290: * @node: unused
1291: * @node2: unused
1292: *
1293: * Implements the XML shell function "save"
1294: * Write the current document to the filename, or it's original name
1295: *
1296: * Returns 0 or -1 in case of error
1297: */
1298: int
1299: xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1300: xmlNodePtr node2) {
1301: if (ctxt->doc == NULL)
1302: return(-1);
1303: if ((filename == NULL) || (filename[0] == 0))
1304: filename = ctxt->filename;
1305: #ifdef W_OK
1306: if (access((char *) filename, W_OK)) {
1307: fprintf(stderr, "Cannot save to %s\n", filename);
1308: return(-1);
1309: }
1310: #endif
1311: switch(ctxt->doc->type) {
1312: case XML_DOCUMENT_NODE:
1313: if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1314: fprintf(stderr, "Failed to save to %s\n", filename);
1315: }
1316: break;
1317: case XML_HTML_DOCUMENT_NODE:
1.23 daniel 1318: #ifdef LIBXML_HTML_ENABLED
1.12 daniel 1319: if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1320: fprintf(stderr, "Failed to save to %s\n", filename);
1321: }
1.23 daniel 1322: #else
1323: if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1324: fprintf(stderr, "Failed to save to %s\n", filename);
1325: }
1326: #endif /* LIBXML_HTML_ENABLED */
1.12 daniel 1327: break;
1328: default:
1329: fprintf(stderr,
1330: "To save to subparts of a document use the 'write' command\n");
1331: return(-1);
1332:
1333: }
1334: return(0);
1335: }
1336:
1337: /**
1338: * xmlShellValidate:
1339: * @ctxt: the shell context
1340: * @dtd: the DTD URI (optionnal)
1341: * @node: unused
1342: * @node2: unused
1343: *
1344: * Implements the XML shell function "validate"
1345: * Validate the document, if a DTD path is provided, then the validation
1346: * is done against the given DTD.
1347: *
1348: * Returns 0 or -1 in case of error
1349: */
1350: int
1351: xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
1352: xmlNodePtr node2) {
1353: xmlValidCtxt vctxt;
1354: int res = -1;
1355:
1356: vctxt.userData = stderr;
1357: vctxt.error = (xmlValidityErrorFunc) fprintf;
1358: vctxt.warning = (xmlValidityWarningFunc) fprintf;
1359:
1360: if ((dtd == NULL) || (dtd[0] == 0)) {
1361: res = xmlValidateDocument(&vctxt, ctxt->doc);
1362: } else {
1363: xmlDtdPtr subset;
1364:
1365: subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1366: if (subset != NULL) {
1367: res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1368:
1369: xmlFreeDtd(subset);
1370: }
1371: }
1372: return(res);
1373: }
1374:
1375: /**
1376: * xmlShellDu:
1377: * @ctxt: the shell context
1378: * @arg: unused
1379: * @tree: a node defining a subtree
1380: * @node2: unused
1381: *
1382: * Implements the XML shell function "du"
1383: * show the structure of the subtree under node @tree
1384: * If @tree is null, the command works on the current node.
1385: *
1386: * Returns 0 or -1 in case of error
1387: */
1388: int
1389: xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
1390: xmlNodePtr node2) {
1391: xmlNodePtr node;
1392: int indent = 0,i;
1393:
1394: if (tree == NULL) return(-1);
1395: node = tree;
1396: while (node != NULL) {
1397: if ((node->type == XML_DOCUMENT_NODE) ||
1398: (node->type == XML_HTML_DOCUMENT_NODE)) {
1399: printf("/\n");
1400: } else if (node->type == XML_ELEMENT_NODE) {
1401: for (i = 0;i < indent;i++)
1402: printf(" ");
1403: printf("%s\n", node->name);
1404: } else {
1405: }
1406:
1407: /*
1408: * Browse the full subtree, deep first
1409: */
1410:
1411: if ((node->type == XML_DOCUMENT_NODE) ||
1412: (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16 daniel 1413: node = ((xmlDocPtr) node)->children;
1.25 daniel 1414: } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1.12 daniel 1415: /* deep first */
1.16 daniel 1416: node = node->children;
1.12 daniel 1417: indent++;
1418: } else if ((node != tree) && (node->next != NULL)) {
1419: /* then siblings */
1420: node = node->next;
1421: } else if (node != tree) {
1422: /* go up to parents->next if needed */
1423: while (node != tree) {
1424: if (node->parent != NULL) {
1425: node = node->parent;
1426: indent--;
1427: }
1428: if ((node != tree) && (node->next != NULL)) {
1429: node = node->next;
1430: break;
1431: }
1432: if (node->parent == NULL) {
1433: node = NULL;
1434: break;
1435: }
1436: if (node == tree) {
1437: node = NULL;
1438: break;
1439: }
1440: }
1441: /* exit condition */
1442: if (node == tree)
1443: node = NULL;
1444: } else
1445: node = NULL;
1446: }
1447: return(0);
1448: }
1449:
1450: /**
1451: * xmlShellPwd:
1452: * @ctxt: the shell context
1453: * @buffer: the output buffer
1454: * @tree: a node
1455: * @node2: unused
1456: *
1457: * Implements the XML shell function "pwd"
1458: * Show the full path from the root to the node, if needed building
1459: * thumblers when similar elements exists at a given ancestor level.
1460: * The output is compatible with XPath commands.
1461: *
1462: * Returns 0 or -1 in case of error
1463: */
1464: int
1465: xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
1466: xmlNodePtr node2) {
1467: xmlNodePtr cur, tmp, next;
1468: char buf[500];
1469: char sep;
1470: const char *name;
1471: int occur = 0;
1472:
1473: buffer[0] = 0;
1474: if (node == NULL) return(-1);
1475: cur = node;
1476: do {
1477: name = "";
1478: sep= '?';
1479: occur = 0;
1480: if ((cur->type == XML_DOCUMENT_NODE) ||
1481: (cur->type == XML_HTML_DOCUMENT_NODE)) {
1482: sep = '/';
1483: next = NULL;
1484: } else if (cur->type == XML_ELEMENT_NODE) {
1485: sep = '/';
1486: name = (const char *)cur->name;
1487: next = cur->parent;
1488:
1489: /*
1490: * Thumbler index computation
1491: */
1492: tmp = cur->prev;
1493: while (tmp != NULL) {
1.35 veillard 1494: if (xmlStrEqual(cur->name, tmp->name))
1.12 daniel 1495: occur++;
1496: tmp = tmp->prev;
1497: }
1498: if (occur == 0) {
1499: tmp = cur->next;
1500: while (tmp != NULL) {
1.35 veillard 1501: if (xmlStrEqual(cur->name, tmp->name))
1.12 daniel 1502: occur++;
1503: tmp = tmp->next;
1504: }
1505: if (occur != 0) occur = 1;
1506: } else
1507: occur++;
1508: } else if (cur->type == XML_ATTRIBUTE_NODE) {
1509: sep = '@';
1510: name = (const char *) (((xmlAttrPtr) cur)->name);
1.16 daniel 1511: next = ((xmlAttrPtr) cur)->parent;
1.12 daniel 1512: } else {
1513: next = cur->parent;
1514: }
1515: if (occur == 0)
1.31 veillard 1516: #ifdef HAVE_SNPRINTF
1517: snprintf(buf, sizeof(buf), "%c%s%s", sep, name, buffer);
1518: #else
1.12 daniel 1519: sprintf(buf, "%c%s%s", sep, name, buffer);
1.31 veillard 1520: #endif
1521: else
1522: #ifdef HAVE_SNPRINTF
1523: snprintf(buf, sizeof(buf), "%c%s[%d]%s",
1524: sep, name, occur, buffer);
1525: #else
1.12 daniel 1526: sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
1.31 veillard 1527: #endif
1528: buf[sizeof(buf) - 1] = 0;
1529: /*
1530: * This test prevents buffer overflow, because this routine
1531: * is only called by xmlShell, in which the second argument is
1532: * 500 chars long.
1533: * It is a dirty hack before a cleaner solution is found.
1534: * Documentation should mention that the second argument must
1535: * be at least 500 chars long, and could be stripped if too long.
1536: */
1537: if (strlen(buffer) + strlen(buf) > 499)
1538: break;
1.12 daniel 1539: strcpy(buffer, buf);
1540: cur = next;
1541: } while (cur != NULL);
1542: return(0);
1543: }
1544:
1545: /**
1546: * xmlShell
1547: * @doc: the initial document
1548: * @filename: the output buffer
1549: * @input: the line reading function
1550: * @output: the output FILE*
1551: *
1552: * Implements the XML shell
1553: * This allow to load, validate, view, modify and save a document
1554: * using a environment similar to a UNIX commandline.
1555: */
1556: void
1557: xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1558: FILE *output) {
1559: char prompt[500] = "/ > ";
1560: char *cmdline = NULL;
1561: int nbargs;
1562: char command[100];
1563: char arg[400];
1564: xmlShellCtxtPtr ctxt;
1565: xmlXPathObjectPtr list;
1566:
1567: if (doc == NULL)
1568: return;
1569: if (filename == NULL)
1570: return;
1571: if (input == NULL)
1572: return;
1573: if (output == NULL)
1574: return;
1575: ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1576: if (ctxt == NULL)
1577: return;
1578: ctxt->loaded = 0;
1579: ctxt->doc = doc;
1580: ctxt->input = input;
1581: ctxt->output = output;
1582: ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1583: ctxt->node = (xmlNodePtr) ctxt->doc;
1584:
1.23 daniel 1585: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1586: ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1587: if (ctxt->pctxt == NULL) {
1588: xmlFree(ctxt);
1589: return;
1590: }
1.23 daniel 1591: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1592: while (1) {
1593: if (ctxt->node == (xmlNodePtr) ctxt->doc)
1594: sprintf(prompt, "%s > ", "/");
1595: else if (ctxt->node->name)
1.31 veillard 1596: #ifdef HAVE_SNPRINTF
1597: snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
1598: #else
1.34 veillard 1599: sprintf(prompt, "%s > ", ctxt->node->name);
1.31 veillard 1600: #endif
1601: else
1.12 daniel 1602: sprintf(prompt, "? > ");
1.31 veillard 1603: prompt[sizeof(prompt) - 1] = 0;
1.12 daniel 1604:
1605: cmdline = ctxt->input(prompt);
1606: if (cmdline == NULL) break;
1607:
1608: command[0] = 0;
1609: arg[0] = 0;
1610: nbargs = sscanf(cmdline, "%s %s", command, arg);
1611:
1612: if (command[0] == 0) continue;
1613: if (!strcmp(command, "exit"))
1614: break;
1615: if (!strcmp(command, "quit"))
1616: break;
1617: if (!strcmp(command, "bye"))
1618: break;
1619: if (!strcmp(command, "validate")) {
1620: xmlShellValidate(ctxt, arg, NULL, NULL);
1621: } else if (!strcmp(command, "load")) {
1622: xmlShellLoad(ctxt, arg, NULL, NULL);
1623: } else if (!strcmp(command, "save")) {
1624: xmlShellSave(ctxt, arg, NULL, NULL);
1625: } else if (!strcmp(command, "write")) {
1626: xmlShellWrite(ctxt, arg, NULL, NULL);
1627: } else if (!strcmp(command, "free")) {
1628: if (arg[0] == 0) {
1629: xmlMemShow(stdout, 0);
1630: } else {
1631: int len = 0;
1632: sscanf(arg, "%d", &len);
1633: xmlMemShow(stdout, len);
1634: }
1635: } else if (!strcmp(command, "pwd")) {
1636: char dir[500];
1637: if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
1638: printf("%s\n", dir);
1639: } else if (!strcmp(command, "du")) {
1640: xmlShellDu(ctxt, NULL, ctxt->node, NULL);
1641: } else if ((!strcmp(command, "ls")) ||
1642: (!strcmp(command, "dir"))) {
1643: int dir = (!strcmp(command, "dir"));
1644: if (arg[0] == 0) {
1645: if (dir)
1646: xmlShellDir(ctxt, NULL, ctxt->node, NULL);
1647: else
1648: xmlShellList(ctxt, NULL, ctxt->node, NULL);
1649: } else {
1650: ctxt->pctxt->node = ctxt->node;
1.23 daniel 1651: #ifdef LIBXML_XPATH_ENABLED
1.36 veillard 1652: ctxt->pctxt->node = ctxt->node;
1.12 daniel 1653: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23 daniel 1654: #else
1655: list = NULL;
1656: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1657: if (list != NULL) {
1658: switch (list->type) {
1659: case XPATH_UNDEFINED:
1660: fprintf(stderr, "%s: no such node\n", arg);
1661: break;
1662: case XPATH_NODESET: {
1663: int i;
1664:
1665: for (i = 0;i < list->nodesetval->nodeNr;i++) {
1666: if (dir)
1667: xmlShellDir(ctxt, NULL,
1668: list->nodesetval->nodeTab[i], NULL);
1669: else
1670: xmlShellList(ctxt, NULL,
1671: list->nodesetval->nodeTab[i], NULL);
1672: }
1673: break;
1674: }
1675: case XPATH_BOOLEAN:
1676: fprintf(stderr, "%s is a Boolean\n", arg);
1677: break;
1678: case XPATH_NUMBER:
1679: fprintf(stderr, "%s is a number\n", arg);
1680: break;
1681: case XPATH_STRING:
1682: fprintf(stderr, "%s is a string\n", arg);
1683: break;
1.37 ! veillard 1684: case XPATH_POINT:
! 1685: fprintf(stderr, "%s is a point\n", arg);
! 1686: break;
! 1687: case XPATH_RANGE:
! 1688: fprintf(stderr, "%s is a range\n", arg);
! 1689: break;
! 1690: case XPATH_RANGESET:
! 1691: fprintf(stderr, "%s is a range\n", arg);
! 1692: break;
! 1693: case XPATH_USERS:
! 1694: fprintf(stderr, "%s is user-defined\n", arg);
! 1695: break;
1.12 daniel 1696: }
1697: xmlXPathFreeNodeSetList(list);
1698: } else {
1699: fprintf(stderr, "%s: no such node\n", arg);
1700: }
1.36 veillard 1701: ctxt->pctxt->node = NULL;
1.12 daniel 1702: }
1703: } else if (!strcmp(command, "cd")) {
1704: if (arg[0] == 0) {
1705: ctxt->node = (xmlNodePtr) ctxt->doc;
1706: } else {
1.36 veillard 1707: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1708: ctxt->pctxt->node = ctxt->node;
1709: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23 daniel 1710: #else
1711: list = NULL;
1712: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1713: if (list != NULL) {
1714: switch (list->type) {
1715: case XPATH_UNDEFINED:
1716: fprintf(stderr, "%s: no such node\n", arg);
1717: break;
1718: case XPATH_NODESET:
1719: if (list->nodesetval->nodeNr == 1) {
1720: ctxt->node = list->nodesetval->nodeTab[0];
1721: } else
1722: fprintf(stderr, "%s is a %d Node Set\n",
1723: arg, list->nodesetval->nodeNr);
1724: break;
1725: case XPATH_BOOLEAN:
1726: fprintf(stderr, "%s is a Boolean\n", arg);
1727: break;
1728: case XPATH_NUMBER:
1729: fprintf(stderr, "%s is a number\n", arg);
1730: break;
1731: case XPATH_STRING:
1732: fprintf(stderr, "%s is a string\n", arg);
1733: break;
1.37 ! veillard 1734: case XPATH_POINT:
! 1735: fprintf(stderr, "%s is a point\n", arg);
! 1736: break;
! 1737: case XPATH_RANGE:
! 1738: fprintf(stderr, "%s is a range\n", arg);
! 1739: break;
! 1740: case XPATH_RANGESET:
! 1741: fprintf(stderr, "%s is a range\n", arg);
! 1742: break;
! 1743: case XPATH_USERS:
! 1744: fprintf(stderr, "%s is user-defined\n", arg);
! 1745: break;
1.12 daniel 1746: }
1747: xmlXPathFreeNodeSetList(list);
1748: } else {
1749: fprintf(stderr, "%s: no such node\n", arg);
1750: }
1.36 veillard 1751: ctxt->pctxt->node = NULL;
1.12 daniel 1752: }
1753: } else if (!strcmp(command, "cat")) {
1754: if (arg[0] == 0) {
1755: xmlShellCat(ctxt, NULL, ctxt->node, NULL);
1756: } else {
1757: ctxt->pctxt->node = ctxt->node;
1.23 daniel 1758: #ifdef LIBXML_XPATH_ENABLED
1.36 veillard 1759: ctxt->pctxt->node = ctxt->node;
1.12 daniel 1760: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1.23 daniel 1761: #else
1762: list = NULL;
1763: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1764: if (list != NULL) {
1765: switch (list->type) {
1766: case XPATH_UNDEFINED:
1767: fprintf(stderr, "%s: no such node\n", arg);
1768: break;
1769: case XPATH_NODESET: {
1770: int i;
1771:
1772: for (i = 0;i < list->nodesetval->nodeNr;i++) {
1773: if (i > 0) printf(" -------\n");
1774: xmlShellCat(ctxt, NULL,
1775: list->nodesetval->nodeTab[i], NULL);
1776: }
1777: break;
1778: }
1779: case XPATH_BOOLEAN:
1780: fprintf(stderr, "%s is a Boolean\n", arg);
1781: break;
1782: case XPATH_NUMBER:
1783: fprintf(stderr, "%s is a number\n", arg);
1784: break;
1785: case XPATH_STRING:
1786: fprintf(stderr, "%s is a string\n", arg);
1.37 ! veillard 1787: break;
! 1788: case XPATH_POINT:
! 1789: fprintf(stderr, "%s is a point\n", arg);
! 1790: break;
! 1791: case XPATH_RANGE:
! 1792: fprintf(stderr, "%s is a range\n", arg);
! 1793: break;
! 1794: case XPATH_RANGESET:
! 1795: fprintf(stderr, "%s is a range\n", arg);
! 1796: break;
! 1797: case XPATH_USERS:
! 1798: fprintf(stderr, "%s is user-defined\n", arg);
1.12 daniel 1799: break;
1800: }
1801: xmlXPathFreeNodeSetList(list);
1802: } else {
1803: fprintf(stderr, "%s: no such node\n", arg);
1804: }
1.36 veillard 1805: ctxt->pctxt->node = NULL;
1.12 daniel 1806: }
1807: } else {
1808: fprintf(stderr, "Unknown command %s\n", command);
1809: }
1810: free(cmdline); /* not xmlFree here ! */
1811: }
1.23 daniel 1812: #ifdef LIBXML_XPATH_ENABLED
1.12 daniel 1813: xmlXPathFreeContext(ctxt->pctxt);
1.23 daniel 1814: #endif /* LIBXML_XPATH_ENABLED */
1.12 daniel 1815: if (ctxt->loaded) {
1816: xmlFreeDoc(ctxt->doc);
1817: }
1818: xmlFree(ctxt);
1819: if (cmdline != NULL)
1820: free(cmdline); /* not xmlFree here ! */
1821: }
1822:
1.23 daniel 1823: #endif /* LIBXML_DEBUG_ENABLED */
Webmaster