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