blob: e0c41f9f86f58dd717cbacfab815584a1a99d794 [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 Veillard361d8452000-04-03 19:48:13 +000015
16#include "xmlversion.h"
17#ifdef LIBXML_DEBUG_ENABLED
18
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000019#include <stdio.h>
Daniel Veillard32bc74e2000-07-14 14:49:25 +000020#include <string.h>
Daniel Veillarddbfd6411999-12-28 16:35:14 +000021#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
Daniel Veillard5feb8492000-02-02 17:15:36 +000024#ifdef HAVE_STRING_H
25#include <string.h>
26#endif
Daniel Veillard361d8452000-04-03 19:48:13 +000027#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>
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000034
35#define IS_BLANK(c) \
36 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
37
Daniel Veillarddd6b3671999-09-23 22:19:22 +000038void xmlDebugDumpString(FILE *output, const xmlChar *str) {
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000039 int i;
Daniel Veillarde0854c32000-08-27 21:12:29 +000040 if (str == NULL) {
41 fprintf(output, "(NULL)");
42 return;
43 }
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000044 for (i = 0;i < 40;i++)
45 if (str[i] == 0) return;
46 else if (IS_BLANK(str[i])) fputc(' ', output);
Daniel Veillard32bc74e2000-07-14 14:49:25 +000047 else if (str[i] >= 0x80)
48 fprintf(output, "#%X", str[i]);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +000049 else fputc(str[i], output);
50 fprintf(output, "...");
51}
52
Daniel Veillardcf461992000-03-14 18:30:20 +000053void 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
101void 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
217void 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 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000231 if (elem->name != NULL) {
232 fprintf(output, "ELEMDECL(");
233 xmlDebugDumpString(output, elem->name);
234 fprintf(output, ")");
235 } else
Daniel Veillardcf461992000-03-14 18:30:20 +0000236 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) {
Daniel Veillard39c7d712000-09-10 16:14:55 +0000252 char buf[5001];
Daniel Veillardcf461992000-03-14 18:30:20 +0000253
254 buf[0] = 0;
255 xmlSprintfElementContent(buf, elem->content, 1);
Daniel Veillard39c7d712000-09-10 16:14:55 +0000256 buf[5000] = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +0000257 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
286void 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 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000300 if (ent->name != NULL) {
301 fprintf(output, "ENTITYDECL(");
302 xmlDebugDumpString(output, ent->name);
303 fprintf(output, ")");
304 } else
Daniel Veillardcf461992000-03-14 18:30:20 +0000305 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);
Daniel Veillard39c7d712000-09-10 16:14:55 +0000328 fprintf(output, " ExternalID=%s\n", ent->ExternalID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000329 }
330 if (ent->SystemID) {
331 fprintf(output, shift);
Daniel Veillard39c7d712000-09-10 16:14:55 +0000332 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);
Daniel Veillardcf461992000-03-14 18:30:20 +0000337 }
338 if (ent->content) {
339 fprintf(output, shift);
Daniel Veillard39c7d712000-09-10 16:14:55 +0000340 fprintf(output, " content=");
Daniel Veillardcf461992000-03-14 18:30:20 +0000341 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
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000370void 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 ");
Daniel Veillarde0854c32000-08-27 21:12:29 +0000381 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=");
Daniel Veillard5cb5ab81999-12-21 15:35:29 +0000391
Daniel Veillarde0854c32000-08-27 21:12:29 +0000392 xmlDebugDumpString(output, ns->href);
393 fprintf(output, "\n");
394 }
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000395}
396
397void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
398 while (ns != NULL) {
399 xmlDebugDumpNamespace(output, ns, depth);
400 ns = ns->next;
401 }
402}
403
404void 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);
Daniel Veillardcf461992000-03-14 18:30:20 +0000413 switch (ent->etype) {
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000414 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:
Daniel Veillardcf461992000-03-14 18:30:20 +0000430 fprintf(output, "ENTITY_%d ! ", ent->etype);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000431 }
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 }
Daniel Veillard39c7d712000-09-10 16:14:55 +0000441 if (ent->URI) {
442 fprintf(output, shift);
443 fprintf(output, "URI=%s\n", ent->URI);
444 }
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000445 if (ent->content) {
446 fprintf(output, shift);
447 fprintf(output, "content=");
448 xmlDebugDumpString(output, ent->content);
449 fprintf(output, "\n");
450 }
451}
452
453void 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);
Daniel Veillardcf461992000-03-14 18:30:20 +0000462
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000463 fprintf(output, "ATTRIBUTE ");
464 xmlDebugDumpString(output, attr->name);
465 fprintf(output, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000466 if (attr->children != NULL)
467 xmlDebugDumpNodeList(output, attr->children, depth + 1);
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 }
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000489}
490
491void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) {
492 while (attr != NULL) {
493 xmlDebugDumpAttr(output, attr, depth);
494 attr = attr->next;
495 }
496}
497
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000498void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) {
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000499 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
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000506 switch (node->type) {
507 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000508 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000509 fprintf(output, "ELEMENT ");
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000510 if (node->ns != NULL) {
511 xmlDebugDumpString(output, node->ns->prefix);
512 fprintf(output, ":");
513 }
514 xmlDebugDumpString(output, node->name);
515 fprintf(output, "\n");
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000516 break;
517 case XML_ATTRIBUTE_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000518 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000519 fprintf(output, "Error, ATTRIBUTE found here\n");
520 break;
521 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000522 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000523 fprintf(output, "TEXT\n");
524 break;
525 case XML_CDATA_SECTION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000526 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000527 fprintf(output, "CDATA_SECTION\n");
528 break;
529 case XML_ENTITY_REF_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000530 fprintf(output, shift);
531 fprintf(output, "ENTITY_REF(%s)\n", node->name);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000532 break;
533 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000534 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000535 fprintf(output, "ENTITY\n");
536 break;
537 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000538 fprintf(output, shift);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000539 fprintf(output, "PI %s\n", node->name);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000540 break;
541 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000542 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000543 fprintf(output, "COMMENT\n");
544 break;
545 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000546 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000547 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000548 fprintf(output, "Error, DOCUMENT found here\n");
549 break;
550 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000551 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000552 fprintf(output, "DOCUMENT_TYPE\n");
553 break;
554 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000555 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000556 fprintf(output, "DOCUMENT_FRAG\n");
557 break;
558 case XML_NOTATION_NODE:
559 fprintf(output, "NOTATION\n");
560 break;
Daniel Veillardcf461992000-03-14 18:30:20 +0000561 case XML_DTD_NODE:
562 xmlDebugDumpDtd(output, (xmlDtdPtr) node, depth);
563 return;
564 case XML_ELEMENT_DECL:
565 xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
566 return;
567 case XML_ATTRIBUTE_DECL:
568 xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
569 return;
570 case XML_ENTITY_DECL:
571 xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
572 return;
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000573 default:
Daniel Veillardcf461992000-03-14 18:30:20 +0000574 fprintf(output, shift);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000575 fprintf(output, "NODE_%d\n", node->type);
576 }
577 if (node->doc == NULL) {
578 fprintf(output, shift);
579 fprintf(output, "doc == NULL !!!\n");
580 }
581 if (node->nsDef != NULL)
582 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
583 if (node->properties != NULL)
584 xmlDebugDumpAttrList(output, node->properties, depth + 1);
585 if (node->type != XML_ENTITY_REF_NODE) {
586 if (node->content != NULL) {
587 fprintf(output, shift);
588 fprintf(output, "content=");
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000589#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000590 xmlDebugDumpString(output, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000591#else
592 xmlDebugDumpString(output, xmlBufferContent(node->content));
593#endif
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000594 fprintf(output, "\n");
595 }
596 } else {
597 xmlEntityPtr ent;
598 ent = xmlGetDocEntity(node->doc, node->name);
599 if (ent != NULL)
600 xmlDebugDumpEntity(output, ent, depth + 1);
601 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000602 /*
603 * Do a bit of checking
604 */
605 if (node->parent == NULL)
606 fprintf(output, "PBM: Node has no parent\n");
607 if (node->doc == NULL)
608 fprintf(output, "PBM: Node has no doc\n");
609 if ((node->parent != NULL) && (node->doc != node->parent->doc))
610 fprintf(output, "PBM: Node doc differs from parent's one\n");
611 if (node->prev == NULL) {
612 if ((node->parent != NULL) && (node->parent->children != node))
613 fprintf(output, "PBM: Node has no prev and not first of list\n");
614 } else {
615 if (node->prev->next != node)
616 fprintf(output, "PBM: Node prev->next : back link wrong\n");
617 }
618 if (node->next == NULL) {
619 if ((node->parent != NULL) && (node->parent->last != node))
620 fprintf(output, "PBM: Node has no next and not last of list\n");
621 } else {
622 if (node->next->prev != node)
623 fprintf(output, "PBM: Node next->prev : forward link wrong\n");
624 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000625}
626
627void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
628 xmlDebugDumpOneNode(output, node, depth);
Daniel Veillard39c7d712000-09-10 16:14:55 +0000629 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
Daniel Veillardcf461992000-03-14 18:30:20 +0000630 xmlDebugDumpNodeList(output, node->children, depth + 1);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000631}
632
633void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
634 while (node != NULL) {
635 xmlDebugDumpNode(output, node, depth);
636 node = node->next;
637 }
638}
639
640
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000641void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000642 if (output == NULL) output = stdout;
643 if (doc == NULL) {
644 fprintf(output, "DOCUMENT == NULL !\n");
645 return;
646 }
647
648 switch (doc->type) {
649 case XML_ELEMENT_NODE:
650 fprintf(output, "Error, ELEMENT found here ");
651 break;
652 case XML_ATTRIBUTE_NODE:
653 fprintf(output, "Error, ATTRIBUTE found here\n");
654 break;
655 case XML_TEXT_NODE:
656 fprintf(output, "Error, TEXT\n");
657 break;
658 case XML_CDATA_SECTION_NODE:
659 fprintf(output, "Error, CDATA_SECTION\n");
660 break;
661 case XML_ENTITY_REF_NODE:
662 fprintf(output, "Error, ENTITY_REF\n");
663 break;
664 case XML_ENTITY_NODE:
665 fprintf(output, "Error, ENTITY\n");
666 break;
667 case XML_PI_NODE:
668 fprintf(output, "Error, PI\n");
669 break;
670 case XML_COMMENT_NODE:
671 fprintf(output, "Error, COMMENT\n");
672 break;
673 case XML_DOCUMENT_NODE:
674 fprintf(output, "DOCUMENT\n");
675 break;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000676 case XML_HTML_DOCUMENT_NODE:
677 fprintf(output, "HTML DOCUMENT\n");
678 break;
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000679 case XML_DOCUMENT_TYPE_NODE:
680 fprintf(output, "Error, DOCUMENT_TYPE\n");
681 break;
682 case XML_DOCUMENT_FRAG_NODE:
683 fprintf(output, "Error, DOCUMENT_FRAG\n");
684 break;
685 case XML_NOTATION_NODE:
686 fprintf(output, "Error, NOTATION\n");
687 break;
688 default:
689 fprintf(output, "NODE_%d\n", doc->type);
690 }
691 if (doc->name != NULL) {
692 fprintf(output, "name=");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000693 xmlDebugDumpString(output, BAD_CAST doc->name);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000694 fprintf(output, "\n");
695 }
696 if (doc->version != NULL) {
697 fprintf(output, "version=");
698 xmlDebugDumpString(output, doc->version);
699 fprintf(output, "\n");
700 }
701 if (doc->encoding != NULL) {
702 fprintf(output, "encoding=");
703 xmlDebugDumpString(output, doc->encoding);
704 fprintf(output, "\n");
705 }
Daniel Veillard39c7d712000-09-10 16:14:55 +0000706 if (doc->URL != NULL) {
707 fprintf(output, "URL=");
708 xmlDebugDumpString(output, doc->URL);
709 fprintf(output, "\n");
710 }
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000711 if (doc->standalone)
712 fprintf(output, "standalone=true\n");
713 if (doc->oldNs != NULL)
714 xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000715}
Daniel Veillard10a2c651999-12-12 13:03:50 +0000716
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000717void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
718 if (output == NULL) output = stdout;
719 if (doc == NULL) {
720 fprintf(output, "DOCUMENT == NULL !\n");
721 return;
722 }
723 xmlDebugDumpDocumentHead(output, doc);
724 if (((doc->type == XML_DOCUMENT_NODE) ||
725 (doc->type == XML_HTML_DOCUMENT_NODE)) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000726 (doc->children != NULL))
727 xmlDebugDumpNodeList(output, doc->children, 1);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000728}
729
Daniel Veillard39c7d712000-09-10 16:14:55 +0000730void xmlDebugDumpDTD(FILE *output, xmlDtdPtr dtd) {
731 if (dtd == NULL)
732 return;
733 if (dtd->type != XML_DTD_NODE) {
734 fprintf(output, "PBM: not a DTD\n");
735 return;
736 }
737 if (dtd->name != NULL)
738 fprintf(output, "DTD(%s)", dtd->name);
739 else
740 fprintf(output, "DTD");
741 if (dtd->ExternalID != NULL)
742 fprintf(output, ", PUBLIC %s", dtd->ExternalID);
743 if (dtd->SystemID != NULL)
744 fprintf(output, ", SYSTEM %s", dtd->SystemID);
745 fprintf(output, "\n");
746 /*
747 * Do a bit of checking
748 */
749 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
750 fprintf(output, "PBM: Dtd doc differs from parent's one\n");
751 if (dtd->prev == NULL) {
752 if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
753 fprintf(output, "PBM: Dtd has no prev and not first of list\n");
754 } else {
755 if (dtd->prev->next != (xmlNodePtr) dtd)
756 fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
757 }
758 if (dtd->next == NULL) {
759 if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
760 fprintf(output, "PBM: Dtd has no next and not last of list\n");
761 } else {
762 if (dtd->next->prev != (xmlNodePtr) dtd)
763 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
764 }
765 if (dtd->children == NULL)
766 fprintf(output, " DTD is empty\n");
767 else
768 xmlDebugDumpNodeList(output, dtd->children, 1);
769}
770
Daniel Veillard10a2c651999-12-12 13:03:50 +0000771void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
772 int i;
773 xmlEntityPtr cur;
774
775 if (output == NULL) output = stdout;
776 if (doc == NULL) {
777 fprintf(output, "DOCUMENT == NULL !\n");
778 return;
779 }
780
781 switch (doc->type) {
782 case XML_ELEMENT_NODE:
783 fprintf(output, "Error, ELEMENT found here ");
784 break;
785 case XML_ATTRIBUTE_NODE:
786 fprintf(output, "Error, ATTRIBUTE found here\n");
787 break;
788 case XML_TEXT_NODE:
789 fprintf(output, "Error, TEXT\n");
790 break;
791 case XML_CDATA_SECTION_NODE:
792 fprintf(output, "Error, CDATA_SECTION\n");
793 break;
794 case XML_ENTITY_REF_NODE:
795 fprintf(output, "Error, ENTITY_REF\n");
796 break;
797 case XML_ENTITY_NODE:
798 fprintf(output, "Error, ENTITY\n");
799 break;
800 case XML_PI_NODE:
801 fprintf(output, "Error, PI\n");
802 break;
803 case XML_COMMENT_NODE:
804 fprintf(output, "Error, COMMENT\n");
805 break;
806 case XML_DOCUMENT_NODE:
807 fprintf(output, "DOCUMENT\n");
808 break;
809 case XML_HTML_DOCUMENT_NODE:
810 fprintf(output, "HTML DOCUMENT\n");
811 break;
812 case XML_DOCUMENT_TYPE_NODE:
813 fprintf(output, "Error, DOCUMENT_TYPE\n");
814 break;
815 case XML_DOCUMENT_FRAG_NODE:
816 fprintf(output, "Error, DOCUMENT_FRAG\n");
817 break;
818 case XML_NOTATION_NODE:
819 fprintf(output, "Error, NOTATION\n");
820 break;
821 default:
822 fprintf(output, "NODE_%d\n", doc->type);
823 }
824 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
825 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
826 doc->intSubset->entities;
827 fprintf(output, "Entities in internal subset\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000828 for (i = 0;i < table->max_entities;i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000829 cur = table->table[i];
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000830 while (cur != NULL) {
831 fprintf(output, "%d : %s : ", i, cur->name);
832 switch (cur->etype) {
833 case XML_INTERNAL_GENERAL_ENTITY:
834 fprintf(output, "INTERNAL GENERAL, ");
835 break;
836 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
837 fprintf(output, "EXTERNAL PARSED, ");
838 break;
839 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
840 fprintf(output, "EXTERNAL UNPARSED, ");
841 break;
842 case XML_INTERNAL_PARAMETER_ENTITY:
843 fprintf(output, "INTERNAL PARAMETER, ");
844 break;
845 case XML_EXTERNAL_PARAMETER_ENTITY:
846 fprintf(output, "EXTERNAL PARAMETER, ");
847 break;
848 default:
849 fprintf(output, "UNKNOWN TYPE %d",
850 cur->etype);
851 }
852 if (cur->ExternalID != NULL)
853 fprintf(output, "ID \"%s\"", cur->ExternalID);
854 if (cur->SystemID != NULL)
855 fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
856 if (cur->orig != NULL)
857 fprintf(output, "\n orig \"%s\"", cur->orig);
858 if (cur->content != NULL)
859 fprintf(output, "\n content \"%s\"", cur->content);
860 fprintf(output, "\n");
861 cur = cur->nexte;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000862 }
Daniel Veillard10a2c651999-12-12 13:03:50 +0000863 }
864 } else
865 fprintf(output, "No entities in internal subset\n");
866 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
867 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
868 doc->extSubset->entities;
869 fprintf(output, "Entities in external subset\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000870 for (i = 0;i < table->max_entities;i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000871 cur = table->table[i];
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000872 while (cur != NULL) {
873 fprintf(output, "%d : %s : ", i, cur->name);
874 switch (cur->etype) {
875 case XML_INTERNAL_GENERAL_ENTITY:
876 fprintf(output, "INTERNAL GENERAL, ");
877 break;
878 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
879 fprintf(output, "EXTERNAL PARSED, ");
880 break;
881 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
882 fprintf(output, "EXTERNAL UNPARSED, ");
883 break;
884 case XML_INTERNAL_PARAMETER_ENTITY:
885 fprintf(output, "INTERNAL PARAMETER, ");
886 break;
887 case XML_EXTERNAL_PARAMETER_ENTITY:
888 fprintf(output, "EXTERNAL PARAMETER, ");
889 break;
890 default:
891 fprintf(output, "UNKNOWN TYPE %d",
892 cur->etype);
893 }
894 if (cur->ExternalID != NULL)
895 fprintf(output, "ID \"%s\"", cur->ExternalID);
896 if (cur->SystemID != NULL)
897 fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
898 if (cur->orig != NULL)
899 fprintf(output, "\n orig \"%s\"", cur->orig);
900 if (cur->content != NULL)
901 fprintf(output, "\n content \"%s\"", cur->content);
902 fprintf(output, "\n");
903 cur = cur->nexte;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000904 }
Daniel Veillard10a2c651999-12-12 13:03:50 +0000905 }
906 } else
907 fprintf(output, "No entities in external subset\n");
908}
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000909
910static int xmlLsCountNode(xmlNodePtr node) {
911 int ret = 0;
912 xmlNodePtr list = NULL;
913
914 switch (node->type) {
915 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000916 list = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000917 break;
918 case XML_DOCUMENT_NODE:
919 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000920 list = ((xmlDocPtr) node)->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000921 break;
922 case XML_ATTRIBUTE_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000923 list = ((xmlAttrPtr) node)->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000924 break;
925 case XML_TEXT_NODE:
926 case XML_CDATA_SECTION_NODE:
927 case XML_PI_NODE:
928 case XML_COMMENT_NODE:
929 if (node->content != NULL) {
930#ifndef XML_USE_BUFFER_CONTENT
931 ret = xmlStrlen(node->content);
932#else
933 ret = xmlBufferLength(node->content);
934#endif
935 }
936 break;
937 case XML_ENTITY_REF_NODE:
938 case XML_DOCUMENT_TYPE_NODE:
939 case XML_ENTITY_NODE:
940 case XML_DOCUMENT_FRAG_NODE:
941 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +0000942 case XML_DTD_NODE:
943 case XML_ELEMENT_DECL:
944 case XML_ATTRIBUTE_DECL:
945 case XML_ENTITY_DECL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000946 ret = 1;
947 break;
948 }
949 for (;list != NULL;ret++)
950 list = list->next;
951 return(ret);
952}
953
954void xmlLsOneNode(FILE *output, xmlNodePtr node) {
955 switch (node->type) {
956 case XML_ELEMENT_NODE:
957 fprintf(output, "-");
958 break;
959 case XML_ATTRIBUTE_NODE:
960 fprintf(output, "a");
961 break;
962 case XML_TEXT_NODE:
963 fprintf(output, "t");
964 break;
965 case XML_CDATA_SECTION_NODE:
966 fprintf(output, "c");
967 break;
968 case XML_ENTITY_REF_NODE:
969 fprintf(output, "e");
970 break;
971 case XML_ENTITY_NODE:
972 fprintf(output, "E");
973 break;
974 case XML_PI_NODE:
975 fprintf(output, "p");
976 break;
977 case XML_COMMENT_NODE:
978 fprintf(output, "c");
979 break;
980 case XML_DOCUMENT_NODE:
981 fprintf(output, "d");
982 break;
983 case XML_HTML_DOCUMENT_NODE:
984 fprintf(output, "h");
985 break;
986 case XML_DOCUMENT_TYPE_NODE:
987 fprintf(output, "T");
988 break;
989 case XML_DOCUMENT_FRAG_NODE:
990 fprintf(output, "F");
991 break;
992 case XML_NOTATION_NODE:
993 fprintf(output, "N");
994 break;
995 default:
996 fprintf(output, "?");
997 }
998 if (node->properties != NULL)
999 fprintf(output, "a");
1000 else
1001 fprintf(output, "-");
1002 if (node->nsDef != NULL)
1003 fprintf(output, "n");
1004 else
1005 fprintf(output, "-");
1006
1007 fprintf(output, " %8d ", xmlLsCountNode(node));
1008
1009 switch (node->type) {
1010 case XML_ELEMENT_NODE:
1011 if (node->name != NULL)
1012 fprintf(output, "%s", node->name);
1013 break;
1014 case XML_ATTRIBUTE_NODE:
1015 if (node->name != NULL)
1016 fprintf(output, "%s", node->name);
1017 break;
1018 case XML_TEXT_NODE:
1019 if (node->content != NULL) {
1020#ifndef XML_USE_BUFFER_CONTENT
1021 xmlDebugDumpString(output, node->content);
1022#else
1023 xmlDebugDumpString(output, xmlBufferContent(node->content));
1024#endif
1025 }
1026 break;
1027 case XML_CDATA_SECTION_NODE:
1028 break;
1029 case XML_ENTITY_REF_NODE:
1030 if (node->name != NULL)
1031 fprintf(output, "%s", node->name);
1032 break;
1033 case XML_ENTITY_NODE:
1034 if (node->name != NULL)
1035 fprintf(output, "%s", node->name);
1036 break;
1037 case XML_PI_NODE:
1038 if (node->name != NULL)
1039 fprintf(output, "%s", node->name);
1040 break;
1041 case XML_COMMENT_NODE:
1042 break;
1043 case XML_DOCUMENT_NODE:
1044 break;
1045 case XML_HTML_DOCUMENT_NODE:
1046 break;
1047 case XML_DOCUMENT_TYPE_NODE:
1048 break;
1049 case XML_DOCUMENT_FRAG_NODE:
1050 break;
1051 case XML_NOTATION_NODE:
1052 break;
1053 default:
1054 if (node->name != NULL)
1055 fprintf(output, "%s", node->name);
1056 }
1057 fprintf(output, "\n");
1058}
1059
1060/****************************************************************
1061 * *
1062 * The XML shell related functions *
1063 * *
1064 ****************************************************************/
1065
1066/*
1067 * TODO: Improvement/cleanups for the XML shell
1068 * - allow to shell out an editor on a subpart
1069 * - cleanup function registrations (with help) and calling
1070 * - provide registration routines
1071 */
1072
1073/**
1074 * xmlShellList:
1075 * @ctxt: the shell context
1076 * @arg: unused
1077 * @node: a node
1078 * @node2: unused
1079 *
1080 * Implements the XML shell function "ls"
1081 * Does an Unix like listing of the given node (like a directory)
1082 *
1083 * Returns 0
1084 */
1085int
1086xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1087 xmlNodePtr node2) {
1088 xmlNodePtr cur;
1089
1090 if ((node->type == XML_DOCUMENT_NODE) ||
1091 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001092 cur = ((xmlDocPtr) node)->children;
1093 } else if (node->children != NULL) {
1094 cur = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001095 } else {
1096 xmlLsOneNode(stdout, node);
1097 return(0);
1098 }
1099 while (cur != NULL) {
1100 xmlLsOneNode(stdout, cur);
1101 cur = cur->next;
1102 }
1103 return(0);
1104}
1105
1106/**
1107 * xmlShellDir:
1108 * @ctxt: the shell context
1109 * @arg: unused
1110 * @node: a node
1111 * @node2: unused
1112 *
1113 * Implements the XML shell function "dir"
1114 * dumps informations about the node (namespace, attributes, content).
1115 *
1116 * Returns 0
1117 */
1118int
1119xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1120 xmlNodePtr node2) {
1121 if ((node->type == XML_DOCUMENT_NODE) ||
1122 (node->type == XML_HTML_DOCUMENT_NODE)) {
1123 xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
1124 } else if (node->type == XML_ATTRIBUTE_NODE) {
1125 xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
1126 } else {
1127 xmlDebugDumpOneNode(stdout, node, 0);
1128 }
1129 return(0);
1130}
1131
1132/**
1133 * xmlShellCat:
1134 * @ctxt: the shell context
1135 * @arg: unused
1136 * @node: a node
1137 * @node2: unused
1138 *
1139 * Implements the XML shell function "cat"
1140 * dumps the serialization node content (XML or HTML).
1141 *
1142 * Returns 0
1143 */
1144int
1145xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
1146 xmlNodePtr node2) {
Daniel Veillardaeea04f2000-01-25 19:27:27 +00001147 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard361d8452000-04-03 19:48:13 +00001148#ifdef LIBXML_HTML_ENABLED
Daniel Veillardaeea04f2000-01-25 19:27:27 +00001149 if (node->type == XML_HTML_DOCUMENT_NODE)
1150 htmlDocDump(stdout, (htmlDocPtr) node);
1151 else
Daniel Veillard5feb8492000-02-02 17:15:36 +00001152 htmlNodeDumpFile(stdout, ctxt->doc, node);
Daniel Veillard361d8452000-04-03 19:48:13 +00001153#else
1154 if (node->type == XML_DOCUMENT_NODE)
1155 xmlDocDump(stdout, (xmlDocPtr) node);
1156 else
1157 xmlElemDump(stdout, ctxt->doc, node);
1158#endif /* LIBXML_HTML_ENABLED */
Daniel Veillardaeea04f2000-01-25 19:27:27 +00001159 } else {
1160 if (node->type == XML_DOCUMENT_NODE)
1161 xmlDocDump(stdout, (xmlDocPtr) node);
1162 else
1163 xmlElemDump(stdout, ctxt->doc, node);
1164 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001165 printf("\n");
1166 return(0);
1167}
1168
1169/**
1170 * xmlShellLoad:
1171 * @ctxt: the shell context
1172 * @filename: the file name
1173 * @node: unused
1174 * @node2: unused
1175 *
1176 * Implements the XML shell function "load"
1177 * loads a new document specified by the filename
1178 *
1179 * Returns 0 or -1 if loading failed
1180 */
1181int
1182xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1183 xmlNodePtr node2) {
1184 xmlDocPtr doc;
1185 int html = 0;
1186
1187 if (ctxt->doc != NULL)
1188 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
1189
1190 if (html) {
Daniel Veillard361d8452000-04-03 19:48:13 +00001191#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001192 doc = htmlParseFile(filename, NULL);
Daniel Veillard361d8452000-04-03 19:48:13 +00001193#else
1194 printf("HTML support not compiled in\n");
1195 doc = NULL;
1196#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001197 } else {
1198 doc = xmlParseFile(filename);
1199 }
1200 if (doc != NULL) {
1201 if (ctxt->loaded == 1) {
1202 xmlFreeDoc(ctxt->doc);
1203 }
1204 ctxt->loaded = 1;
Daniel Veillard361d8452000-04-03 19:48:13 +00001205#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001206 xmlXPathFreeContext(ctxt->pctxt);
Daniel Veillard361d8452000-04-03 19:48:13 +00001207#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001208 xmlFree(ctxt->filename);
1209 ctxt->doc = doc;
1210 ctxt->node = (xmlNodePtr) doc;
Daniel Veillard361d8452000-04-03 19:48:13 +00001211#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001212 ctxt->pctxt = xmlXPathNewContext(doc);
Daniel Veillard361d8452000-04-03 19:48:13 +00001213#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001214 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1215 } else
1216 return(-1);
1217 return(0);
1218}
1219
1220/**
1221 * xmlShellWrite:
1222 * @ctxt: the shell context
1223 * @filename: the file name
1224 * @node: a node in the tree
1225 * @node2: unused
1226 *
1227 * Implements the XML shell function "write"
1228 * Write the current node to the filename, it saves the serailization
1229 * of the subtree under the @node specified
1230 *
1231 * Returns 0 or -1 in case of error
1232 */
1233int
1234xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1235 xmlNodePtr node2) {
1236 if (node == NULL)
1237 return(-1);
1238 if ((filename == NULL) || (filename[0] == 0)) {
1239 fprintf(stderr, "Write command requires a filename argument\n");
1240 return(-1);
1241 }
1242#ifdef W_OK
1243 if (access((char *) filename, W_OK)) {
1244 fprintf(stderr, "Cannot write to %s\n", filename);
1245 return(-1);
1246 }
1247#endif
1248 switch(node->type) {
1249 case XML_DOCUMENT_NODE:
1250 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1251 fprintf(stderr, "Failed to write to %s\n", filename);
1252 return(-1);
1253 }
1254 break;
1255 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard361d8452000-04-03 19:48:13 +00001256#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001257 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1258 fprintf(stderr, "Failed to write to %s\n", filename);
1259 return(-1);
1260 }
Daniel Veillard361d8452000-04-03 19:48:13 +00001261#else
1262 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1263 fprintf(stderr, "Failed to write to %s\n", filename);
1264 return(-1);
1265 }
1266#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001267 break;
1268 default: {
1269 FILE *f;
1270
1271 f = fopen((char *) filename, "w");
1272 if (f == NULL) {
1273 fprintf(stderr, "Failed to write to %s\n", filename);
1274 return(-1);
1275 }
1276 xmlElemDump(f, ctxt->doc, node);
1277 fclose(f);
1278 }
1279 }
1280 return(0);
1281}
1282
1283/**
1284 * xmlShellSave:
1285 * @ctxt: the shell context
1286 * @filename: the file name (optionnal)
1287 * @node: unused
1288 * @node2: unused
1289 *
1290 * Implements the XML shell function "save"
1291 * Write the current document to the filename, or it's original name
1292 *
1293 * Returns 0 or -1 in case of error
1294 */
1295int
1296xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
1297 xmlNodePtr node2) {
1298 if (ctxt->doc == NULL)
1299 return(-1);
1300 if ((filename == NULL) || (filename[0] == 0))
1301 filename = ctxt->filename;
1302#ifdef W_OK
1303 if (access((char *) filename, W_OK)) {
1304 fprintf(stderr, "Cannot save to %s\n", filename);
1305 return(-1);
1306 }
1307#endif
1308 switch(ctxt->doc->type) {
1309 case XML_DOCUMENT_NODE:
1310 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1311 fprintf(stderr, "Failed to save to %s\n", filename);
1312 }
1313 break;
1314 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard361d8452000-04-03 19:48:13 +00001315#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001316 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1317 fprintf(stderr, "Failed to save to %s\n", filename);
1318 }
Daniel Veillard361d8452000-04-03 19:48:13 +00001319#else
1320 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1321 fprintf(stderr, "Failed to save to %s\n", filename);
1322 }
1323#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001324 break;
1325 default:
1326 fprintf(stderr,
1327 "To save to subparts of a document use the 'write' command\n");
1328 return(-1);
1329
1330 }
1331 return(0);
1332}
1333
1334/**
1335 * xmlShellValidate:
1336 * @ctxt: the shell context
1337 * @dtd: the DTD URI (optionnal)
1338 * @node: unused
1339 * @node2: unused
1340 *
1341 * Implements the XML shell function "validate"
1342 * Validate the document, if a DTD path is provided, then the validation
1343 * is done against the given DTD.
1344 *
1345 * Returns 0 or -1 in case of error
1346 */
1347int
1348xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
1349 xmlNodePtr node2) {
1350 xmlValidCtxt vctxt;
1351 int res = -1;
1352
1353 vctxt.userData = stderr;
1354 vctxt.error = (xmlValidityErrorFunc) fprintf;
1355 vctxt.warning = (xmlValidityWarningFunc) fprintf;
1356
1357 if ((dtd == NULL) || (dtd[0] == 0)) {
1358 res = xmlValidateDocument(&vctxt, ctxt->doc);
1359 } else {
1360 xmlDtdPtr subset;
1361
1362 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1363 if (subset != NULL) {
1364 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1365
1366 xmlFreeDtd(subset);
1367 }
1368 }
1369 return(res);
1370}
1371
1372/**
1373 * xmlShellDu:
1374 * @ctxt: the shell context
1375 * @arg: unused
1376 * @tree: a node defining a subtree
1377 * @node2: unused
1378 *
1379 * Implements the XML shell function "du"
1380 * show the structure of the subtree under node @tree
1381 * If @tree is null, the command works on the current node.
1382 *
1383 * Returns 0 or -1 in case of error
1384 */
1385int
1386xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
1387 xmlNodePtr node2) {
1388 xmlNodePtr node;
1389 int indent = 0,i;
1390
1391 if (tree == NULL) return(-1);
1392 node = tree;
1393 while (node != NULL) {
1394 if ((node->type == XML_DOCUMENT_NODE) ||
1395 (node->type == XML_HTML_DOCUMENT_NODE)) {
1396 printf("/\n");
1397 } else if (node->type == XML_ELEMENT_NODE) {
1398 for (i = 0;i < indent;i++)
1399 printf(" ");
1400 printf("%s\n", node->name);
1401 } else {
1402 }
1403
1404 /*
1405 * Browse the full subtree, deep first
1406 */
1407
1408 if ((node->type == XML_DOCUMENT_NODE) ||
1409 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001410 node = ((xmlDocPtr) node)->children;
Daniel Veillardbe803962000-06-28 23:40:59 +00001411 } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001412 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00001413 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001414 indent++;
1415 } else if ((node != tree) && (node->next != NULL)) {
1416 /* then siblings */
1417 node = node->next;
1418 } else if (node != tree) {
1419 /* go up to parents->next if needed */
1420 while (node != tree) {
1421 if (node->parent != NULL) {
1422 node = node->parent;
1423 indent--;
1424 }
1425 if ((node != tree) && (node->next != NULL)) {
1426 node = node->next;
1427 break;
1428 }
1429 if (node->parent == NULL) {
1430 node = NULL;
1431 break;
1432 }
1433 if (node == tree) {
1434 node = NULL;
1435 break;
1436 }
1437 }
1438 /* exit condition */
1439 if (node == tree)
1440 node = NULL;
1441 } else
1442 node = NULL;
1443 }
1444 return(0);
1445}
1446
1447/**
1448 * xmlShellPwd:
1449 * @ctxt: the shell context
1450 * @buffer: the output buffer
1451 * @tree: a node
1452 * @node2: unused
1453 *
1454 * Implements the XML shell function "pwd"
1455 * Show the full path from the root to the node, if needed building
1456 * thumblers when similar elements exists at a given ancestor level.
1457 * The output is compatible with XPath commands.
1458 *
1459 * Returns 0 or -1 in case of error
1460 */
1461int
1462xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
1463 xmlNodePtr node2) {
1464 xmlNodePtr cur, tmp, next;
1465 char buf[500];
1466 char sep;
1467 const char *name;
1468 int occur = 0;
1469
1470 buffer[0] = 0;
1471 if (node == NULL) return(-1);
1472 cur = node;
1473 do {
1474 name = "";
1475 sep= '?';
1476 occur = 0;
1477 if ((cur->type == XML_DOCUMENT_NODE) ||
1478 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1479 sep = '/';
1480 next = NULL;
1481 } else if (cur->type == XML_ELEMENT_NODE) {
1482 sep = '/';
1483 name = (const char *)cur->name;
1484 next = cur->parent;
1485
1486 /*
1487 * Thumbler index computation
1488 */
1489 tmp = cur->prev;
1490 while (tmp != NULL) {
1491 if (!xmlStrcmp(cur->name, tmp->name))
1492 occur++;
1493 tmp = tmp->prev;
1494 }
1495 if (occur == 0) {
1496 tmp = cur->next;
1497 while (tmp != NULL) {
1498 if (!xmlStrcmp(cur->name, tmp->name))
1499 occur++;
1500 tmp = tmp->next;
1501 }
1502 if (occur != 0) occur = 1;
1503 } else
1504 occur++;
1505 } else if (cur->type == XML_ATTRIBUTE_NODE) {
1506 sep = '@';
1507 name = (const char *) (((xmlAttrPtr) cur)->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001508 next = ((xmlAttrPtr) cur)->parent;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001509 } else {
1510 next = cur->parent;
1511 }
1512 if (occur == 0)
Daniel Veillard39c7d712000-09-10 16:14:55 +00001513#ifdef HAVE_SNPRINTF
1514 snprintf(buf, sizeof(buf), "%c%s%s", sep, name, buffer);
1515#else
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001516 sprintf(buf, "%c%s%s", sep, name, buffer);
Daniel Veillard39c7d712000-09-10 16:14:55 +00001517#endif
1518 else
1519#ifdef HAVE_SNPRINTF
1520 snprintf(buf, sizeof(buf), "%c%s[%d]%s",
1521 sep, name, occur, buffer);
1522#else
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001523 sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
Daniel Veillard39c7d712000-09-10 16:14:55 +00001524#endif
1525 buf[sizeof(buf) - 1] = 0;
1526 /*
1527 * This test prevents buffer overflow, because this routine
1528 * is only called by xmlShell, in which the second argument is
1529 * 500 chars long.
1530 * It is a dirty hack before a cleaner solution is found.
1531 * Documentation should mention that the second argument must
1532 * be at least 500 chars long, and could be stripped if too long.
1533 */
1534 if (strlen(buffer) + strlen(buf) > 499)
1535 break;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001536 strcpy(buffer, buf);
1537 cur = next;
1538 } while (cur != NULL);
1539 return(0);
1540}
1541
1542/**
1543 * xmlShell
1544 * @doc: the initial document
1545 * @filename: the output buffer
1546 * @input: the line reading function
1547 * @output: the output FILE*
1548 *
1549 * Implements the XML shell
1550 * This allow to load, validate, view, modify and save a document
1551 * using a environment similar to a UNIX commandline.
1552 */
1553void
1554xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1555 FILE *output) {
1556 char prompt[500] = "/ > ";
1557 char *cmdline = NULL;
1558 int nbargs;
1559 char command[100];
1560 char arg[400];
1561 xmlShellCtxtPtr ctxt;
1562 xmlXPathObjectPtr list;
1563
1564 if (doc == NULL)
1565 return;
1566 if (filename == NULL)
1567 return;
1568 if (input == NULL)
1569 return;
1570 if (output == NULL)
1571 return;
1572 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1573 if (ctxt == NULL)
1574 return;
1575 ctxt->loaded = 0;
1576 ctxt->doc = doc;
1577 ctxt->input = input;
1578 ctxt->output = output;
1579 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1580 ctxt->node = (xmlNodePtr) ctxt->doc;
1581
Daniel Veillard361d8452000-04-03 19:48:13 +00001582#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001583 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1584 if (ctxt->pctxt == NULL) {
1585 xmlFree(ctxt);
1586 return;
1587 }
Daniel Veillard361d8452000-04-03 19:48:13 +00001588#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001589 while (1) {
1590 if (ctxt->node == (xmlNodePtr) ctxt->doc)
1591 sprintf(prompt, "%s > ", "/");
1592 else if (ctxt->node->name)
Daniel Veillard39c7d712000-09-10 16:14:55 +00001593#ifdef HAVE_SNPRINTF
1594 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
1595#else
1596 sprintf(buf, "%s > ", ctxt->node->name);
1597#endif
1598 else
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001599 sprintf(prompt, "? > ");
Daniel Veillard39c7d712000-09-10 16:14:55 +00001600 prompt[sizeof(prompt) - 1] = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001601
1602 cmdline = ctxt->input(prompt);
1603 if (cmdline == NULL) break;
1604
1605 command[0] = 0;
1606 arg[0] = 0;
1607 nbargs = sscanf(cmdline, "%s %s", command, arg);
1608
1609 if (command[0] == 0) continue;
1610 if (!strcmp(command, "exit"))
1611 break;
1612 if (!strcmp(command, "quit"))
1613 break;
1614 if (!strcmp(command, "bye"))
1615 break;
1616 if (!strcmp(command, "validate")) {
1617 xmlShellValidate(ctxt, arg, NULL, NULL);
1618 } else if (!strcmp(command, "load")) {
1619 xmlShellLoad(ctxt, arg, NULL, NULL);
1620 } else if (!strcmp(command, "save")) {
1621 xmlShellSave(ctxt, arg, NULL, NULL);
1622 } else if (!strcmp(command, "write")) {
1623 xmlShellWrite(ctxt, arg, NULL, NULL);
1624 } else if (!strcmp(command, "free")) {
1625 if (arg[0] == 0) {
1626 xmlMemShow(stdout, 0);
1627 } else {
1628 int len = 0;
1629 sscanf(arg, "%d", &len);
1630 xmlMemShow(stdout, len);
1631 }
1632 } else if (!strcmp(command, "pwd")) {
1633 char dir[500];
1634 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
1635 printf("%s\n", dir);
1636 } else if (!strcmp(command, "du")) {
1637 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
1638 } else if ((!strcmp(command, "ls")) ||
1639 (!strcmp(command, "dir"))) {
1640 int dir = (!strcmp(command, "dir"));
1641 if (arg[0] == 0) {
1642 if (dir)
1643 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
1644 else
1645 xmlShellList(ctxt, NULL, ctxt->node, NULL);
1646 } else {
1647 ctxt->pctxt->node = ctxt->node;
Daniel Veillard361d8452000-04-03 19:48:13 +00001648#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001649 if (ctxt->pctxt->nodelist != NULL)
1650 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1651 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1652 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard361d8452000-04-03 19:48:13 +00001653#else
1654 list = NULL;
1655#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001656 if (list != NULL) {
1657 switch (list->type) {
1658 case XPATH_UNDEFINED:
1659 fprintf(stderr, "%s: no such node\n", arg);
1660 break;
1661 case XPATH_NODESET: {
1662 int i;
1663
1664 for (i = 0;i < list->nodesetval->nodeNr;i++) {
1665 if (dir)
1666 xmlShellDir(ctxt, NULL,
1667 list->nodesetval->nodeTab[i], NULL);
1668 else
1669 xmlShellList(ctxt, NULL,
1670 list->nodesetval->nodeTab[i], NULL);
1671 }
1672 break;
1673 }
1674 case XPATH_BOOLEAN:
1675 fprintf(stderr, "%s is a Boolean\n", arg);
1676 break;
1677 case XPATH_NUMBER:
1678 fprintf(stderr, "%s is a number\n", arg);
1679 break;
1680 case XPATH_STRING:
1681 fprintf(stderr, "%s is a string\n", arg);
1682 break;
1683 }
1684 xmlXPathFreeNodeSetList(list);
1685 } else {
1686 fprintf(stderr, "%s: no such node\n", arg);
1687 }
Daniel Veillard361d8452000-04-03 19:48:13 +00001688#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001689 if (ctxt->pctxt->nodelist != NULL)
1690 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
Daniel Veillard361d8452000-04-03 19:48:13 +00001691#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001692 ctxt->pctxt->nodelist = NULL;
1693 }
1694 } else if (!strcmp(command, "cd")) {
1695 if (arg[0] == 0) {
1696 ctxt->node = (xmlNodePtr) ctxt->doc;
1697 } else {
1698 ctxt->pctxt->node = ctxt->node;
Daniel Veillard361d8452000-04-03 19:48:13 +00001699#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001700 if (ctxt->pctxt->nodelist != NULL)
1701 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1702 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1703 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard361d8452000-04-03 19:48:13 +00001704#else
1705 list = NULL;
1706#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001707 if (list != NULL) {
1708 switch (list->type) {
1709 case XPATH_UNDEFINED:
1710 fprintf(stderr, "%s: no such node\n", arg);
1711 break;
1712 case XPATH_NODESET:
1713 if (list->nodesetval->nodeNr == 1) {
1714 ctxt->node = list->nodesetval->nodeTab[0];
1715 } else
1716 fprintf(stderr, "%s is a %d Node Set\n",
1717 arg, list->nodesetval->nodeNr);
1718 break;
1719 case XPATH_BOOLEAN:
1720 fprintf(stderr, "%s is a Boolean\n", arg);
1721 break;
1722 case XPATH_NUMBER:
1723 fprintf(stderr, "%s is a number\n", arg);
1724 break;
1725 case XPATH_STRING:
1726 fprintf(stderr, "%s is a string\n", arg);
1727 break;
1728 }
1729 xmlXPathFreeNodeSetList(list);
1730 } else {
1731 fprintf(stderr, "%s: no such node\n", arg);
1732 }
Daniel Veillard361d8452000-04-03 19:48:13 +00001733#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001734 if (ctxt->pctxt->nodelist != NULL)
1735 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
Daniel Veillard361d8452000-04-03 19:48:13 +00001736#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001737 ctxt->pctxt->nodelist = NULL;
1738 }
1739 } else if (!strcmp(command, "cat")) {
1740 if (arg[0] == 0) {
1741 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
1742 } else {
1743 ctxt->pctxt->node = ctxt->node;
Daniel Veillard361d8452000-04-03 19:48:13 +00001744#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001745 if (ctxt->pctxt->nodelist != NULL)
1746 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1747 ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1748 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard361d8452000-04-03 19:48:13 +00001749#else
1750 list = NULL;
1751#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001752 if (list != NULL) {
1753 switch (list->type) {
1754 case XPATH_UNDEFINED:
1755 fprintf(stderr, "%s: no such node\n", arg);
1756 break;
1757 case XPATH_NODESET: {
1758 int i;
1759
1760 for (i = 0;i < list->nodesetval->nodeNr;i++) {
1761 if (i > 0) printf(" -------\n");
1762 xmlShellCat(ctxt, NULL,
1763 list->nodesetval->nodeTab[i], NULL);
1764 }
1765 break;
1766 }
1767 case XPATH_BOOLEAN:
1768 fprintf(stderr, "%s is a Boolean\n", arg);
1769 break;
1770 case XPATH_NUMBER:
1771 fprintf(stderr, "%s is a number\n", arg);
1772 break;
1773 case XPATH_STRING:
1774 fprintf(stderr, "%s is a string\n", arg);
1775 break;
1776 }
1777 xmlXPathFreeNodeSetList(list);
1778 } else {
1779 fprintf(stderr, "%s: no such node\n", arg);
1780 }
Daniel Veillard361d8452000-04-03 19:48:13 +00001781#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001782 if (ctxt->pctxt->nodelist != NULL)
1783 xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
Daniel Veillard361d8452000-04-03 19:48:13 +00001784#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001785 ctxt->pctxt->nodelist = NULL;
1786 }
1787 } else {
1788 fprintf(stderr, "Unknown command %s\n", command);
1789 }
1790 free(cmdline); /* not xmlFree here ! */
1791 }
Daniel Veillard361d8452000-04-03 19:48:13 +00001792#ifdef LIBXML_XPATH_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001793 xmlXPathFreeContext(ctxt->pctxt);
Daniel Veillard361d8452000-04-03 19:48:13 +00001794#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001795 if (ctxt->loaded) {
1796 xmlFreeDoc(ctxt->doc);
1797 }
1798 xmlFree(ctxt);
1799 if (cmdline != NULL)
1800 free(cmdline); /* not xmlFree here ! */
1801}
1802
Daniel Veillard361d8452000-04-03 19:48:13 +00001803#endif /* LIBXML_DEBUG_ENABLED */