blob: aa3eaf9ef8965ccd9ac002aaf501ca0e9a4e5c8f [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * debugXML.c : This is a set of routines used for debugging the tree
3 * produced by the XML parser.
4 *
5 * See Copyright for the status of this software.
6 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00007 * Daniel Veillard <daniel@veillard.com>
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Bjorn Reese70a9da52001-04-21 16:57:29 +000010#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000011#ifdef LIBXML_DEBUG_ENABLED
12
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h>
14#ifdef HAVE_STDLIB_H
15#include <stdlib.h>
16#endif
17#ifdef HAVE_STRING_H
18#include <string.h>
19#endif
20#include <libxml/xmlmemory.h>
21#include <libxml/tree.h>
22#include <libxml/parser.h>
Daniel Veillard567e1b42001-08-01 15:53:47 +000023#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000024#include <libxml/valid.h>
25#include <libxml/debugXML.h>
26#include <libxml/HTMLtree.h>
27#include <libxml/HTMLparser.h>
28#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000029#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000030
Daniel Veillard5e2dace2001-07-18 19:30:27 +000031/**
Daniel Veillardc6e013a2001-11-10 10:08:57 +000032 * xmlGetNodePath:
33 * @node: a node
34 *
35 * Build a structure based Path for the given node
36 *
37 * Returns the new path or NULL in case of error. The caller must free
38 * the returned string
39 */
40xmlChar *
41xmlGetNodePath(xmlNodePtr node)
42{
43 xmlNodePtr cur, tmp, next;
44 xmlChar *buffer = NULL, *temp;
45 size_t buf_len;
46 xmlChar *buf;
47 char sep;
48 const char *name;
49 char nametemp[100];
50 int occur = 0;
51
52 if (node == NULL)
53 return (NULL);
54
55 buf_len = 500;
56 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
57 if (buffer == NULL)
58 return (NULL);
59 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
60 if (buf == NULL) {
61 xmlFree(buffer);
62 return (NULL);
63 }
64
65 buffer[0] = 0;
66 cur = node;
67 do {
68 name = "";
69 sep = '?';
70 occur = 0;
71 if ((cur->type == XML_DOCUMENT_NODE) ||
72 (cur->type == XML_HTML_DOCUMENT_NODE)) {
73 if (buffer[0] == '/')
74 break;
75 sep = '/';
76 next = NULL;
77 } else if (cur->type == XML_ELEMENT_NODE) {
78 sep = '/';
79 name = (const char *) cur->name;
80 if (cur->ns) {
81 snprintf(nametemp, sizeof(nametemp) - 1,
82 "%s:%s", cur->ns->prefix, cur->name);
83 nametemp[sizeof(nametemp) - 1] = 0;
84 name = nametemp;
85 }
86 next = cur->parent;
87
88 /*
89 * Thumbler index computation
90 */
91 tmp = cur->prev;
92 while (tmp != NULL) {
93 if (xmlStrEqual(cur->name, tmp->name))
94 occur++;
95 tmp = tmp->prev;
96 }
97 if (occur == 0) {
98 tmp = cur->next;
99 while (tmp != NULL) {
100 if (xmlStrEqual(cur->name, tmp->name))
101 occur++;
102 tmp = tmp->next;
103 }
104 if (occur != 0)
105 occur = 1;
106 } else
107 occur++;
108 } else if (cur->type == XML_ATTRIBUTE_NODE) {
109 sep = '@';
110 name = (const char *) (((xmlAttrPtr) cur)->name);
111 next = ((xmlAttrPtr) cur)->parent;
112 } else {
113 next = cur->parent;
114 }
115
116 /*
117 * Make sure there is enough room
118 */
119 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
120 buf_len =
121 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
122 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
123 if (temp == NULL) {
124 xmlFree(buf);
125 xmlFree(buffer);
126 return (NULL);
127 }
128 buffer = temp;
129 temp = (xmlChar *) xmlRealloc(buf, buf_len);
130 if (temp == NULL) {
131 xmlFree(buf);
132 xmlFree(buffer);
133 return (NULL);
134 }
135 buf = temp;
136 }
137 if (occur == 0)
138 snprintf((char *) buf, buf_len, "%c%s%s",
139 sep, name, (char *) buffer);
140 else
141 snprintf((char *) buf, buf_len, "%c%s[%d]%s",
142 sep, name, occur, (char *) buffer);
143 snprintf((char *) buffer, buf_len, "%s", buf);
144 cur = next;
145 } while (cur != NULL);
146 xmlFree(buf);
147 return (buffer);
148}
149
150/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000151 * xmlDebugDumpString:
152 * @output: the FILE * for the output
153 * @str: the string
154 *
155 * Dumps informations about the string, shorten it if necessary
156 */
157void
158xmlDebugDumpString(FILE * output, const xmlChar * str)
159{
Owen Taylor3473f882001-02-23 17:55:21 +0000160 int i;
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000161
Owen Taylor3473f882001-02-23 17:55:21 +0000162 if (str == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000163 fprintf(output, "(NULL)");
164 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000165 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000166 for (i = 0; i < 40; i++)
167 if (str[i] == 0)
168 return;
169 else if (IS_BLANK(str[i]))
170 fputc(' ', output);
171 else if (str[i] >= 0x80)
172 fprintf(output, "#%X", str[i]);
173 else
174 fputc(str[i], output);
Owen Taylor3473f882001-02-23 17:55:21 +0000175 fprintf(output, "...");
176}
177
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000178static void
179xmlDebugDumpDtdNode(FILE *output, xmlDtdPtr dtd, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000180 int i;
181 char shift[100];
182
183 for (i = 0;((i < depth) && (i < 25));i++)
184 shift[2 * i] = shift[2 * i + 1] = ' ';
185 shift[2 * i] = shift[2 * i + 1] = 0;
186
187 fprintf(output, shift);
188
189 if (dtd->type != XML_DTD_NODE) {
190 fprintf(output, "PBM: not a DTD\n");
191 return;
192 }
193 if (dtd->name != NULL)
194 fprintf(output, "DTD(%s)", dtd->name);
195 else
196 fprintf(output, "DTD");
197 if (dtd->ExternalID != NULL)
198 fprintf(output, ", PUBLIC %s", dtd->ExternalID);
199 if (dtd->SystemID != NULL)
200 fprintf(output, ", SYSTEM %s", dtd->SystemID);
201 fprintf(output, "\n");
202 /*
203 * Do a bit of checking
204 */
205 if (dtd->parent == NULL)
206 fprintf(output, "PBM: Dtd has no parent\n");
207 if (dtd->doc == NULL)
208 fprintf(output, "PBM: Dtd has no doc\n");
209 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
210 fprintf(output, "PBM: Dtd doc differs from parent's one\n");
211 if (dtd->prev == NULL) {
212 if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
213 fprintf(output, "PBM: Dtd has no prev and not first of list\n");
214 } else {
215 if (dtd->prev->next != (xmlNodePtr) dtd)
216 fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
217 }
218 if (dtd->next == NULL) {
219 if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
220 fprintf(output, "PBM: Dtd has no next and not last of list\n");
221 } else {
222 if (dtd->next->prev != (xmlNodePtr) dtd)
223 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
224 }
225}
226
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000227static void
228xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000229 int i;
230 char shift[100];
231
232 for (i = 0;((i < depth) && (i < 25));i++)
233 shift[2 * i] = shift[2 * i + 1] = ' ';
234 shift[2 * i] = shift[2 * i + 1] = 0;
235
236 fprintf(output, shift);
237
238 if (attr->type != XML_ATTRIBUTE_DECL) {
239 fprintf(output, "PBM: not a Attr\n");
240 return;
241 }
242 if (attr->name != NULL)
243 fprintf(output, "ATTRDECL(%s)", attr->name);
244 else
245 fprintf(output, "PBM ATTRDECL noname!!!");
246 if (attr->elem != NULL)
247 fprintf(output, " for %s", attr->elem);
248 else
249 fprintf(output, " PBM noelem!!!");
250 switch (attr->atype) {
251 case XML_ATTRIBUTE_CDATA:
252 fprintf(output, " CDATA");
253 break;
254 case XML_ATTRIBUTE_ID:
255 fprintf(output, " ID");
256 break;
257 case XML_ATTRIBUTE_IDREF:
258 fprintf(output, " IDREF");
259 break;
260 case XML_ATTRIBUTE_IDREFS:
261 fprintf(output, " IDREFS");
262 break;
263 case XML_ATTRIBUTE_ENTITY:
264 fprintf(output, " ENTITY");
265 break;
266 case XML_ATTRIBUTE_ENTITIES:
267 fprintf(output, " ENTITIES");
268 break;
269 case XML_ATTRIBUTE_NMTOKEN:
270 fprintf(output, " NMTOKEN");
271 break;
272 case XML_ATTRIBUTE_NMTOKENS:
273 fprintf(output, " NMTOKENS");
274 break;
275 case XML_ATTRIBUTE_ENUMERATION:
276 fprintf(output, " ENUMERATION");
277 break;
278 case XML_ATTRIBUTE_NOTATION:
279 fprintf(output, " NOTATION ");
280 break;
281 }
282 if (attr->tree != NULL) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000283 int indx;
Owen Taylor3473f882001-02-23 17:55:21 +0000284 xmlEnumerationPtr cur = attr->tree;
285
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000286 for (indx = 0;indx < 5; indx++) {
287 if (indx != 0)
Owen Taylor3473f882001-02-23 17:55:21 +0000288 fprintf(output, "|%s", cur->name);
289 else
290 fprintf(output, " (%s", cur->name);
291 cur = cur->next;
292 if (cur == NULL) break;
293 }
294 if (cur == NULL)
295 fprintf(output, ")");
296 else
297 fprintf(output, "...)");
298 }
299 switch (attr->def) {
300 case XML_ATTRIBUTE_NONE:
301 break;
302 case XML_ATTRIBUTE_REQUIRED:
303 fprintf(output, " REQUIRED");
304 break;
305 case XML_ATTRIBUTE_IMPLIED:
306 fprintf(output, " IMPLIED");
307 break;
308 case XML_ATTRIBUTE_FIXED:
309 fprintf(output, " FIXED");
310 break;
311 }
312 if (attr->defaultValue != NULL) {
313 fprintf(output, "\"");
314 xmlDebugDumpString(output, attr->defaultValue);
315 fprintf(output, "\"");
316 }
Daniel Veillardcd337f02001-11-22 18:20:37 +0000317 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000318
319 /*
320 * Do a bit of checking
321 */
322 if (attr->parent == NULL)
323 fprintf(output, "PBM: Attr has no parent\n");
324 if (attr->doc == NULL)
325 fprintf(output, "PBM: Attr has no doc\n");
326 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
327 fprintf(output, "PBM: Attr doc differs from parent's one\n");
328 if (attr->prev == NULL) {
329 if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr))
330 fprintf(output, "PBM: Attr has no prev and not first of list\n");
331 } else {
332 if (attr->prev->next != (xmlNodePtr) attr)
333 fprintf(output, "PBM: Attr prev->next : back link wrong\n");
334 }
335 if (attr->next == NULL) {
336 if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr))
337 fprintf(output, "PBM: Attr has no next and not last of list\n");
338 } else {
339 if (attr->next->prev != (xmlNodePtr) attr)
340 fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
341 }
342}
343
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000344static void
345xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000346 int i;
347 char shift[100];
348
349 for (i = 0;((i < depth) && (i < 25));i++)
350 shift[2 * i] = shift[2 * i + 1] = ' ';
351 shift[2 * i] = shift[2 * i + 1] = 0;
352
353 fprintf(output, shift);
354
355 if (elem->type != XML_ELEMENT_DECL) {
356 fprintf(output, "PBM: not a Elem\n");
357 return;
358 }
359 if (elem->name != NULL) {
360 fprintf(output, "ELEMDECL(");
361 xmlDebugDumpString(output, elem->name);
362 fprintf(output, ")");
363 } else
364 fprintf(output, "PBM ELEMDECL noname!!!");
365 switch (elem->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000366 case XML_ELEMENT_TYPE_UNDEFINED:
367 fprintf(output, ", UNDEFINED");
368 break;
Owen Taylor3473f882001-02-23 17:55:21 +0000369 case XML_ELEMENT_TYPE_EMPTY:
370 fprintf(output, ", EMPTY");
371 break;
372 case XML_ELEMENT_TYPE_ANY:
373 fprintf(output, ", ANY");
374 break;
375 case XML_ELEMENT_TYPE_MIXED:
376 fprintf(output, ", MIXED ");
377 break;
378 case XML_ELEMENT_TYPE_ELEMENT:
379 fprintf(output, ", MIXED ");
380 break;
381 }
Daniel Veillard7db37732001-07-12 01:20:08 +0000382 if ((elem->type != XML_ELEMENT_NODE) &&
383 (elem->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000384 char buf[5001];
385
386 buf[0] = 0;
Daniel Veillardd3d06722001-08-15 12:06:36 +0000387 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000388 buf[5000] = 0;
389 fprintf(output, "%s", buf);
390 }
Daniel Veillardcd337f02001-11-22 18:20:37 +0000391 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000392
393 /*
394 * Do a bit of checking
395 */
396 if (elem->parent == NULL)
397 fprintf(output, "PBM: Elem has no parent\n");
398 if (elem->doc == NULL)
399 fprintf(output, "PBM: Elem has no doc\n");
400 if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
401 fprintf(output, "PBM: Elem doc differs from parent's one\n");
402 if (elem->prev == NULL) {
403 if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem))
404 fprintf(output, "PBM: Elem has no prev and not first of list\n");
405 } else {
406 if (elem->prev->next != (xmlNodePtr) elem)
407 fprintf(output, "PBM: Elem prev->next : back link wrong\n");
408 }
409 if (elem->next == NULL) {
410 if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem))
411 fprintf(output, "PBM: Elem has no next and not last of list\n");
412 } else {
413 if (elem->next->prev != (xmlNodePtr) elem)
414 fprintf(output, "PBM: Elem next->prev : forward link wrong\n");
415 }
416}
417
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000418static void
419xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000420 int i;
421 char shift[100];
422
423 for (i = 0;((i < depth) && (i < 25));i++)
424 shift[2 * i] = shift[2 * i + 1] = ' ';
425 shift[2 * i] = shift[2 * i + 1] = 0;
426
427 fprintf(output, shift);
428
429 if (ent->type != XML_ENTITY_DECL) {
430 fprintf(output, "PBM: not a Entity decl\n");
431 return;
432 }
433 if (ent->name != NULL) {
434 fprintf(output, "ENTITYDECL(");
435 xmlDebugDumpString(output, ent->name);
436 fprintf(output, ")");
437 } else
438 fprintf(output, "PBM ENTITYDECL noname!!!");
439 switch (ent->etype) {
440 case XML_INTERNAL_GENERAL_ENTITY:
441 fprintf(output, ", internal\n");
442 break;
443 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
444 fprintf(output, ", external parsed\n");
445 break;
446 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
447 fprintf(output, ", unparsed\n");
448 break;
449 case XML_INTERNAL_PARAMETER_ENTITY:
450 fprintf(output, ", parameter\n");
451 break;
452 case XML_EXTERNAL_PARAMETER_ENTITY:
453 fprintf(output, ", external parameter\n");
454 break;
455 case XML_INTERNAL_PREDEFINED_ENTITY:
456 fprintf(output, ", predefined\n");
457 break;
458 }
459 if (ent->ExternalID) {
460 fprintf(output, shift);
461 fprintf(output, " ExternalID=%s\n", ent->ExternalID);
462 }
463 if (ent->SystemID) {
464 fprintf(output, shift);
465 fprintf(output, " SystemID=%s\n", ent->SystemID);
466 }
467 if (ent->URI != NULL) {
468 fprintf(output, shift);
469 fprintf(output, " URI=%s\n", ent->URI);
470 }
471 if (ent->content) {
472 fprintf(output, shift);
473 fprintf(output, " content=");
474 xmlDebugDumpString(output, ent->content);
475 fprintf(output, "\n");
476 }
477
478 /*
479 * Do a bit of checking
480 */
481 if (ent->parent == NULL)
482 fprintf(output, "PBM: Ent has no parent\n");
483 if (ent->doc == NULL)
484 fprintf(output, "PBM: Ent has no doc\n");
485 if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
486 fprintf(output, "PBM: Ent doc differs from parent's one\n");
487 if (ent->prev == NULL) {
488 if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent))
489 fprintf(output, "PBM: Ent has no prev and not first of list\n");
490 } else {
491 if (ent->prev->next != (xmlNodePtr) ent)
492 fprintf(output, "PBM: Ent prev->next : back link wrong\n");
493 }
494 if (ent->next == NULL) {
495 if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent))
496 fprintf(output, "PBM: Ent has no next and not last of list\n");
497 } else {
498 if (ent->next->prev != (xmlNodePtr) ent)
499 fprintf(output, "PBM: Ent next->prev : forward link wrong\n");
500 }
501}
502
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000503static void
504xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000505 int i;
506 char shift[100];
507
508 for (i = 0;((i < depth) && (i < 25));i++)
509 shift[2 * i] = shift[2 * i + 1] = ' ';
510 shift[2 * i] = shift[2 * i + 1] = 0;
511
512 fprintf(output, shift);
513 if (ns->type != XML_NAMESPACE_DECL) {
514 fprintf(output, "invalid namespace node %d\n", ns->type);
515 return;
516 }
517 if (ns->href == NULL) {
518 if (ns->prefix != NULL)
519 fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix);
520 else
521 fprintf(output, "incomplete default namespace href=NULL\n");
522 } else {
523 if (ns->prefix != NULL)
524 fprintf(output, "namespace %s href=", ns->prefix);
525 else
526 fprintf(output, "default namespace href=");
527
528 xmlDebugDumpString(output, ns->href);
529 fprintf(output, "\n");
530 }
531}
532
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000533static void
534xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000535 while (ns != NULL) {
536 xmlDebugDumpNamespace(output, ns, depth);
537 ns = ns->next;
538 }
539}
540
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000541static void
542xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000543 int i;
544 char shift[100];
545
546 for (i = 0;((i < depth) && (i < 25));i++)
547 shift[2 * i] = shift[2 * i + 1] = ' ';
548 shift[2 * i] = shift[2 * i + 1] = 0;
549
550 fprintf(output, shift);
551 switch (ent->etype) {
552 case XML_INTERNAL_GENERAL_ENTITY:
553 fprintf(output, "INTERNAL_GENERAL_ENTITY ");
554 break;
555 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
556 fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
557 break;
558 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
559 fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
560 break;
561 case XML_INTERNAL_PARAMETER_ENTITY:
562 fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
563 break;
564 case XML_EXTERNAL_PARAMETER_ENTITY:
565 fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
566 break;
567 default:
568 fprintf(output, "ENTITY_%d ! ", ent->etype);
569 }
570 fprintf(output, "%s\n", ent->name);
571 if (ent->ExternalID) {
572 fprintf(output, shift);
573 fprintf(output, "ExternalID=%s\n", ent->ExternalID);
574 }
575 if (ent->SystemID) {
576 fprintf(output, shift);
577 fprintf(output, "SystemID=%s\n", ent->SystemID);
578 }
579 if (ent->URI) {
580 fprintf(output, shift);
581 fprintf(output, "URI=%s\n", ent->URI);
582 }
583 if (ent->content) {
584 fprintf(output, shift);
585 fprintf(output, "content=");
586 xmlDebugDumpString(output, ent->content);
587 fprintf(output, "\n");
588 }
589}
590
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000591/**
592 * xmlDebugDumpAttr:
593 * @output: the FILE * for the output
594 * @attr: the attribute
595 * @depth: the indentation level.
596 *
597 * Dumps debug information for the attribute
598 */
599void
600xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000601 int i;
602 char shift[100];
603
604 for (i = 0;((i < depth) && (i < 25));i++)
605 shift[2 * i] = shift[2 * i + 1] = ' ';
606 shift[2 * i] = shift[2 * i + 1] = 0;
607
608 fprintf(output, shift);
609
610 fprintf(output, "ATTRIBUTE ");
611 xmlDebugDumpString(output, attr->name);
612 fprintf(output, "\n");
613 if (attr->children != NULL)
614 xmlDebugDumpNodeList(output, attr->children, depth + 1);
615
616 /*
617 * Do a bit of checking
618 */
619 if (attr->parent == NULL)
620 fprintf(output, "PBM: Attr has no parent\n");
621 if (attr->doc == NULL)
622 fprintf(output, "PBM: Attr has no doc\n");
623 if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
624 fprintf(output, "PBM: Attr doc differs from parent's one\n");
625 if (attr->prev == NULL) {
626 if ((attr->parent != NULL) && (attr->parent->properties != attr))
627 fprintf(output, "PBM: Attr has no prev and not first of list\n");
628 } else {
629 if (attr->prev->next != attr)
630 fprintf(output, "PBM: Attr prev->next : back link wrong\n");
631 }
632 if (attr->next != NULL) {
633 if (attr->next->prev != attr)
634 fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
635 }
636}
637
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000638/**
639 * xmlDebugDumpAttrList:
640 * @output: the FILE * for the output
641 * @attr: the attribute list
642 * @depth: the indentation level.
643 *
644 * Dumps debug information for the attribute list
645 */
646void
647xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
648{
Owen Taylor3473f882001-02-23 17:55:21 +0000649 while (attr != NULL) {
650 xmlDebugDumpAttr(output, attr, depth);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000651 attr = attr->next;
Owen Taylor3473f882001-02-23 17:55:21 +0000652 }
653}
654
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000655/**
656 * xmlDebugDumpOneNode:
657 * @output: the FILE * for the output
658 * @node: the node
659 * @depth: the indentation level.
660 *
661 * Dumps debug information for the element node, it is not recursive
662 */
663void
664xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
665{
Owen Taylor3473f882001-02-23 17:55:21 +0000666 int i;
667 char shift[100];
668
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000669 for (i = 0; ((i < depth) && (i < 25)); i++)
Owen Taylor3473f882001-02-23 17:55:21 +0000670 shift[2 * i] = shift[2 * i + 1] = ' ';
671 shift[2 * i] = shift[2 * i + 1] = 0;
672
673 switch (node->type) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000674 case XML_ELEMENT_NODE:
675 fprintf(output, shift);
676 fprintf(output, "ELEMENT ");
677 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
678 xmlDebugDumpString(output, node->ns->prefix);
679 fprintf(output, ":");
680 }
681 xmlDebugDumpString(output, node->name);
682 fprintf(output, "\n");
683 break;
684 case XML_ATTRIBUTE_NODE:
685 fprintf(output, shift);
686 fprintf(output, "Error, ATTRIBUTE found here\n");
687 break;
688 case XML_TEXT_NODE:
689 fprintf(output, shift);
Daniel Veillardb44025c2001-10-11 22:55:55 +0000690 if (node->name == (const xmlChar *) xmlStringTextNoenc)
Daniel Veillard567e1b42001-08-01 15:53:47 +0000691 fprintf(output, "TEXT no enc\n");
692 else
693 fprintf(output, "TEXT\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000694 break;
695 case XML_CDATA_SECTION_NODE:
696 fprintf(output, shift);
697 fprintf(output, "CDATA_SECTION\n");
698 break;
699 case XML_ENTITY_REF_NODE:
700 fprintf(output, shift);
701 fprintf(output, "ENTITY_REF(%s)\n", node->name);
702 break;
703 case XML_ENTITY_NODE:
704 fprintf(output, shift);
705 fprintf(output, "ENTITY\n");
706 break;
707 case XML_PI_NODE:
708 fprintf(output, shift);
709 fprintf(output, "PI %s\n", node->name);
710 break;
711 case XML_COMMENT_NODE:
712 fprintf(output, shift);
713 fprintf(output, "COMMENT\n");
714 break;
715 case XML_DOCUMENT_NODE:
716 case XML_HTML_DOCUMENT_NODE:
717 fprintf(output, shift);
718 fprintf(output, "Error, DOCUMENT found here\n");
719 break;
720 case XML_DOCUMENT_TYPE_NODE:
721 fprintf(output, shift);
722 fprintf(output, "DOCUMENT_TYPE\n");
723 break;
724 case XML_DOCUMENT_FRAG_NODE:
725 fprintf(output, shift);
726 fprintf(output, "DOCUMENT_FRAG\n");
727 break;
728 case XML_NOTATION_NODE:
729 fprintf(output, shift);
730 fprintf(output, "NOTATION\n");
731 break;
732 case XML_DTD_NODE:
733 xmlDebugDumpDtdNode(output, (xmlDtdPtr) node, depth);
734 return;
735 case XML_ELEMENT_DECL:
736 xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
737 return;
738 case XML_ATTRIBUTE_DECL:
739 xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
740 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000741 case XML_ENTITY_DECL:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000742 xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
743 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000744 case XML_NAMESPACE_DECL:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000745 xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
746 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000747 case XML_XINCLUDE_START:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000748 fprintf(output, shift);
749 fprintf(output, "INCLUDE START\n");
750 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000751 case XML_XINCLUDE_END:
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000752 fprintf(output, shift);
753 fprintf(output, "INCLUDE END\n");
754 return;
755 default:
756 fprintf(output, shift);
757 fprintf(output, "NODE_%d !!!\n", node->type);
758 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000759 }
760 if (node->doc == NULL) {
761 fprintf(output, shift);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000762 fprintf(output, "doc == NULL !!!\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000763 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000764 if (node->nsDef != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000765 xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
766 if (node->properties != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000767 xmlDebugDumpAttrList(output, node->properties, depth + 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000768 if (node->type != XML_ENTITY_REF_NODE) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000769 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
770 shift[2 * i] = shift[2 * i + 1] = ' ';
771 shift[2 * i + 2] = shift[2 * i + 3] = 0;
772 fprintf(output, shift);
773 fprintf(output, "content=");
774#ifndef XML_USE_BUFFER_CONTENT
775 xmlDebugDumpString(output, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000776#else
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000777 xmlDebugDumpString(output, xmlBufferContent(node->content));
Owen Taylor3473f882001-02-23 17:55:21 +0000778#endif
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000779 fprintf(output, "\n");
780 }
Owen Taylor3473f882001-02-23 17:55:21 +0000781 } else {
782 xmlEntityPtr ent;
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000783
784 ent = xmlGetDocEntity(node->doc, node->name);
785 if (ent != NULL)
786 xmlDebugDumpEntity(output, ent, depth + 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000787 }
788 /*
789 * Do a bit of checking
790 */
791 if (node->parent == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000792 fprintf(output, "PBM: Node has no parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000793 if (node->doc == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000794 fprintf(output, "PBM: Node has no doc\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000795 if ((node->parent != NULL) && (node->doc != node->parent->doc))
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000796 fprintf(output, "PBM: Node doc differs from parent's one\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000797 if (node->prev == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000798 if ((node->parent != NULL) && (node->parent->children != node))
799 fprintf(output,
800 "PBM: Node has no prev and not first of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000801 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000802 if (node->prev->next != node)
803 fprintf(output, "PBM: Node prev->next : back link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000804 }
805 if (node->next == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000806 if ((node->parent != NULL) && (node->parent->last != node))
807 fprintf(output,
808 "PBM: Node has no next and not last of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000809 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000810 if (node->next->prev != node)
811 fprintf(output, "PBM: Node next->prev : forward link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000812 }
813}
814
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000815/**
816 * xmlDebugDumpNode:
817 * @output: the FILE * for the output
818 * @node: the node
819 * @depth: the indentation level.
820 *
821 * Dumps debug information for the element node, it is recursive
822 */
823void
824xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
825{
Owen Taylor3473f882001-02-23 17:55:21 +0000826 xmlDebugDumpOneNode(output, node, depth);
827 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000828 xmlDebugDumpNodeList(output, node->children, depth + 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000829}
830
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000831/**
832 * xmlDebugDumpNodeList:
833 * @output: the FILE * for the output
834 * @node: the node list
835 * @depth: the indentation level.
836 *
837 * Dumps debug information for the list of element node, it is recursive
838 */
839void
840xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
841{
Owen Taylor3473f882001-02-23 17:55:21 +0000842 while (node != NULL) {
843 xmlDebugDumpNode(output, node, depth);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000844 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +0000845 }
846}
847
848
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000849/**
850 * xmlDebugDumpDocumentHead:
851 * @output: the FILE * for the output
852 * @doc: the document
853 *
854 * Dumps debug information cncerning the document, not recursive
855 */
856void
857xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
858{
859 if (output == NULL)
860 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +0000861 if (doc == NULL) {
862 fprintf(output, "DOCUMENT == NULL !\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000863 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000864 }
865
866 switch (doc->type) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000867 case XML_ELEMENT_NODE:
868 fprintf(output, "Error, ELEMENT found here ");
869 break;
870 case XML_ATTRIBUTE_NODE:
871 fprintf(output, "Error, ATTRIBUTE found here\n");
872 break;
873 case XML_TEXT_NODE:
874 fprintf(output, "Error, TEXT\n");
875 break;
876 case XML_CDATA_SECTION_NODE:
877 fprintf(output, "Error, CDATA_SECTION\n");
878 break;
879 case XML_ENTITY_REF_NODE:
880 fprintf(output, "Error, ENTITY_REF\n");
881 break;
882 case XML_ENTITY_NODE:
883 fprintf(output, "Error, ENTITY\n");
884 break;
885 case XML_PI_NODE:
886 fprintf(output, "Error, PI\n");
887 break;
888 case XML_COMMENT_NODE:
889 fprintf(output, "Error, COMMENT\n");
890 break;
891 case XML_DOCUMENT_NODE:
892 fprintf(output, "DOCUMENT\n");
893 break;
894 case XML_HTML_DOCUMENT_NODE:
895 fprintf(output, "HTML DOCUMENT\n");
896 break;
897 case XML_DOCUMENT_TYPE_NODE:
898 fprintf(output, "Error, DOCUMENT_TYPE\n");
899 break;
900 case XML_DOCUMENT_FRAG_NODE:
901 fprintf(output, "Error, DOCUMENT_FRAG\n");
902 break;
903 case XML_NOTATION_NODE:
904 fprintf(output, "Error, NOTATION\n");
905 break;
906 default:
907 fprintf(output, "NODE_%d\n", doc->type);
Owen Taylor3473f882001-02-23 17:55:21 +0000908 }
909 if (doc->name != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000910 fprintf(output, "name=");
Owen Taylor3473f882001-02-23 17:55:21 +0000911 xmlDebugDumpString(output, BAD_CAST doc->name);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000912 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000913 }
914 if (doc->version != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000915 fprintf(output, "version=");
Owen Taylor3473f882001-02-23 17:55:21 +0000916 xmlDebugDumpString(output, doc->version);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000917 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000918 }
919 if (doc->encoding != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000920 fprintf(output, "encoding=");
Owen Taylor3473f882001-02-23 17:55:21 +0000921 xmlDebugDumpString(output, doc->encoding);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000923 }
924 if (doc->URL != NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000925 fprintf(output, "URL=");
Owen Taylor3473f882001-02-23 17:55:21 +0000926 xmlDebugDumpString(output, doc->URL);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000927 fprintf(output, "\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000928 }
929 if (doc->standalone)
930 fprintf(output, "standalone=true\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000931 if (doc->oldNs != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000932 xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
933}
934
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000935/**
936 * xmlDebugDumpDocument:
937 * @output: the FILE * for the output
938 * @doc: the document
939 *
940 * Dumps debug information for the document, it's recursive
941 */
942void
943xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
944{
945 if (output == NULL)
946 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +0000947 if (doc == NULL) {
948 fprintf(output, "DOCUMENT == NULL !\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000949 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000950 }
951 xmlDebugDumpDocumentHead(output, doc);
952 if (((doc->type == XML_DOCUMENT_NODE) ||
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000953 (doc->type == XML_HTML_DOCUMENT_NODE)) && (doc->children != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +0000954 xmlDebugDumpNodeList(output, doc->children, 1);
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000955}
Owen Taylor3473f882001-02-23 17:55:21 +0000956
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000957/**
958 * xmlDebugDumpDTD:
959 * @output: the FILE * for the output
960 * @dtd: the DTD
961 *
962 * Dumps debug information for the DTD
963 */
964void
965xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
966{
Owen Taylor3473f882001-02-23 17:55:21 +0000967 if (dtd == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000968 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000969 if (dtd->type != XML_DTD_NODE) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000970 fprintf(output, "PBM: not a DTD\n");
971 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000972 }
973 if (dtd->name != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000974 fprintf(output, "DTD(%s)", dtd->name);
Owen Taylor3473f882001-02-23 17:55:21 +0000975 else
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000976 fprintf(output, "DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000977 if (dtd->ExternalID != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000978 fprintf(output, ", PUBLIC %s", dtd->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +0000979 if (dtd->SystemID != NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000980 fprintf(output, ", SYSTEM %s", dtd->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +0000981 fprintf(output, "\n");
982 /*
983 * Do a bit of checking
984 */
985 if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000986 fprintf(output, "PBM: Dtd doc differs from parent's one\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000987 if (dtd->prev == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000988 if ((dtd->parent != NULL)
989 && (dtd->parent->children != (xmlNodePtr) dtd))
990 fprintf(output,
991 "PBM: Dtd has no prev and not first of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000992 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000993 if (dtd->prev->next != (xmlNodePtr) dtd)
994 fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000995 }
996 if (dtd->next == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000997 if ((dtd->parent != NULL)
998 && (dtd->parent->last != (xmlNodePtr) dtd))
999 fprintf(output, "PBM: Dtd has no next and not last of list\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001000 } else {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001001 if (dtd->next->prev != (xmlNodePtr) dtd)
1002 fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001003 }
1004 if (dtd->children == NULL)
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001005 fprintf(output, " DTD is empty\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001006 else
1007 xmlDebugDumpNodeList(output, dtd->children, 1);
1008}
1009
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001010static void
1011xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output) {
Owen Taylor3473f882001-02-23 17:55:21 +00001012 fprintf(output, "%s : ", cur->name);
1013 switch (cur->etype) {
1014 case XML_INTERNAL_GENERAL_ENTITY:
1015 fprintf(output, "INTERNAL GENERAL, ");
1016 break;
1017 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1018 fprintf(output, "EXTERNAL PARSED, ");
1019 break;
1020 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1021 fprintf(output, "EXTERNAL UNPARSED, ");
1022 break;
1023 case XML_INTERNAL_PARAMETER_ENTITY:
1024 fprintf(output, "INTERNAL PARAMETER, ");
1025 break;
1026 case XML_EXTERNAL_PARAMETER_ENTITY:
1027 fprintf(output, "EXTERNAL PARAMETER, ");
1028 break;
1029 default:
1030 fprintf(output, "UNKNOWN TYPE %d",
1031 cur->etype);
1032 }
1033 if (cur->ExternalID != NULL)
1034 fprintf(output, "ID \"%s\"", cur->ExternalID);
1035 if (cur->SystemID != NULL)
1036 fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
1037 if (cur->orig != NULL)
1038 fprintf(output, "\n orig \"%s\"", cur->orig);
Daniel Veillard7db37732001-07-12 01:20:08 +00001039 if ((cur->type != XML_ELEMENT_NODE) &&
1040 (cur->content != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001041 fprintf(output, "\n content \"%s\"", cur->content);
1042 fprintf(output, "\n");
1043}
1044
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001045/**
1046 * xmlDebugDumpEntities:
1047 * @output: the FILE * for the output
1048 * @doc: the document
1049 *
1050 * Dumps debug information for all the entities in use by the document
1051 */
1052void
1053xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1054{
1055 if (output == NULL)
1056 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00001057 if (doc == NULL) {
1058 fprintf(output, "DOCUMENT == NULL !\n");
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001059 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001060 }
1061
1062 switch (doc->type) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001063 case XML_ELEMENT_NODE:
1064 fprintf(output, "Error, ELEMENT found here ");
1065 break;
1066 case XML_ATTRIBUTE_NODE:
1067 fprintf(output, "Error, ATTRIBUTE found here\n");
1068 break;
1069 case XML_TEXT_NODE:
1070 fprintf(output, "Error, TEXT\n");
1071 break;
1072 case XML_CDATA_SECTION_NODE:
1073 fprintf(output, "Error, CDATA_SECTION\n");
1074 break;
1075 case XML_ENTITY_REF_NODE:
1076 fprintf(output, "Error, ENTITY_REF\n");
1077 break;
1078 case XML_ENTITY_NODE:
1079 fprintf(output, "Error, ENTITY\n");
1080 break;
1081 case XML_PI_NODE:
1082 fprintf(output, "Error, PI\n");
1083 break;
1084 case XML_COMMENT_NODE:
1085 fprintf(output, "Error, COMMENT\n");
1086 break;
1087 case XML_DOCUMENT_NODE:
1088 fprintf(output, "DOCUMENT\n");
1089 break;
1090 case XML_HTML_DOCUMENT_NODE:
1091 fprintf(output, "HTML DOCUMENT\n");
1092 break;
1093 case XML_DOCUMENT_TYPE_NODE:
1094 fprintf(output, "Error, DOCUMENT_TYPE\n");
1095 break;
1096 case XML_DOCUMENT_FRAG_NODE:
1097 fprintf(output, "Error, DOCUMENT_FRAG\n");
1098 break;
1099 case XML_NOTATION_NODE:
1100 fprintf(output, "Error, NOTATION\n");
1101 break;
1102 default:
1103 fprintf(output, "NODE_%d\n", doc->type);
Owen Taylor3473f882001-02-23 17:55:21 +00001104 }
1105 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001106 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1107 doc->intSubset->entities;
1108
1109 fprintf(output, "Entities in internal subset\n");
1110 xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
1111 output);
Owen Taylor3473f882001-02-23 17:55:21 +00001112 } else
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001113 fprintf(output, "No entities in internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001114 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001115 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1116 doc->extSubset->entities;
1117
1118 fprintf(output, "Entities in external subset\n");
1119 xmlHashScan(table, (xmlHashScanner) xmlDebugDumpEntityCallback,
1120 output);
Owen Taylor3473f882001-02-23 17:55:21 +00001121 } else
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001122 fprintf(output, "No entities in external subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001123}
1124
Daniel Veillard78d12092001-10-11 09:12:24 +00001125int xmlLsCountNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001126 int ret = 0;
1127 xmlNodePtr list = NULL;
1128
1129 switch (node->type) {
1130 case XML_ELEMENT_NODE:
1131 list = node->children;
1132 break;
1133 case XML_DOCUMENT_NODE:
1134 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00001135#ifdef LIBXML_DOCB_ENABLED
1136 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00001137#endif
1138 list = ((xmlDocPtr) node)->children;
1139 break;
1140 case XML_ATTRIBUTE_NODE:
1141 list = ((xmlAttrPtr) node)->children;
1142 break;
1143 case XML_TEXT_NODE:
1144 case XML_CDATA_SECTION_NODE:
1145 case XML_PI_NODE:
1146 case XML_COMMENT_NODE:
1147 if (node->content != NULL) {
1148#ifndef XML_USE_BUFFER_CONTENT
1149 ret = xmlStrlen(node->content);
1150#else
1151 ret = xmlBufferLength(node->content);
1152#endif
1153 }
1154 break;
1155 case XML_ENTITY_REF_NODE:
1156 case XML_DOCUMENT_TYPE_NODE:
1157 case XML_ENTITY_NODE:
1158 case XML_DOCUMENT_FRAG_NODE:
1159 case XML_NOTATION_NODE:
1160 case XML_DTD_NODE:
1161 case XML_ELEMENT_DECL:
1162 case XML_ATTRIBUTE_DECL:
1163 case XML_ENTITY_DECL:
1164 case XML_NAMESPACE_DECL:
1165 case XML_XINCLUDE_START:
1166 case XML_XINCLUDE_END:
1167 ret = 1;
1168 break;
1169 }
1170 for (;list != NULL;ret++)
1171 list = list->next;
1172 return(ret);
1173}
1174
Daniel Veillard78d12092001-10-11 09:12:24 +00001175void
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001176xmlLsOneNode(FILE *output, xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001177 switch (node->type) {
1178 case XML_ELEMENT_NODE:
1179 fprintf(output, "-");
1180 break;
1181 case XML_ATTRIBUTE_NODE:
1182 fprintf(output, "a");
1183 break;
1184 case XML_TEXT_NODE:
1185 fprintf(output, "t");
1186 break;
1187 case XML_CDATA_SECTION_NODE:
1188 fprintf(output, "c");
1189 break;
1190 case XML_ENTITY_REF_NODE:
1191 fprintf(output, "e");
1192 break;
1193 case XML_ENTITY_NODE:
1194 fprintf(output, "E");
1195 break;
1196 case XML_PI_NODE:
1197 fprintf(output, "p");
1198 break;
1199 case XML_COMMENT_NODE:
1200 fprintf(output, "c");
1201 break;
1202 case XML_DOCUMENT_NODE:
1203 fprintf(output, "d");
1204 break;
1205 case XML_HTML_DOCUMENT_NODE:
1206 fprintf(output, "h");
1207 break;
1208 case XML_DOCUMENT_TYPE_NODE:
1209 fprintf(output, "T");
1210 break;
1211 case XML_DOCUMENT_FRAG_NODE:
1212 fprintf(output, "F");
1213 break;
1214 case XML_NOTATION_NODE:
1215 fprintf(output, "N");
1216 break;
1217 default:
1218 fprintf(output, "?");
1219 }
1220 if (node->properties != NULL)
1221 fprintf(output, "a");
1222 else
1223 fprintf(output, "-");
1224 if (node->nsDef != NULL)
1225 fprintf(output, "n");
1226 else
1227 fprintf(output, "-");
1228
1229 fprintf(output, " %8d ", xmlLsCountNode(node));
1230
1231 switch (node->type) {
1232 case XML_ELEMENT_NODE:
1233 if (node->name != NULL)
1234 fprintf(output, "%s", node->name);
1235 break;
1236 case XML_ATTRIBUTE_NODE:
1237 if (node->name != NULL)
1238 fprintf(output, "%s", node->name);
1239 break;
1240 case XML_TEXT_NODE:
1241 if (node->content != NULL) {
1242#ifndef XML_USE_BUFFER_CONTENT
1243 xmlDebugDumpString(output, node->content);
1244#else
1245 xmlDebugDumpString(output, xmlBufferContent(node->content));
1246#endif
1247 }
1248 break;
1249 case XML_CDATA_SECTION_NODE:
1250 break;
1251 case XML_ENTITY_REF_NODE:
1252 if (node->name != NULL)
1253 fprintf(output, "%s", node->name);
1254 break;
1255 case XML_ENTITY_NODE:
1256 if (node->name != NULL)
1257 fprintf(output, "%s", node->name);
1258 break;
1259 case XML_PI_NODE:
1260 if (node->name != NULL)
1261 fprintf(output, "%s", node->name);
1262 break;
1263 case XML_COMMENT_NODE:
1264 break;
1265 case XML_DOCUMENT_NODE:
1266 break;
1267 case XML_HTML_DOCUMENT_NODE:
1268 break;
1269 case XML_DOCUMENT_TYPE_NODE:
1270 break;
1271 case XML_DOCUMENT_FRAG_NODE:
1272 break;
1273 case XML_NOTATION_NODE:
1274 break;
1275 default:
1276 if (node->name != NULL)
1277 fprintf(output, "%s", node->name);
1278 }
1279 fprintf(output, "\n");
1280}
1281
Daniel Veillard78d12092001-10-11 09:12:24 +00001282/**
1283 * xmlBoolToText:
Daniel Veillardebd38c52001-11-01 08:38:12 +00001284 * @boolval : a bool to turn into text
Daniel Veillard78d12092001-10-11 09:12:24 +00001285 *
1286 * Convenient way to turn bool into text
1287*/
1288const char *
Daniel Veillardebd38c52001-11-01 08:38:12 +00001289xmlBoolToText(int boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001290{
Daniel Veillardebd38c52001-11-01 08:38:12 +00001291 if (boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001292 return("True");
1293 else
1294 return("False");
1295}
1296
1297
1298/**
1299 * xmlGetLineNo:
1300 * @node : valid node
1301 *
1302 * Get line number of node
1303 *
1304 * Returns the line number if sucessfull, -1 otherwise
1305 */
1306long
1307xmlGetLineNo(xmlNodePtr node)
1308{
1309 long result = -1;
1310
1311 if (!node)
1312 return result;
1313 if (node->type == XML_ELEMENT_NODE)
1314 result = (long) node->content;
1315 else if ((node->prev != NULL) &&
Daniel Veillard66870c72001-11-05 19:27:49 +00001316 ((node->prev->type == XML_ELEMENT_NODE) ||
1317 (node->prev->type == XML_TEXT_NODE)))
1318 result = xmlGetLineNo(node->prev);
Daniel Veillard78d12092001-10-11 09:12:24 +00001319 else if ((node->parent != NULL) &&
Daniel Veillard66870c72001-11-05 19:27:49 +00001320 ((node->parent->type == XML_ELEMENT_NODE) ||
1321 (node->parent->type == XML_TEXT_NODE)))
1322 result = xmlGetLineNo(node->parent);
Daniel Veillard78d12092001-10-11 09:12:24 +00001323
1324 return result;
1325}
1326
Owen Taylor3473f882001-02-23 17:55:21 +00001327/****************************************************************
1328 * *
1329 * The XML shell related functions *
1330 * *
1331 ****************************************************************/
1332
Daniel Veillard78d12092001-10-11 09:12:24 +00001333
1334
Owen Taylor3473f882001-02-23 17:55:21 +00001335/*
1336 * TODO: Improvement/cleanups for the XML shell
1337 * - allow to shell out an editor on a subpart
1338 * - cleanup function registrations (with help) and calling
1339 * - provide registration routines
1340 */
1341
1342/**
Daniel Veillard78d12092001-10-11 09:12:24 +00001343 * xmlShellPrintXpathError:
1344 * @errorType: valid xpath error id
1345 * @arg : the argument that cause xpath to fail
1346 *
1347 * Print the xpath error to libxml default error channel
1348 */
1349void
1350xmlShellPrintXPathError(int errorType, const char *arg)
1351{
1352 const char *default_arg = "Result";
1353
1354 if (!arg)
1355 arg = default_arg;
1356
1357 switch (errorType) {
1358 case XPATH_UNDEFINED:
1359 xmlGenericError(xmlGenericErrorContext,
1360 "%s: no such node\n", arg);
1361 break;
1362
1363 case XPATH_BOOLEAN:
1364 xmlGenericError(xmlGenericErrorContext,
1365 "%s is a Boolean\n", arg);
1366 break;
1367 case XPATH_NUMBER:
1368 xmlGenericError(xmlGenericErrorContext,
1369 "%s is a number\n", arg);
1370 break;
1371 case XPATH_STRING:
1372 xmlGenericError(xmlGenericErrorContext,
1373 "%s is a string\n", arg);
1374 break;
1375 case XPATH_POINT:
1376 xmlGenericError(xmlGenericErrorContext,
1377 "%s is a point\n", arg);
1378 break;
1379 case XPATH_RANGE:
1380 xmlGenericError(xmlGenericErrorContext,
1381 "%s is a range\n", arg);
1382 break;
1383 case XPATH_LOCATIONSET:
1384 xmlGenericError(xmlGenericErrorContext,
1385 "%s is a range\n", arg);
1386 break;
1387 case XPATH_USERS:
1388 xmlGenericError(xmlGenericErrorContext,
1389 "%s is user-defined\n", arg);
1390 break;
1391 case XPATH_XSLT_TREE:
1392 xmlGenericError(xmlGenericErrorContext,
1393 "%s is an XSLT value tree\n", arg);
1394 break;
1395 }
1396 xmlGenericError(xmlGenericErrorContext,
1397 "Try casting the result string function (xpath builtin)\n",
1398 arg);
1399}
1400
1401
1402/**
1403 * xmlShellPrintNode:
1404 * @node : a non-null node to print to stdout
1405 *
1406 * Print node to stdout
1407 */
1408void
1409xmlShellPrintNode(xmlNodePtr node)
1410{
1411 if (!node)
1412 return;
1413
1414 if (node->type == XML_DOCUMENT_NODE)
1415 xmlDocDump(stdout, (xmlDocPtr) node);
1416 else if (node->type == XML_ATTRIBUTE_NODE)
1417 xmlDebugDumpAttrList(stdout, (xmlAttrPtr) node, 0);
1418 else
1419 xmlElemDump(stdout, node->doc, node);
1420
1421 fprintf(stdout, "\n");
1422}
1423
1424
1425/**
1426 * xmlShellPrintXPathResult:
1427 * list : a valid result generated by an xpath evaluation
1428 *
1429 * Prints result to stdout
1430 */
1431void
1432xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1433{
1434 int i = 0;
1435
1436 if (list != NULL) {
1437 switch (list->type) {
1438 case XPATH_NODESET:{
1439 int indx;
1440
1441 if (list->nodesetval) {
1442 for (indx = 0; indx < list->nodesetval->nodeNr;
1443 indx++) {
1444 if (i > 0)
1445 fprintf(stderr, " -------\n");
1446 xmlShellPrintNode(list->nodesetval->
1447 nodeTab[indx]);
1448 }
1449 } else {
1450 xmlGenericError(xmlGenericErrorContext,
1451 "Empty node set\n");
1452 }
1453 break;
1454 }
1455 case XPATH_BOOLEAN:
1456 xmlGenericError(xmlGenericErrorContext,
1457 "Is a Boolean:%s\n",
1458 xmlBoolToText(list->boolval));
1459 break;
1460 case XPATH_NUMBER:
1461 xmlGenericError(xmlGenericErrorContext,
1462 "Is a number:%0g\n", list->floatval);
1463 break;
1464 case XPATH_STRING:
1465 xmlGenericError(xmlGenericErrorContext,
1466 "Is a string:%s\n", list->stringval);
1467 break;
1468
1469 default:
1470 xmlShellPrintXPathError(list->type, NULL);
1471 }
1472 }
1473}
1474
1475/**
Owen Taylor3473f882001-02-23 17:55:21 +00001476 * xmlShellList:
1477 * @ctxt: the shell context
1478 * @arg: unused
1479 * @node: a node
1480 * @node2: unused
1481 *
1482 * Implements the XML shell function "ls"
1483 * Does an Unix like listing of the given node (like a directory)
1484 *
1485 * Returns 0
1486 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001487int
1488xmlShellList(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1489 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1490 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1491{
Owen Taylor3473f882001-02-23 17:55:21 +00001492 xmlNodePtr cur;
1493
1494 if ((node->type == XML_DOCUMENT_NODE) ||
1495 (node->type == XML_HTML_DOCUMENT_NODE)) {
1496 cur = ((xmlDocPtr) node)->children;
1497 } else if (node->children != NULL) {
1498 cur = node->children;
1499 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00001500 xmlLsOneNode(stdout, node);
1501 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001502 }
1503 while (cur != NULL) {
Daniel Veillard78d12092001-10-11 09:12:24 +00001504 xmlLsOneNode(stdout, cur);
1505 cur = cur->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001506 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001507 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001508}
1509
1510/**
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001511 * xmlShellBase:
1512 * @ctxt: the shell context
1513 * @arg: unused
1514 * @node: a node
1515 * @node2: unused
1516 *
1517 * Implements the XML shell function "base"
1518 * dumps the current XML base of the node
1519 *
1520 * Returns 0
1521 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001522int
1523xmlShellBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1524 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1525 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1526{
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001527 xmlChar *base;
1528
1529 base = xmlNodeGetBase(node->doc, node);
1530
1531 if (base == NULL) {
Daniel Veillardcd337f02001-11-22 18:20:37 +00001532 fprintf(stdout, " No base found !!!\n");
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001533 } else {
Daniel Veillardcd337f02001-11-22 18:20:37 +00001534 fprintf(stdout, "%s\n", base);
Daniel Veillard78d12092001-10-11 09:12:24 +00001535 xmlFree(base);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001536 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001537 return (0);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001538}
1539
1540/**
Owen Taylor3473f882001-02-23 17:55:21 +00001541 * xmlShellDir:
1542 * @ctxt: the shell context
1543 * @arg: unused
1544 * @node: a node
1545 * @node2: unused
1546 *
1547 * Implements the XML shell function "dir"
1548 * dumps informations about the node (namespace, attributes, content).
1549 *
1550 * Returns 0
1551 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001552int
1553xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1554 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1555 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1556{
Owen Taylor3473f882001-02-23 17:55:21 +00001557 if ((node->type == XML_DOCUMENT_NODE) ||
1558 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00001559 xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
Owen Taylor3473f882001-02-23 17:55:21 +00001560 } else if (node->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard78d12092001-10-11 09:12:24 +00001561 xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001562 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00001563 xmlDebugDumpOneNode(stdout, node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001564 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001565 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001566}
1567
1568/**
1569 * xmlShellCat:
1570 * @ctxt: the shell context
1571 * @arg: unused
1572 * @node: a node
1573 * @node2: unused
1574 *
1575 * Implements the XML shell function "cat"
1576 * dumps the serialization node content (XML or HTML).
1577 *
1578 * Returns 0
1579 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001580int
1581xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
1582 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1583{
Owen Taylor3473f882001-02-23 17:55:21 +00001584 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
1585#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001586 if (node->type == XML_HTML_DOCUMENT_NODE)
1587 htmlDocDump(stdout, (htmlDocPtr) node);
1588 else
1589 htmlNodeDumpFile(stdout, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001590#else
Daniel Veillard78d12092001-10-11 09:12:24 +00001591 if (node->type == XML_DOCUMENT_NODE)
1592 xmlDocDump(stdout, (xmlDocPtr) node);
1593 else
1594 xmlElemDump(stdout, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001595#endif /* LIBXML_HTML_ENABLED */
1596 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00001597 if (node->type == XML_DOCUMENT_NODE)
1598 xmlDocDump(stdout, (xmlDocPtr) node);
1599 else
1600 xmlElemDump(stdout, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001601 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00001602 fprintf(stdout, "\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00001603 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001604}
1605
1606/**
1607 * xmlShellLoad:
1608 * @ctxt: the shell context
1609 * @filename: the file name
1610 * @node: unused
1611 * @node2: unused
1612 *
1613 * Implements the XML shell function "load"
1614 * loads a new document specified by the filename
1615 *
1616 * Returns 0 or -1 if loading failed
1617 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001618int
1619xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
1620 xmlNodePtr node ATTRIBUTE_UNUSED,
1621 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1622{
Owen Taylor3473f882001-02-23 17:55:21 +00001623 xmlDocPtr doc;
1624 int html = 0;
1625
1626 if (ctxt->doc != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00001627 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00001628
1629 if (html) {
1630#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001631 doc = htmlParseFile(filename, NULL);
1632#else
Daniel Veillardcd337f02001-11-22 18:20:37 +00001633 fprintf(stdout, "HTML support not compiled in\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00001634 doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001635#endif /* LIBXML_HTML_ENABLED */
1636 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00001637 doc = xmlParseFile(filename);
Owen Taylor3473f882001-02-23 17:55:21 +00001638 }
1639 if (doc != NULL) {
1640 if (ctxt->loaded == 1) {
Daniel Veillard78d12092001-10-11 09:12:24 +00001641 xmlFreeDoc(ctxt->doc);
1642 }
1643 ctxt->loaded = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001644#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001645 xmlXPathFreeContext(ctxt->pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001646#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001647 xmlFree(ctxt->filename);
1648 ctxt->doc = doc;
1649 ctxt->node = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001650#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001651 ctxt->pctxt = xmlXPathNewContext(doc);
Owen Taylor3473f882001-02-23 17:55:21 +00001652#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001653 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
Owen Taylor3473f882001-02-23 17:55:21 +00001654 } else
Daniel Veillard78d12092001-10-11 09:12:24 +00001655 return (-1);
1656 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001657}
1658
1659/**
1660 * xmlShellWrite:
1661 * @ctxt: the shell context
1662 * @filename: the file name
1663 * @node: a node in the tree
1664 * @node2: unused
1665 *
1666 * Implements the XML shell function "write"
1667 * Write the current node to the filename, it saves the serailization
1668 * of the subtree under the @node specified
1669 *
1670 * Returns 0 or -1 in case of error
1671 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001672int
Owen Taylor3473f882001-02-23 17:55:21 +00001673xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
Daniel Veillard78d12092001-10-11 09:12:24 +00001674 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1675{
Owen Taylor3473f882001-02-23 17:55:21 +00001676 if (node == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00001677 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001678 if ((filename == NULL) || (filename[0] == 0)) {
1679 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00001680 "Write command requires a filename argument\n");
1681 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001682 }
1683#ifdef W_OK
1684 if (access((char *) filename, W_OK)) {
1685 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00001686 "Cannot write to %s\n", filename);
1687 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001688 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001689#endif
1690 switch (node->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00001691 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00001692 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1693 xmlGenericError(xmlGenericErrorContext,
1694 "Failed to write to %s\n", filename);
1695 return (-1);
1696 }
1697 break;
Owen Taylor3473f882001-02-23 17:55:21 +00001698 case XML_HTML_DOCUMENT_NODE:
1699#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001700 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1701 xmlGenericError(xmlGenericErrorContext,
1702 "Failed to write to %s\n", filename);
1703 return (-1);
1704 }
Owen Taylor3473f882001-02-23 17:55:21 +00001705#else
Daniel Veillard78d12092001-10-11 09:12:24 +00001706 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
1707 xmlGenericError(xmlGenericErrorContext,
1708 "Failed to write to %s\n", filename);
1709 return (-1);
1710 }
Owen Taylor3473f882001-02-23 17:55:21 +00001711#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001712 break;
1713 default:{
1714 FILE *f;
Owen Taylor3473f882001-02-23 17:55:21 +00001715
Daniel Veillard78d12092001-10-11 09:12:24 +00001716 f = fopen((char *) filename, "w");
1717 if (f == NULL) {
1718 xmlGenericError(xmlGenericErrorContext,
1719 "Failed to write to %s\n", filename);
1720 return (-1);
1721 }
1722 xmlElemDump(f, ctxt->doc, node);
1723 fclose(f);
1724 }
Owen Taylor3473f882001-02-23 17:55:21 +00001725 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001726 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001727}
1728
1729/**
1730 * xmlShellSave:
1731 * @ctxt: the shell context
1732 * @filename: the file name (optionnal)
1733 * @node: unused
1734 * @node2: unused
1735 *
1736 * Implements the XML shell function "save"
1737 * Write the current document to the filename, or it's original name
1738 *
1739 * Returns 0 or -1 in case of error
1740 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001741int
1742xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
1743 xmlNodePtr node ATTRIBUTE_UNUSED,
1744 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1745{
Owen Taylor3473f882001-02-23 17:55:21 +00001746 if (ctxt->doc == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00001747 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001748 if ((filename == NULL) || (filename[0] == 0))
1749 filename = ctxt->filename;
1750#ifdef W_OK
1751 if (access((char *) filename, W_OK)) {
1752 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00001753 "Cannot save to %s\n", filename);
1754 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001755 }
1756#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00001757 switch (ctxt->doc->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00001758 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00001759 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1760 xmlGenericError(xmlGenericErrorContext,
1761 "Failed to save to %s\n", filename);
1762 }
1763 break;
Owen Taylor3473f882001-02-23 17:55:21 +00001764 case XML_HTML_DOCUMENT_NODE:
1765#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001766 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
1767 xmlGenericError(xmlGenericErrorContext,
1768 "Failed to save to %s\n", filename);
1769 }
Owen Taylor3473f882001-02-23 17:55:21 +00001770#else
Daniel Veillard78d12092001-10-11 09:12:24 +00001771 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
1772 xmlGenericError(xmlGenericErrorContext,
1773 "Failed to save to %s\n", filename);
1774 }
Owen Taylor3473f882001-02-23 17:55:21 +00001775#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001776 break;
1777 default:
1778 xmlGenericError(xmlGenericErrorContext,
1779 "To save to subparts of a document use the 'write' command\n");
1780 return (-1);
1781
Owen Taylor3473f882001-02-23 17:55:21 +00001782 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001783 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001784}
1785
1786/**
1787 * xmlShellValidate:
1788 * @ctxt: the shell context
1789 * @dtd: the DTD URI (optionnal)
1790 * @node: unused
1791 * @node2: unused
1792 *
1793 * Implements the XML shell function "validate"
1794 * Validate the document, if a DTD path is provided, then the validation
1795 * is done against the given DTD.
1796 *
1797 * Returns 0 or -1 in case of error
1798 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001799int
1800xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
1801 xmlNodePtr node ATTRIBUTE_UNUSED,
1802 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1803{
Owen Taylor3473f882001-02-23 17:55:21 +00001804 xmlValidCtxt vctxt;
1805 int res = -1;
1806
1807 vctxt.userData = stderr;
1808 vctxt.error = (xmlValidityErrorFunc) fprintf;
1809 vctxt.warning = (xmlValidityWarningFunc) fprintf;
1810
1811 if ((dtd == NULL) || (dtd[0] == 0)) {
1812 res = xmlValidateDocument(&vctxt, ctxt->doc);
1813 } else {
1814 xmlDtdPtr subset;
1815
Daniel Veillard78d12092001-10-11 09:12:24 +00001816 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
1817 if (subset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001818 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
1819
Daniel Veillard78d12092001-10-11 09:12:24 +00001820 xmlFreeDtd(subset);
1821 }
Owen Taylor3473f882001-02-23 17:55:21 +00001822 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001823 return (res);
Owen Taylor3473f882001-02-23 17:55:21 +00001824}
1825
1826/**
1827 * xmlShellDu:
1828 * @ctxt: the shell context
1829 * @arg: unused
1830 * @tree: a node defining a subtree
1831 * @node2: unused
1832 *
1833 * Implements the XML shell function "du"
1834 * show the structure of the subtree under node @tree
1835 * If @tree is null, the command works on the current node.
1836 *
1837 * Returns 0 or -1 in case of error
1838 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001839int
1840xmlShellDu(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1841 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
1842 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1843{
Owen Taylor3473f882001-02-23 17:55:21 +00001844 xmlNodePtr node;
Daniel Veillard78d12092001-10-11 09:12:24 +00001845 int indent = 0, i;
Owen Taylor3473f882001-02-23 17:55:21 +00001846
Daniel Veillard78d12092001-10-11 09:12:24 +00001847 if (tree == NULL)
1848 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001849 node = tree;
1850 while (node != NULL) {
1851 if ((node->type == XML_DOCUMENT_NODE) ||
1852 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcd337f02001-11-22 18:20:37 +00001853 fprintf(stdout, "/\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00001854 } else if (node->type == XML_ELEMENT_NODE) {
1855 for (i = 0; i < indent; i++)
Daniel Veillardcd337f02001-11-22 18:20:37 +00001856 fprintf(stdout, " ");
1857 fprintf(stdout, "%s\n", node->name);
Daniel Veillard78d12092001-10-11 09:12:24 +00001858 } else {
1859 }
Owen Taylor3473f882001-02-23 17:55:21 +00001860
Daniel Veillard78d12092001-10-11 09:12:24 +00001861 /*
1862 * Browse the full subtree, deep first
1863 */
Owen Taylor3473f882001-02-23 17:55:21 +00001864
1865 if ((node->type == XML_DOCUMENT_NODE) ||
1866 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00001867 node = ((xmlDocPtr) node)->children;
1868 } else if ((node->children != NULL)
1869 && (node->type != XML_ENTITY_REF_NODE)) {
1870 /* deep first */
1871 node = node->children;
1872 indent++;
1873 } else if ((node != tree) && (node->next != NULL)) {
1874 /* then siblings */
1875 node = node->next;
1876 } else if (node != tree) {
1877 /* go up to parents->next if needed */
1878 while (node != tree) {
1879 if (node->parent != NULL) {
1880 node = node->parent;
1881 indent--;
1882 }
1883 if ((node != tree) && (node->next != NULL)) {
1884 node = node->next;
1885 break;
1886 }
1887 if (node->parent == NULL) {
1888 node = NULL;
1889 break;
1890 }
1891 if (node == tree) {
1892 node = NULL;
1893 break;
1894 }
1895 }
1896 /* exit condition */
1897 if (node == tree)
1898 node = NULL;
1899 } else
1900 node = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001901 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001902 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001903}
1904
1905/**
1906 * xmlShellPwd:
1907 * @ctxt: the shell context
1908 * @buffer: the output buffer
1909 * @tree: a node
1910 * @node2: unused
1911 *
1912 * Implements the XML shell function "pwd"
1913 * Show the full path from the root to the node, if needed building
1914 * thumblers when similar elements exists at a given ancestor level.
1915 * The output is compatible with XPath commands.
1916 *
1917 * Returns 0 or -1 in case of error
1918 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001919int
1920xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
1921 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1922{
Daniel Veillardc6e013a2001-11-10 10:08:57 +00001923 xmlChar *path;
Owen Taylor3473f882001-02-23 17:55:21 +00001924
Daniel Veillard78d12092001-10-11 09:12:24 +00001925 if (node == NULL)
1926 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001927
Daniel Veillardc6e013a2001-11-10 10:08:57 +00001928 path = xmlGetNodePath(node);
1929 if (path == NULL)
1930 return (-1);
1931
1932 /*
1933 * This test prevents buffer overflow, because this routine
1934 * is only called by xmlShell, in which the second argument is
1935 * 500 chars long.
1936 * It is a dirty hack before a cleaner solution is found.
1937 * Documentation should mention that the second argument must
1938 * be at least 500 chars long, and could be stripped if too long.
1939 */
1940 snprintf(buffer, 499, "%s", path);
1941 buffer[499] = '0';
1942 xmlFree(path);
1943
Daniel Veillard78d12092001-10-11 09:12:24 +00001944 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001945}
1946
1947/**
1948 * xmlShell
1949 * @doc: the initial document
1950 * @filename: the output buffer
1951 * @input: the line reading function
1952 * @output: the output FILE*
1953 *
1954 * Implements the XML shell
1955 * This allow to load, validate, view, modify and save a document
1956 * using a environment similar to a UNIX commandline.
1957 */
1958void
1959xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
Daniel Veillard78d12092001-10-11 09:12:24 +00001960 FILE * output)
1961{
Owen Taylor3473f882001-02-23 17:55:21 +00001962 char prompt[500] = "/ > ";
1963 char *cmdline = NULL, *cur;
1964 int nbargs;
1965 char command[100];
1966 char arg[400];
1967 int i;
1968 xmlShellCtxtPtr ctxt;
1969 xmlXPathObjectPtr list;
1970
1971 if (doc == NULL)
1972 return;
1973 if (filename == NULL)
1974 return;
1975 if (input == NULL)
1976 return;
1977 if (output == NULL)
1978 return;
1979 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
Daniel Veillard78d12092001-10-11 09:12:24 +00001980 if (ctxt == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00001981 return;
1982 ctxt->loaded = 0;
1983 ctxt->doc = doc;
1984 ctxt->input = input;
1985 ctxt->output = output;
1986 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
Daniel Veillard78d12092001-10-11 09:12:24 +00001987 ctxt->node = (xmlNodePtr) ctxt->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001988
1989#ifdef LIBXML_XPATH_ENABLED
1990 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1991 if (ctxt->pctxt == NULL) {
Daniel Veillard78d12092001-10-11 09:12:24 +00001992 xmlFree(ctxt);
1993 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001994 }
1995#endif /* LIBXML_XPATH_ENABLED */
1996 while (1) {
1997 if (ctxt->node == (xmlNodePtr) ctxt->doc)
Daniel Veillard78d12092001-10-11 09:12:24 +00001998 sprintf(prompt, "%s > ", "/");
1999 else if (ctxt->node->name)
2000 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002001 else
Daniel Veillard78d12092001-10-11 09:12:24 +00002002 sprintf(prompt, "? > ");
Owen Taylor3473f882001-02-23 17:55:21 +00002003 prompt[sizeof(prompt) - 1] = 0;
2004
Daniel Veillard78d12092001-10-11 09:12:24 +00002005 /*
2006 * Get a new command line
2007 */
Owen Taylor3473f882001-02-23 17:55:21 +00002008 cmdline = ctxt->input(prompt);
Daniel Veillard78d12092001-10-11 09:12:24 +00002009 if (cmdline == NULL)
2010 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002011
Daniel Veillard78d12092001-10-11 09:12:24 +00002012 /*
2013 * Parse the command itself
2014 */
2015 cur = cmdline;
2016 nbargs = 0;
2017 while ((*cur == ' ') || (*cur == '\t'))
2018 cur++;
2019 i = 0;
2020 while ((*cur != ' ') && (*cur != '\t') &&
2021 (*cur != '\n') && (*cur != '\r')) {
2022 if (*cur == 0)
2023 break;
2024 command[i++] = *cur++;
2025 }
2026 command[i] = 0;
2027 if (i == 0)
2028 continue;
2029 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002030
Daniel Veillard78d12092001-10-11 09:12:24 +00002031 /*
2032 * Parse the argument
2033 */
2034 while ((*cur == ' ') || (*cur == '\t'))
2035 cur++;
2036 i = 0;
2037 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2038 if (*cur == 0)
2039 break;
2040 arg[i++] = *cur++;
2041 }
2042 arg[i] = 0;
2043 if (i != 0)
2044 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002045
Daniel Veillard78d12092001-10-11 09:12:24 +00002046 /*
2047 * start interpreting the command
2048 */
Owen Taylor3473f882001-02-23 17:55:21 +00002049 if (!strcmp(command, "exit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002050 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002051 if (!strcmp(command, "quit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002052 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002053 if (!strcmp(command, "bye"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002054 break;
Daniel Veillard5004f422001-11-08 13:53:05 +00002055 if (!strcmp(command, "help")) {
Daniel Veillardcd337f02001-11-22 18:20:37 +00002056 fprintf(stdout, "\tbase display XML base of the node\n");
2057 fprintf(stdout, "\tbye leave shell\n");
2058 fprintf(stdout, "\tcat [node] display node or current node\n");
2059 fprintf(stdout, "\tcd [path] change directory to path or to root\n");
2060 fprintf(stdout, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n");
2061 fprintf(stdout, "\tdu [path] show the structure of the subtree under path or the current node\n");
2062 fprintf(stdout, "\texit leave shell\n");
2063 fprintf(stdout, "\thelp display this help\n");
2064 fprintf(stdout, "\tfree display memory usage\n");
2065 fprintf(stdout, "\tload [name] load a new document with name\n");
2066 fprintf(stdout, "\tls [path] list contents of path or the current directory\n");
2067 fprintf(stdout, "\tpwd display current working directory\n");
2068 fprintf(stdout, "\tquit leave shell\n");
2069 fprintf(stdout, "\tsave [name] save this document to name or the original name\n");
2070 fprintf(stdout, "\tvalidate check the document for errors\n");
2071 fprintf(stdout, "\twrite [name] write the current node to the filename\n");
Daniel Veillard5004f422001-11-08 13:53:05 +00002072 } else if (!strcmp(command, "validate")) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002073 xmlShellValidate(ctxt, arg, NULL, NULL);
2074 } else if (!strcmp(command, "load")) {
2075 xmlShellLoad(ctxt, arg, NULL, NULL);
2076 } else if (!strcmp(command, "save")) {
2077 xmlShellSave(ctxt, arg, NULL, NULL);
2078 } else if (!strcmp(command, "write")) {
2079 xmlShellWrite(ctxt, arg, NULL, NULL);
2080 } else if (!strcmp(command, "free")) {
2081 if (arg[0] == 0) {
2082 xmlMemShow(stdout, 0);
2083 } else {
2084 int len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002085
Daniel Veillard78d12092001-10-11 09:12:24 +00002086 sscanf(arg, "%d", &len);
2087 xmlMemShow(stdout, len);
2088 }
2089 } else if (!strcmp(command, "pwd")) {
2090 char dir[500];
Owen Taylor3473f882001-02-23 17:55:21 +00002091
Daniel Veillard78d12092001-10-11 09:12:24 +00002092 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
Daniel Veillardcd337f02001-11-22 18:20:37 +00002093 fprintf(stdout, "%s\n", dir);
Daniel Veillard78d12092001-10-11 09:12:24 +00002094 } else if (!strcmp(command, "du")) {
2095 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2096 } else if (!strcmp(command, "base")) {
2097 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
2098 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2099 int dir = (!strcmp(command, "dir"));
2100
2101 if (arg[0] == 0) {
2102 if (dir)
2103 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
2104 else
2105 xmlShellList(ctxt, NULL, ctxt->node, NULL);
2106 } else {
2107 ctxt->pctxt->node = ctxt->node;
Daniel Veillard61d80a22001-04-27 17:13:01 +00002108#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002109 ctxt->pctxt->node = ctxt->node;
2110 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2111#else
2112 list = NULL;
2113#endif /* LIBXML_XPATH_ENABLED */
2114 if (list != NULL) {
2115 switch (list->type) {
2116 case XPATH_UNDEFINED:
2117 xmlGenericError(xmlGenericErrorContext,
2118 "%s: no such node\n", arg);
2119 break;
2120 case XPATH_NODESET:{
2121 int indx;
2122
Daniel Veillarda6825e82001-11-07 13:33:59 +00002123 if (list->nodesetval == NULL)
2124 break;
2125
Daniel Veillard78d12092001-10-11 09:12:24 +00002126 for (indx = 0;
2127 indx < list->nodesetval->nodeNr;
2128 indx++) {
2129 if (dir)
2130 xmlShellDir(ctxt, NULL,
2131 list->nodesetval->
2132 nodeTab[indx], NULL);
2133 else
2134 xmlShellList(ctxt, NULL,
2135 list->nodesetval->
2136 nodeTab[indx], NULL);
2137 }
2138 break;
2139 }
2140 case XPATH_BOOLEAN:
2141 xmlGenericError(xmlGenericErrorContext,
2142 "%s is a Boolean\n", arg);
2143 break;
2144 case XPATH_NUMBER:
2145 xmlGenericError(xmlGenericErrorContext,
2146 "%s is a number\n", arg);
2147 break;
2148 case XPATH_STRING:
2149 xmlGenericError(xmlGenericErrorContext,
2150 "%s is a string\n", arg);
2151 break;
2152 case XPATH_POINT:
2153 xmlGenericError(xmlGenericErrorContext,
2154 "%s is a point\n", arg);
2155 break;
2156 case XPATH_RANGE:
2157 xmlGenericError(xmlGenericErrorContext,
2158 "%s is a range\n", arg);
2159 break;
2160 case XPATH_LOCATIONSET:
2161 xmlGenericError(xmlGenericErrorContext,
2162 "%s is a range\n", arg);
2163 break;
2164 case XPATH_USERS:
2165 xmlGenericError(xmlGenericErrorContext,
2166 "%s is user-defined\n", arg);
2167 break;
2168 case XPATH_XSLT_TREE:
2169 xmlGenericError(xmlGenericErrorContext,
2170 "%s is an XSLT value tree\n",
2171 arg);
2172 break;
2173 }
2174#ifdef LIBXML_XPATH_ENABLED
2175 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00002176#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002177 } else {
2178 xmlGenericError(xmlGenericErrorContext,
2179 "%s: no such node\n", arg);
2180 }
2181 ctxt->pctxt->node = NULL;
2182 }
2183 } else if (!strcmp(command, "cd")) {
2184 if (arg[0] == 0) {
2185 ctxt->node = (xmlNodePtr) ctxt->doc;
2186 } else {
2187#ifdef LIBXML_XPATH_ENABLED
2188 ctxt->pctxt->node = ctxt->node;
2189 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2190#else
2191 list = NULL;
2192#endif /* LIBXML_XPATH_ENABLED */
2193 if (list != NULL) {
2194 switch (list->type) {
2195 case XPATH_UNDEFINED:
2196 xmlGenericError(xmlGenericErrorContext,
2197 "%s: no such node\n", arg);
2198 break;
2199 case XPATH_NODESET:
Daniel Veillarda6825e82001-11-07 13:33:59 +00002200 if (list->nodesetval != NULL) {
2201 if (list->nodesetval->nodeNr == 1) {
2202 ctxt->node = list->nodesetval->nodeTab[0];
2203 } else
2204 xmlGenericError(xmlGenericErrorContext,
2205 "%s is a %d Node Set\n",
2206 arg,
2207 list->nodesetval->nodeNr);
Daniel Veillard78d12092001-10-11 09:12:24 +00002208 } else
2209 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6825e82001-11-07 13:33:59 +00002210 "%s is an empty Node Set\n",
2211 arg);
Daniel Veillard78d12092001-10-11 09:12:24 +00002212 break;
2213 case XPATH_BOOLEAN:
2214 xmlGenericError(xmlGenericErrorContext,
2215 "%s is a Boolean\n", arg);
2216 break;
2217 case XPATH_NUMBER:
2218 xmlGenericError(xmlGenericErrorContext,
2219 "%s is a number\n", arg);
2220 break;
2221 case XPATH_STRING:
2222 xmlGenericError(xmlGenericErrorContext,
2223 "%s is a string\n", arg);
2224 break;
2225 case XPATH_POINT:
2226 xmlGenericError(xmlGenericErrorContext,
2227 "%s is a point\n", arg);
2228 break;
2229 case XPATH_RANGE:
2230 xmlGenericError(xmlGenericErrorContext,
2231 "%s is a range\n", arg);
2232 break;
2233 case XPATH_LOCATIONSET:
2234 xmlGenericError(xmlGenericErrorContext,
2235 "%s is a range\n", arg);
2236 break;
2237 case XPATH_USERS:
2238 xmlGenericError(xmlGenericErrorContext,
2239 "%s is user-defined\n", arg);
2240 break;
2241 case XPATH_XSLT_TREE:
2242 xmlGenericError(xmlGenericErrorContext,
2243 "%s is an XSLT value tree\n",
2244 arg);
2245 break;
2246 }
2247#ifdef LIBXML_XPATH_ENABLED
2248 xmlXPathFreeObject(list);
2249#endif
2250 } else {
2251 xmlGenericError(xmlGenericErrorContext,
2252 "%s: no such node\n", arg);
2253 }
2254 ctxt->pctxt->node = NULL;
2255 }
2256 } else if (!strcmp(command, "cat")) {
2257 if (arg[0] == 0) {
2258 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
2259 } else {
2260 ctxt->pctxt->node = ctxt->node;
2261#ifdef LIBXML_XPATH_ENABLED
2262 ctxt->pctxt->node = ctxt->node;
2263 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2264#else
2265 list = NULL;
2266#endif /* LIBXML_XPATH_ENABLED */
2267 if (list != NULL) {
2268 switch (list->type) {
2269 case XPATH_UNDEFINED:
2270 xmlGenericError(xmlGenericErrorContext,
2271 "%s: no such node\n", arg);
2272 break;
2273 case XPATH_NODESET:{
2274 int indx;
2275
Daniel Veillarda6825e82001-11-07 13:33:59 +00002276 if (list->nodesetval == NULL)
2277 break;
2278
Daniel Veillard78d12092001-10-11 09:12:24 +00002279 for (indx = 0;
2280 indx < list->nodesetval->nodeNr;
2281 indx++) {
2282 if (i > 0)
Daniel Veillardcd337f02001-11-22 18:20:37 +00002283 fprintf(stdout, " -------\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002284 xmlShellCat(ctxt, NULL,
2285 list->nodesetval->
2286 nodeTab[indx], NULL);
2287 }
2288 break;
2289 }
2290 case XPATH_BOOLEAN:
2291 xmlGenericError(xmlGenericErrorContext,
2292 "%s is a Boolean\n", arg);
2293 break;
2294 case XPATH_NUMBER:
2295 xmlGenericError(xmlGenericErrorContext,
2296 "%s is a number\n", arg);
2297 break;
2298 case XPATH_STRING:
2299 xmlGenericError(xmlGenericErrorContext,
2300 "%s is a string\n", arg);
2301 break;
2302 case XPATH_POINT:
2303 xmlGenericError(xmlGenericErrorContext,
2304 "%s is a point\n", arg);
2305 break;
2306 case XPATH_RANGE:
2307 xmlGenericError(xmlGenericErrorContext,
2308 "%s is a range\n", arg);
2309 break;
2310 case XPATH_LOCATIONSET:
2311 xmlGenericError(xmlGenericErrorContext,
2312 "%s is a range\n", arg);
2313 break;
2314 case XPATH_USERS:
2315 xmlGenericError(xmlGenericErrorContext,
2316 "%s is user-defined\n", arg);
2317 break;
2318 case XPATH_XSLT_TREE:
2319 xmlGenericError(xmlGenericErrorContext,
2320 "%s is an XSLT value tree\n",
2321 arg);
2322 break;
2323 }
2324#ifdef LIBXML_XPATH_ENABLED
2325 xmlXPathFreeObject(list);
2326#endif
2327 } else {
2328 xmlGenericError(xmlGenericErrorContext,
2329 "%s: no such node\n", arg);
2330 }
2331 ctxt->pctxt->node = NULL;
2332 }
2333 } else {
2334 xmlGenericError(xmlGenericErrorContext,
2335 "Unknown command %s\n", command);
2336 }
2337 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00002338 }
2339#ifdef LIBXML_XPATH_ENABLED
2340 xmlXPathFreeContext(ctxt->pctxt);
2341#endif /* LIBXML_XPATH_ENABLED */
2342 if (ctxt->loaded) {
2343 xmlFreeDoc(ctxt->doc);
2344 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002345 if (ctxt->filename != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002346 xmlFree(ctxt->filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002347 xmlFree(ctxt);
2348 if (cmdline != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002349 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00002350}
2351
2352#endif /* LIBXML_DEBUG_ENABLED */