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