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