blob: 372847002cd1209ffd715393c33985a6bad5c1cd [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
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012#ifdef LIBXML_DEBUG_ENABLED
13
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18#ifdef HAVE_STRING_H
19#include <string.h>
20#endif
21#include <libxml/xmlmemory.h>
22#include <libxml/tree.h>
23#include <libxml/parser.h>
Daniel Veillard567e1b42001-08-01 15:53:47 +000024#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000025#include <libxml/valid.h>
26#include <libxml/debugXML.h>
27#include <libxml/HTMLtree.h>
28#include <libxml/HTMLparser.h>
29#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000030#include <libxml/globals.h>
Daniel Veillard0ba59232002-02-10 13:20:39 +000031#include <libxml/xpathInternals.h>
Igor Zlatkovicc06bb622003-04-27 15:59:00 +000032#include <libxml/uri.h>
Daniel Veillard522bc602004-02-21 11:53:09 +000033#ifdef LIBXML_SCHEMAS_ENABLED
34#include <libxml/relaxng.h>
35#endif
Owen Taylor3473f882001-02-23 17:55:21 +000036
Daniel Veillard22cdb842004-10-04 14:09:17 +000037typedef struct _xmlDebugCtxt xmlDebugCtxt;
38typedef xmlDebugCtxt *xmlDebugCtxtPtr;
39struct _xmlDebugCtxt {
40 FILE *output; /* the output file */
41 char shift[101]; /* used for indenting */
42 int depth; /* current depth */
43 xmlDocPtr doc; /* current document */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000044 xmlNodePtr node; /* current node */
Daniel Veillard22cdb842004-10-04 14:09:17 +000045 int check; /* do just checkings */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000046 int errors; /* number of errors found */
Daniel Veillard22cdb842004-10-04 14:09:17 +000047};
48
49static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
50
51static void
52xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
53{
54 int i;
55
56 ctxt->depth = 0;
57 ctxt->check = 0;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000058 ctxt->errors = 0;
Daniel Veillard22cdb842004-10-04 14:09:17 +000059 ctxt->output = stdout;
60 for (i = 0; i < 100; i++)
61 ctxt->shift[i] = ' ';
62 ctxt->shift[100] = 0;
63}
64
65static void
Daniel Veillard76821142004-10-09 20:39:04 +000066xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt)
67{
Daniel Veillard76821142004-10-09 20:39:04 +000068}
69
70/**
Daniel Veillard0d24b112004-10-11 12:28:34 +000071 * xmlNsCheckScope:
72 * @node: the node
73 * @ns: the namespace node
Daniel Veillard76821142004-10-09 20:39:04 +000074 *
Daniel Veillard0d24b112004-10-11 12:28:34 +000075 * Check that a given namespace is in scope on a node.
Daniel Veillard76821142004-10-09 20:39:04 +000076 *
Daniel Veillard0d24b112004-10-11 12:28:34 +000077 * Returns 1 if in scope, -1 in case of argument error,
78 * -2 if the namespace is not in scope, and -3 if not on
79 * an ancestor node.
Daniel Veillard76821142004-10-09 20:39:04 +000080 */
81static int
Daniel Veillard0d24b112004-10-11 12:28:34 +000082xmlNsCheckScope(xmlNodePtr node, xmlNsPtr ns)
Daniel Veillard76821142004-10-09 20:39:04 +000083{
Daniel Veillard0d24b112004-10-11 12:28:34 +000084 xmlNsPtr cur;
Daniel Veillard76821142004-10-09 20:39:04 +000085
Daniel Veillard0d24b112004-10-11 12:28:34 +000086 if ((node == NULL) || (ns == NULL))
87 return(-1);
88
89 if ((node->type != XML_ELEMENT_NODE) &&
90 (node->type != XML_ATTRIBUTE_NODE) &&
91 (node->type != XML_DOCUMENT_NODE) &&
92 (node->type != XML_TEXT_NODE) &&
93 (node->type != XML_HTML_DOCUMENT_NODE) &&
94 (node->type != XML_XINCLUDE_START))
95 return(-2);
96
97 while ((node != NULL) &&
98 ((node->type == XML_ELEMENT_NODE) ||
99 (node->type == XML_ATTRIBUTE_NODE) ||
100 (node->type == XML_TEXT_NODE) ||
101 (node->type == XML_XINCLUDE_START))) {
102 if ((node->type == XML_ELEMENT_NODE) ||
103 (node->type == XML_XINCLUDE_START)) {
104 cur = node->nsDef;
105 while (cur != NULL) {
106 if (cur == ns)
107 return(1);
108 if (xmlStrEqual(cur->prefix, ns->prefix))
109 return(-2);
110 cur = cur->next;
111 }
Daniel Veillard76821142004-10-09 20:39:04 +0000112 }
Daniel Veillard0d24b112004-10-11 12:28:34 +0000113 node = node->parent;
Daniel Veillard76821142004-10-09 20:39:04 +0000114 }
Daniel Veillard0d24b112004-10-11 12:28:34 +0000115 /* the xml namespace may be declared on the document node */
116 if ((node != NULL) &&
117 ((node->type == XML_DOCUMENT_NODE) ||
118 (node->type == XML_HTML_DOCUMENT_NODE))) {
119 xmlNsPtr oldNs = ((xmlDocPtr) node)->oldNs;
120 if (oldNs == ns)
121 return(1);
122 }
123 return(-3);
Daniel Veillard76821142004-10-09 20:39:04 +0000124}
Daniel Veillard76821142004-10-09 20:39:04 +0000125
Daniel Veillard76821142004-10-09 20:39:04 +0000126static void
Daniel Veillard22cdb842004-10-04 14:09:17 +0000127xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
128{
129 if (ctxt->check)
130 return;
131 if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
132 if (ctxt->depth < 50)
133 fprintf(ctxt->output, &ctxt->shift[100 - 2 * ctxt->depth]);
134 else
135 fprintf(ctxt->output, ctxt->shift);
136 }
137}
138
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000139/**
140 * xmlDebugErr:
141 * @ctxt: a debug context
142 * @error: the error code
143 *
144 * Handle a debug error.
145 */
146static void
147xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
148{
149 ctxt->errors++;
150 __xmlRaiseError(NULL, NULL, NULL,
151 NULL, ctxt->node, XML_FROM_CHECK,
152 error, XML_ERR_ERROR, NULL, 0,
153 NULL, NULL, NULL, 0, 0,
154 msg);
155}
156static void
157xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra)
158{
159 ctxt->errors++;
160 __xmlRaiseError(NULL, NULL, NULL,
161 NULL, ctxt->node, XML_FROM_CHECK,
162 error, XML_ERR_ERROR, NULL, 0,
163 NULL, NULL, NULL, 0, 0,
164 msg, extra);
165}
166static void
167xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, char *extra)
168{
169 ctxt->errors++;
170 __xmlRaiseError(NULL, NULL, NULL,
171 NULL, ctxt->node, XML_FROM_CHECK,
172 error, XML_ERR_ERROR, NULL, 0,
173 NULL, NULL, NULL, 0, 0,
174 msg, extra);
175}
176
Daniel Veillard0d24b112004-10-11 12:28:34 +0000177/**
178 * xmlCtxtNsCheckScope:
179 * @ctxt: the debugging context
180 * @node: the node
181 * @ns: the namespace node
182 *
183 * Report if a given namespace is is not in scope.
184 */
185static void
186xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt, xmlNodePtr node, xmlNsPtr ns)
187{
188 int ret;
189
190 ret = xmlNsCheckScope(node, ns);
191 if (ret == -2) {
192 if (ns->prefix == NULL)
193 xmlDebugErr(ctxt, XML_CHECK_NS_SCOPE,
194 "Reference to default namespace not in scope\n");
195 else
196 xmlDebugErr3(ctxt, XML_CHECK_NS_SCOPE,
197 "Reference to namespace '%s' not in scope\n",
198 (char *) ns->prefix);
199 }
200 if (ret == -3) {
201 if (ns->prefix == NULL)
202 xmlDebugErr(ctxt, XML_CHECK_NS_ANCESTOR,
203 "Reference to default namespace not on ancestor\n");
204 else
205 xmlDebugErr3(ctxt, XML_CHECK_NS_ANCESTOR,
206 "Reference to namespace '%s' not on ancestor\n",
207 (char *) ns->prefix);
208 }
209}
210
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000211static void
212xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
213 if (node->parent == NULL)
214 xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
215 "Node has no parent\n");
216 if (node->doc == NULL)
217 xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
218 "Node has no doc\n");
219 if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
220 (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
221 xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
222 "Node doc differs from parent's one\n");
223 if (node->prev == NULL) {
224 if (node->type == XML_ATTRIBUTE_NODE) {
225 if ((node->parent != NULL) &&
226 (node != (xmlNodePtr) node->parent->properties))
227 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
228 "Attr has no prev and not first of attr list\n");
229
230 } else if ((node->parent != NULL) && (node->parent->children != node))
231 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
232 "Node has no prev and not first of parent list\n");
233 } else {
234 if (node->prev->next != node)
235 xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
236 "Node prev->next : back link wrong\n");
237 }
238 if (node->next == NULL) {
239 if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
240 (node->parent->last != node))
241 xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
242 "Node has no next and not last of parent list\n");
243 } else {
244 if (node->next->prev != node)
245 xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
246 "Node next->prev : forward link wrong\n");
Daniel Veillard0d24b112004-10-11 12:28:34 +0000247 if (node->next->parent != node->parent)
248 xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT,
249 "Node next->prev : forward link wrong\n");
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000250 }
Daniel Veillard0d24b112004-10-11 12:28:34 +0000251 if (node->type == XML_ELEMENT_NODE) {
252 xmlNsPtr ns;
253
254 ns = node->nsDef;
255 while (ns != NULL) {
256 xmlCtxtNsCheckScope(ctxt, node, ns);
257 ns = ns->next;
258 }
259 if (node->ns != NULL)
260 xmlCtxtNsCheckScope(ctxt, node, node->ns);
261 } else if (node->type == XML_ATTRIBUTE_NODE) {
262 if (node->ns != NULL)
263 xmlCtxtNsCheckScope(ctxt, node, node->ns);
264 }
265
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000266}
267
Daniel Veillard22cdb842004-10-04 14:09:17 +0000268static void
269xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
270{
271 int i;
272
273 if (ctxt->check)
274 return;
275 /* TODO: check UTF8 content of the string */
276 if (str == NULL) {
277 fprintf(ctxt->output, "(NULL)");
278 return;
279 }
280 for (i = 0; i < 40; i++)
281 if (str[i] == 0)
282 return;
283 else if (IS_BLANK_CH(str[i]))
284 fputc(' ', ctxt->output);
285 else if (str[i] >= 0x80)
286 fprintf(ctxt->output, "#%X", str[i]);
287 else
288 fputc(str[i], ctxt->output);
289 fprintf(ctxt->output, "...");
290}
291
292static void
293xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
294{
295 xmlCtxtDumpSpaces(ctxt);
296
297 if (dtd == NULL) {
298 if (!ctxt->check)
299 fprintf(ctxt->output, "DTD node is NULL\n");
300 return;
301 }
302
303 if (dtd->type != XML_DTD_NODE) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000304 xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
305 "Node is not a DTD");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000306 return;
307 }
308 if (!ctxt->check) {
309 if (dtd->name != NULL)
310 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
311 else
312 fprintf(ctxt->output, "DTD");
313 if (dtd->ExternalID != NULL)
314 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
315 if (dtd->SystemID != NULL)
316 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
317 fprintf(ctxt->output, "\n");
318 }
319 /*
320 * Do a bit of checking
321 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000322 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000323}
324
325static void
326xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
327{
328 xmlCtxtDumpSpaces(ctxt);
329
330 if (attr == NULL) {
331 if (!ctxt->check)
332 fprintf(ctxt->output, "Attribute declaration is NULL\n");
333 return;
334 }
335 if (attr->type != XML_ATTRIBUTE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000336 xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
337 "Node is not an attribute declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000338 return;
339 }
340 if (attr->name != NULL) {
341 if (!ctxt->check)
342 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
343 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000344 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
345 "Node attribute declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000346 if (attr->elem != NULL) {
347 if (!ctxt->check)
348 fprintf(ctxt->output, " for %s", (char *) attr->elem);
349 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000350 xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
351 "Node attribute declaration has no element name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000352 if (!ctxt->check) {
353 switch (attr->atype) {
354 case XML_ATTRIBUTE_CDATA:
355 fprintf(ctxt->output, " CDATA");
356 break;
357 case XML_ATTRIBUTE_ID:
358 fprintf(ctxt->output, " ID");
359 break;
360 case XML_ATTRIBUTE_IDREF:
361 fprintf(ctxt->output, " IDREF");
362 break;
363 case XML_ATTRIBUTE_IDREFS:
364 fprintf(ctxt->output, " IDREFS");
365 break;
366 case XML_ATTRIBUTE_ENTITY:
367 fprintf(ctxt->output, " ENTITY");
368 break;
369 case XML_ATTRIBUTE_ENTITIES:
370 fprintf(ctxt->output, " ENTITIES");
371 break;
372 case XML_ATTRIBUTE_NMTOKEN:
373 fprintf(ctxt->output, " NMTOKEN");
374 break;
375 case XML_ATTRIBUTE_NMTOKENS:
376 fprintf(ctxt->output, " NMTOKENS");
377 break;
378 case XML_ATTRIBUTE_ENUMERATION:
379 fprintf(ctxt->output, " ENUMERATION");
380 break;
381 case XML_ATTRIBUTE_NOTATION:
382 fprintf(ctxt->output, " NOTATION ");
383 break;
384 }
385 if (attr->tree != NULL) {
386 int indx;
387 xmlEnumerationPtr cur = attr->tree;
388
389 for (indx = 0; indx < 5; indx++) {
390 if (indx != 0)
391 fprintf(ctxt->output, "|%s", (char *) cur->name);
392 else
393 fprintf(ctxt->output, " (%s", (char *) cur->name);
394 cur = cur->next;
395 if (cur == NULL)
396 break;
397 }
398 if (cur == NULL)
399 fprintf(ctxt->output, ")");
400 else
401 fprintf(ctxt->output, "...)");
402 }
403 switch (attr->def) {
404 case XML_ATTRIBUTE_NONE:
405 break;
406 case XML_ATTRIBUTE_REQUIRED:
407 fprintf(ctxt->output, " REQUIRED");
408 break;
409 case XML_ATTRIBUTE_IMPLIED:
410 fprintf(ctxt->output, " IMPLIED");
411 break;
412 case XML_ATTRIBUTE_FIXED:
413 fprintf(ctxt->output, " FIXED");
414 break;
415 }
416 if (attr->defaultValue != NULL) {
417 fprintf(ctxt->output, "\"");
418 xmlCtxtDumpString(ctxt, attr->defaultValue);
419 fprintf(ctxt->output, "\"");
420 }
421 fprintf(ctxt->output, "\n");
422 }
423
424 /*
425 * Do a bit of checking
426 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000427 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000428}
429
430static void
431xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
432{
433 xmlCtxtDumpSpaces(ctxt);
434
435 if (elem == NULL) {
436 if (!ctxt->check)
437 fprintf(ctxt->output, "Element declaration is NULL\n");
438 return;
439 }
440 if (elem->type != XML_ELEMENT_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000441 xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
442 "Node is not an element declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000443 return;
444 }
445 if (elem->name != NULL) {
446 if (!ctxt->check) {
447 fprintf(ctxt->output, "ELEMDECL(");
448 xmlCtxtDumpString(ctxt, elem->name);
449 fprintf(ctxt->output, ")");
450 }
451 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000452 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
453 "Element declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000454 if (!ctxt->check) {
455 switch (elem->etype) {
456 case XML_ELEMENT_TYPE_UNDEFINED:
457 fprintf(ctxt->output, ", UNDEFINED");
458 break;
459 case XML_ELEMENT_TYPE_EMPTY:
460 fprintf(ctxt->output, ", EMPTY");
461 break;
462 case XML_ELEMENT_TYPE_ANY:
463 fprintf(ctxt->output, ", ANY");
464 break;
465 case XML_ELEMENT_TYPE_MIXED:
466 fprintf(ctxt->output, ", MIXED ");
467 break;
468 case XML_ELEMENT_TYPE_ELEMENT:
469 fprintf(ctxt->output, ", MIXED ");
470 break;
471 }
472 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
473 char buf[5001];
474
475 buf[0] = 0;
476 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
477 buf[5000] = 0;
478 fprintf(ctxt->output, "%s", buf);
479 }
480 fprintf(ctxt->output, "\n");
481 }
482
483 /*
484 * Do a bit of checking
485 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000486 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000487}
488
489static void
490xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
491{
492 xmlCtxtDumpSpaces(ctxt);
493
494 if (ent == NULL) {
495 if (!ctxt->check)
496 fprintf(ctxt->output, "Entity declaration is NULL\n");
497 return;
498 }
499 if (ent->type != XML_ENTITY_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000500 xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
501 "Node is not an entity declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000502 return;
503 }
504 if (ent->name != NULL) {
505 if (!ctxt->check) {
506 fprintf(ctxt->output, "ENTITYDECL(");
507 xmlCtxtDumpString(ctxt, ent->name);
508 fprintf(ctxt->output, ")");
509 }
510 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000511 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
512 "Entity declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000513 if (!ctxt->check) {
514 switch (ent->etype) {
515 case XML_INTERNAL_GENERAL_ENTITY:
516 fprintf(ctxt->output, ", internal\n");
517 break;
518 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
519 fprintf(ctxt->output, ", external parsed\n");
520 break;
521 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
522 fprintf(ctxt->output, ", unparsed\n");
523 break;
524 case XML_INTERNAL_PARAMETER_ENTITY:
525 fprintf(ctxt->output, ", parameter\n");
526 break;
527 case XML_EXTERNAL_PARAMETER_ENTITY:
528 fprintf(ctxt->output, ", external parameter\n");
529 break;
530 case XML_INTERNAL_PREDEFINED_ENTITY:
531 fprintf(ctxt->output, ", predefined\n");
532 break;
533 }
534 if (ent->ExternalID) {
535 xmlCtxtDumpSpaces(ctxt);
536 fprintf(ctxt->output, " ExternalID=%s\n",
537 (char *) ent->ExternalID);
538 }
539 if (ent->SystemID) {
540 xmlCtxtDumpSpaces(ctxt);
541 fprintf(ctxt->output, " SystemID=%s\n",
542 (char *) ent->SystemID);
543 }
544 if (ent->URI != NULL) {
545 xmlCtxtDumpSpaces(ctxt);
546 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
547 }
548 if (ent->content) {
549 xmlCtxtDumpSpaces(ctxt);
550 fprintf(ctxt->output, " content=");
551 xmlCtxtDumpString(ctxt, ent->content);
552 fprintf(ctxt->output, "\n");
553 }
554 }
555
556 /*
557 * Do a bit of checking
558 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000559 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000560}
561
562static void
563xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
564{
565 xmlCtxtDumpSpaces(ctxt);
566
567 if (ns == NULL) {
568 if (!ctxt->check)
569 fprintf(ctxt->output, "namespace node is NULL\n");
570 return;
571 }
572 if (ns->type != XML_NAMESPACE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000573 xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
574 "Node is not a namespace declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000575 return;
576 }
577 if (ns->href == NULL) {
578 if (ns->prefix != NULL)
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000579 xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
580 "Incomplete namespace %s href=NULL\n",
Daniel Veillard22cdb842004-10-04 14:09:17 +0000581 (char *) ns->prefix);
582 else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000583 xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
584 "Incomplete default namespace href=NULL\n");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000585 } else {
586 if (!ctxt->check) {
587 if (ns->prefix != NULL)
588 fprintf(ctxt->output, "namespace %s href=",
589 (char *) ns->prefix);
590 else
591 fprintf(ctxt->output, "default namespace href=");
592
593 xmlCtxtDumpString(ctxt, ns->href);
594 fprintf(ctxt->output, "\n");
595 }
596 }
597}
598
599static void
600xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
601{
602 while (ns != NULL) {
603 xmlCtxtDumpNamespace(ctxt, ns);
604 ns = ns->next;
605 }
606}
607
608static void
609xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
610{
611 xmlCtxtDumpSpaces(ctxt);
612
613 if (ent == NULL) {
614 if (!ctxt->check)
615 fprintf(ctxt->output, "Entity is NULL\n");
616 return;
617 }
618 if (!ctxt->check) {
619 switch (ent->etype) {
620 case XML_INTERNAL_GENERAL_ENTITY:
621 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
622 break;
623 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
624 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
625 break;
626 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
627 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
628 break;
629 case XML_INTERNAL_PARAMETER_ENTITY:
630 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
631 break;
632 case XML_EXTERNAL_PARAMETER_ENTITY:
633 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
634 break;
635 default:
636 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
637 }
638 fprintf(ctxt->output, "%s\n", ent->name);
639 if (ent->ExternalID) {
640 xmlCtxtDumpSpaces(ctxt);
641 fprintf(ctxt->output, "ExternalID=%s\n",
642 (char *) ent->ExternalID);
643 }
644 if (ent->SystemID) {
645 xmlCtxtDumpSpaces(ctxt);
646 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
647 }
648 if (ent->URI) {
649 xmlCtxtDumpSpaces(ctxt);
650 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
651 }
652 if (ent->content) {
653 xmlCtxtDumpSpaces(ctxt);
654 fprintf(ctxt->output, "content=");
655 xmlCtxtDumpString(ctxt, ent->content);
656 fprintf(ctxt->output, "\n");
657 }
658 }
659}
660
661/**
662 * xmlCtxtDumpAttr:
663 * @output: the FILE * for the output
664 * @attr: the attribute
665 * @depth: the indentation level.
666 *
667 * Dumps debug information for the attribute
668 */
669static void
670xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
671{
672 xmlCtxtDumpSpaces(ctxt);
673
674 if (attr == NULL) {
675 if (!ctxt->check)
676 fprintf(ctxt->output, "Attr is NULL");
677 return;
678 }
679 if (!ctxt->check) {
680 fprintf(ctxt->output, "ATTRIBUTE ");
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000681 xmlCtxtDumpString(ctxt, attr->name);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000682 fprintf(ctxt->output, "\n");
683 if (attr->children != NULL) {
684 ctxt->depth++;
685 xmlCtxtDumpNodeList(ctxt, attr->children);
686 ctxt->depth--;
687 }
688 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000689 if (attr->name == NULL)
690 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
691 "Attribute has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000692
693 /*
694 * Do a bit of checking
695 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000696 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000697}
698
699/**
700 * xmlCtxtDumpAttrList:
701 * @output: the FILE * for the output
702 * @attr: the attribute list
703 * @depth: the indentation level.
704 *
705 * Dumps debug information for the attribute list
706 */
707static void
708xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
709{
710 while (attr != NULL) {
711 xmlCtxtDumpAttr(ctxt, attr);
712 attr = attr->next;
713 }
714}
715
716/**
717 * xmlCtxtDumpOneNode:
718 * @output: the FILE * for the output
719 * @node: the node
720 * @depth: the indentation level.
721 *
722 * Dumps debug information for the element node, it is not recursive
723 */
724static void
725xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
726{
727 if (node == NULL) {
728 if (!ctxt->check) {
729 xmlCtxtDumpSpaces(ctxt);
730 fprintf(ctxt->output, "node is NULL\n");
731 }
732 return;
733 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000734 ctxt->node = node;
735
Daniel Veillard22cdb842004-10-04 14:09:17 +0000736 switch (node->type) {
737 case XML_ELEMENT_NODE:
738 if (!ctxt->check) {
739 xmlCtxtDumpSpaces(ctxt);
740 fprintf(ctxt->output, "ELEMENT ");
741 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
742 xmlCtxtDumpString(ctxt, node->ns->prefix);
743 fprintf(ctxt->output, ":");
744 }
745 xmlCtxtDumpString(ctxt, node->name);
746 fprintf(ctxt->output, "\n");
747 }
748 break;
749 case XML_ATTRIBUTE_NODE:
750 if (!ctxt->check)
751 xmlCtxtDumpSpaces(ctxt);
752 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
753 break;
754 case XML_TEXT_NODE:
755 if (!ctxt->check) {
756 xmlCtxtDumpSpaces(ctxt);
757 if (node->name == (const xmlChar *) xmlStringTextNoenc)
758 fprintf(ctxt->output, "TEXT no enc\n");
759 else
760 fprintf(ctxt->output, "TEXT\n");
761 }
762 break;
763 case XML_CDATA_SECTION_NODE:
764 if (!ctxt->check) {
765 xmlCtxtDumpSpaces(ctxt);
766 fprintf(ctxt->output, "CDATA_SECTION\n");
767 }
768 break;
769 case XML_ENTITY_REF_NODE:
770 if (!ctxt->check) {
771 xmlCtxtDumpSpaces(ctxt);
772 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
773 (char *) node->name);
774 }
775 break;
776 case XML_ENTITY_NODE:
777 if (!ctxt->check) {
778 xmlCtxtDumpSpaces(ctxt);
779 fprintf(ctxt->output, "ENTITY\n");
780 }
781 break;
782 case XML_PI_NODE:
783 if (!ctxt->check) {
784 xmlCtxtDumpSpaces(ctxt);
785 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
786 }
787 break;
788 case XML_COMMENT_NODE:
789 if (!ctxt->check) {
790 xmlCtxtDumpSpaces(ctxt);
791 fprintf(ctxt->output, "COMMENT\n");
792 }
793 break;
794 case XML_DOCUMENT_NODE:
795 case XML_HTML_DOCUMENT_NODE:
796 if (!ctxt->check) {
797 xmlCtxtDumpSpaces(ctxt);
798 }
799 fprintf(ctxt->output, "PBM: DOCUMENT found here\n");
800 break;
801 case XML_DOCUMENT_TYPE_NODE:
802 if (!ctxt->check) {
803 xmlCtxtDumpSpaces(ctxt);
804 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
805 }
806 break;
807 case XML_DOCUMENT_FRAG_NODE:
808 if (!ctxt->check) {
809 xmlCtxtDumpSpaces(ctxt);
810 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
811 }
812 break;
813 case XML_NOTATION_NODE:
814 if (!ctxt->check) {
815 xmlCtxtDumpSpaces(ctxt);
816 fprintf(ctxt->output, "NOTATION\n");
817 }
818 break;
819 case XML_DTD_NODE:
820 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
821 return;
822 case XML_ELEMENT_DECL:
823 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
824 return;
825 case XML_ATTRIBUTE_DECL:
826 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
827 return;
828 case XML_ENTITY_DECL:
829 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
830 return;
831 case XML_NAMESPACE_DECL:
832 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
833 return;
834 case XML_XINCLUDE_START:
835 if (!ctxt->check) {
836 xmlCtxtDumpSpaces(ctxt);
837 fprintf(ctxt->output, "INCLUDE START\n");
838 }
839 return;
840 case XML_XINCLUDE_END:
841 if (!ctxt->check) {
842 xmlCtxtDumpSpaces(ctxt);
843 fprintf(ctxt->output, "INCLUDE END\n");
844 }
845 return;
846 default:
847 if (!ctxt->check)
848 xmlCtxtDumpSpaces(ctxt);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000849 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
850 "Unknown node type %d\n", node->type);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000851 return;
852 }
853 if (node->doc == NULL) {
854 if (!ctxt->check) {
855 xmlCtxtDumpSpaces(ctxt);
856 }
857 fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
858 }
859 ctxt->depth++;
860 if (node->nsDef != NULL)
861 xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
862 if (node->properties != NULL)
863 xmlCtxtDumpAttrList(ctxt, node->properties);
864 if (node->type != XML_ENTITY_REF_NODE) {
865 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
866 if (!ctxt->check) {
867 xmlCtxtDumpSpaces(ctxt);
868 fprintf(ctxt->output, "content=");
869 xmlCtxtDumpString(ctxt, node->content);
870 fprintf(ctxt->output, "\n");
871 }
872 }
873 } else {
874 xmlEntityPtr ent;
875
876 ent = xmlGetDocEntity(node->doc, node->name);
877 if (ent != NULL)
878 xmlCtxtDumpEntity(ctxt, ent);
879 }
880 ctxt->depth--;
881
882 /*
883 * Do a bit of checking
884 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000885 xmlCtxtGenericNodeCheck(ctxt, node);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000886}
887
888/**
889 * xmlCtxtDumpNode:
890 * @output: the FILE * for the output
891 * @node: the node
892 * @depth: the indentation level.
893 *
894 * Dumps debug information for the element node, it is recursive
895 */
896static void
897xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
898{
899 if (node == NULL) {
900 if (!ctxt->check) {
901 xmlCtxtDumpSpaces(ctxt);
902 fprintf(ctxt->output, "node is NULL\n");
903 }
904 return;
905 }
906 xmlCtxtDumpOneNode(ctxt, node);
907 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
908 ctxt->depth++;
909 xmlCtxtDumpNodeList(ctxt, node->children);
910 ctxt->depth--;
911 }
912}
913
914/**
915 * xmlCtxtDumpNodeList:
916 * @output: the FILE * for the output
917 * @node: the node list
918 * @depth: the indentation level.
919 *
920 * Dumps debug information for the list of element node, it is recursive
921 */
922static void
923xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
924{
925 while (node != NULL) {
926 xmlCtxtDumpNode(ctxt, node);
927 node = node->next;
928 }
929}
930
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000931static void
932xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
933{
934 if (doc == NULL) {
935 if (!ctxt->check)
936 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
937 return;
938 }
939 ctxt->node = (xmlNodePtr) doc;
940
941 switch (doc->type) {
942 case XML_ELEMENT_NODE:
943 xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
944 "Misplaced ELEMENT node\n");
945 break;
946 case XML_ATTRIBUTE_NODE:
947 xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
948 "Misplaced ATTRIBUTE node\n");
949 break;
950 case XML_TEXT_NODE:
951 xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
952 "Misplaced TEXT node\n");
953 break;
954 case XML_CDATA_SECTION_NODE:
955 xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
956 "Misplaced CDATA node\n");
957 break;
958 case XML_ENTITY_REF_NODE:
959 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
960 "Misplaced ENTITYREF node\n");
961 break;
962 case XML_ENTITY_NODE:
963 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
964 "Misplaced ENTITY node\n");
965 break;
966 case XML_PI_NODE:
967 xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
968 "Misplaced PI node\n");
969 break;
970 case XML_COMMENT_NODE:
971 xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
972 "Misplaced COMMENT node\n");
973 break;
974 case XML_DOCUMENT_NODE:
975 if (!ctxt->check)
976 fprintf(ctxt->output, "DOCUMENT\n");
977 break;
978 case XML_HTML_DOCUMENT_NODE:
979 if (!ctxt->check)
980 fprintf(ctxt->output, "HTML DOCUMENT\n");
981 break;
982 case XML_DOCUMENT_TYPE_NODE:
983 xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
984 "Misplaced DOCTYPE node\n");
985 break;
986 case XML_DOCUMENT_FRAG_NODE:
987 xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
988 "Misplaced FRAGMENT node\n");
989 break;
990 case XML_NOTATION_NODE:
991 xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
992 "Misplaced NOTATION node\n");
993 break;
994 default:
995 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
996 "Unknown node type %d\n", doc->type);
997 }
998}
Daniel Veillard22cdb842004-10-04 14:09:17 +0000999
1000/**
1001 * xmlCtxtDumpDocumentHead:
1002 * @output: the FILE * for the output
1003 * @doc: the document
1004 *
1005 * Dumps debug information cncerning the document, not recursive
1006 */
1007static void
1008xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1009{
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001010 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001011 if (!ctxt->check) {
1012 if (doc->name != NULL) {
1013 fprintf(ctxt->output, "name=");
1014 xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
1015 fprintf(ctxt->output, "\n");
1016 }
1017 if (doc->version != NULL) {
1018 fprintf(ctxt->output, "version=");
1019 xmlCtxtDumpString(ctxt, doc->version);
1020 fprintf(ctxt->output, "\n");
1021 }
1022 if (doc->encoding != NULL) {
1023 fprintf(ctxt->output, "encoding=");
1024 xmlCtxtDumpString(ctxt, doc->encoding);
1025 fprintf(ctxt->output, "\n");
1026 }
1027 if (doc->URL != NULL) {
1028 fprintf(ctxt->output, "URL=");
1029 xmlCtxtDumpString(ctxt, doc->URL);
1030 fprintf(ctxt->output, "\n");
1031 }
1032 if (doc->standalone)
1033 fprintf(ctxt->output, "standalone=true\n");
1034 }
1035 if (doc->oldNs != NULL)
1036 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
1037}
1038
1039/**
1040 * xmlCtxtDumpDocument:
1041 * @output: the FILE * for the output
1042 * @doc: the document
1043 *
1044 * Dumps debug information for the document, it's recursive
1045 */
1046static void
1047xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1048{
1049 if (doc == NULL) {
1050 if (!ctxt->check)
1051 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1052 return;
1053 }
1054 xmlCtxtDumpDocumentHead(ctxt, doc);
1055 if (((doc->type == XML_DOCUMENT_NODE) ||
1056 (doc->type == XML_HTML_DOCUMENT_NODE))
1057 && (doc->children != NULL)) {
1058 ctxt->depth++;
1059 xmlCtxtDumpNodeList(ctxt, doc->children);
1060 ctxt->depth--;
1061 }
1062}
1063
1064static void
1065xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt)
1066{
1067 if (cur == NULL) {
1068 if (!ctxt->check)
1069 fprintf(ctxt->output, "Entity is NULL");
1070 return;
1071 }
1072 if (!ctxt->check) {
1073 fprintf(ctxt->output, "%s : ", (char *) cur->name);
1074 switch (cur->etype) {
1075 case XML_INTERNAL_GENERAL_ENTITY:
1076 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1077 break;
1078 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1079 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1080 break;
1081 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1082 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1083 break;
1084 case XML_INTERNAL_PARAMETER_ENTITY:
1085 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1086 break;
1087 case XML_EXTERNAL_PARAMETER_ENTITY:
1088 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1089 break;
1090 default:
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001091 xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1092 "Unknown entity type %d\n", cur->etype);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001093 }
1094 if (cur->ExternalID != NULL)
1095 fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1096 if (cur->SystemID != NULL)
1097 fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1098 if (cur->orig != NULL)
1099 fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1100 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1101 fprintf(ctxt->output, "\n content \"%s\"",
1102 (char *) cur->content);
1103 fprintf(ctxt->output, "\n");
1104 }
1105}
1106
1107/**
1108 * xmlCtxtDumpEntities:
1109 * @output: the FILE * for the output
1110 * @doc: the document
1111 *
1112 * Dumps debug information for all the entities in use by the document
1113 */
1114static void
1115xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1116{
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001117 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001118 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1119 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1120 doc->intSubset->entities;
1121
1122 if (!ctxt->check)
1123 fprintf(ctxt->output, "Entities in internal subset\n");
1124 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1125 ctxt);
1126 } else
1127 fprintf(ctxt->output, "No entities in internal subset\n");
1128 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1129 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1130 doc->extSubset->entities;
1131
1132 if (!ctxt->check)
1133 fprintf(ctxt->output, "Entities in external subset\n");
1134 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1135 ctxt);
1136 } else if (!ctxt->check)
1137 fprintf(ctxt->output, "No entities in external subset\n");
1138}
1139
1140/**
1141 * xmlCtxtDumpDTD:
1142 * @output: the FILE * for the output
1143 * @dtd: the DTD
1144 *
1145 * Dumps debug information for the DTD
1146 */
1147static void
1148xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1149{
1150 if (dtd == NULL) {
1151 if (!ctxt->check)
1152 fprintf(ctxt->output, "DTD is NULL\n");
1153 return;
1154 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001155 xmlCtxtDumpDtdNode(ctxt, dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001156 if (dtd->children == NULL)
1157 fprintf(ctxt->output, " DTD is empty\n");
1158 else {
1159 ctxt->depth++;
1160 xmlCtxtDumpNodeList(ctxt, dtd->children);
1161 ctxt->depth--;
1162 }
1163}
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001164
Daniel Veillard22cdb842004-10-04 14:09:17 +00001165/************************************************************************
1166 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001167 * Public entry points for dump *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001168 * *
1169 ************************************************************************/
1170
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001171/**
1172 * xmlDebugDumpString:
1173 * @output: the FILE * for the output
1174 * @str: the string
1175 *
1176 * Dumps informations about the string, shorten it if necessary
1177 */
1178void
1179xmlDebugDumpString(FILE * output, const xmlChar * str)
1180{
Owen Taylor3473f882001-02-23 17:55:21 +00001181 int i;
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001182
Daniel Veillard7db38712002-02-07 16:39:11 +00001183 if (output == NULL)
1184 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00001185 if (str == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001186 fprintf(output, "(NULL)");
1187 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001188 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001189 for (i = 0; i < 40; i++)
1190 if (str[i] == 0)
1191 return;
William M. Brack76e95df2003-10-18 16:20:14 +00001192 else if (IS_BLANK_CH(str[i]))
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001193 fputc(' ', output);
1194 else if (str[i] >= 0x80)
1195 fprintf(output, "#%X", str[i]);
1196 else
1197 fputc(str[i], output);
Owen Taylor3473f882001-02-23 17:55:21 +00001198 fprintf(output, "...");
1199}
1200
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001201/**
1202 * xmlDebugDumpAttr:
1203 * @output: the FILE * for the output
1204 * @attr: the attribute
1205 * @depth: the indentation level.
1206 *
1207 * Dumps debug information for the attribute
1208 */
1209void
1210xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
Daniel Veillard22cdb842004-10-04 14:09:17 +00001211 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001212
Daniel Veillard22cdb842004-10-04 14:09:17 +00001213 xmlCtxtDumpInitCtxt(&ctxt);
1214 ctxt.output = output;
1215 ctxt.depth = depth;
1216 xmlCtxtDumpAttr(&ctxt, attr);
Daniel Veillard76821142004-10-09 20:39:04 +00001217 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001218}
Owen Taylor3473f882001-02-23 17:55:21 +00001219
Owen Taylor3473f882001-02-23 17:55:21 +00001220
Daniel Veillard22cdb842004-10-04 14:09:17 +00001221/**
1222 * xmlDebugDumpEntities:
1223 * @output: the FILE * for the output
1224 * @doc: the document
1225 *
1226 * Dumps debug information for all the entities in use by the document
1227 */
1228void
1229xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1230{
1231 xmlDebugCtxt ctxt;
1232
1233 xmlCtxtDumpInitCtxt(&ctxt);
1234 ctxt.output = output;
1235 xmlCtxtDumpEntities(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001236 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001237}
1238
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001239/**
1240 * xmlDebugDumpAttrList:
1241 * @output: the FILE * for the output
1242 * @attr: the attribute list
1243 * @depth: the indentation level.
1244 *
1245 * Dumps debug information for the attribute list
1246 */
1247void
1248xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1249{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001250 xmlDebugCtxt ctxt;
1251
1252 xmlCtxtDumpInitCtxt(&ctxt);
1253 ctxt.output = output;
1254 ctxt.depth = depth;
1255 xmlCtxtDumpAttrList(&ctxt, attr);
Daniel Veillard76821142004-10-09 20:39:04 +00001256 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001257}
1258
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001259/**
1260 * xmlDebugDumpOneNode:
1261 * @output: the FILE * for the output
1262 * @node: the node
1263 * @depth: the indentation level.
1264 *
1265 * Dumps debug information for the element node, it is not recursive
1266 */
1267void
1268xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1269{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001270 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001271
Daniel Veillard22cdb842004-10-04 14:09:17 +00001272 xmlCtxtDumpInitCtxt(&ctxt);
1273 ctxt.output = output;
1274 ctxt.depth = depth;
1275 xmlCtxtDumpOneNode(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001276 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001277}
1278
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001279/**
1280 * xmlDebugDumpNode:
1281 * @output: the FILE * for the output
1282 * @node: the node
1283 * @depth: the indentation level.
1284 *
1285 * Dumps debug information for the element node, it is recursive
1286 */
1287void
1288xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1289{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001290 xmlDebugCtxt ctxt;
1291
Daniel Veillard7db38712002-02-07 16:39:11 +00001292 if (output == NULL)
1293 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001294 xmlCtxtDumpInitCtxt(&ctxt);
1295 ctxt.output = output;
1296 ctxt.depth = depth;
1297 xmlCtxtDumpNode(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001298 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001299}
1300
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001301/**
1302 * xmlDebugDumpNodeList:
1303 * @output: the FILE * for the output
1304 * @node: the node list
1305 * @depth: the indentation level.
1306 *
1307 * Dumps debug information for the list of element node, it is recursive
1308 */
1309void
1310xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1311{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001312 xmlDebugCtxt ctxt;
1313
Daniel Veillard7db38712002-02-07 16:39:11 +00001314 if (output == NULL)
1315 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001316 xmlCtxtDumpInitCtxt(&ctxt);
1317 ctxt.output = output;
1318 ctxt.depth = depth;
1319 xmlCtxtDumpNodeList(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001320 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001321}
1322
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001323/**
1324 * xmlDebugDumpDocumentHead:
1325 * @output: the FILE * for the output
1326 * @doc: the document
1327 *
1328 * Dumps debug information cncerning the document, not recursive
1329 */
1330void
1331xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1332{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001333 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001334
Daniel Veillard22cdb842004-10-04 14:09:17 +00001335 if (output == NULL)
1336 output = stdout;
1337 xmlCtxtDumpInitCtxt(&ctxt);
1338 ctxt.output = output;
1339 xmlCtxtDumpDocumentHead(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001340 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001341}
1342
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001343/**
1344 * xmlDebugDumpDocument:
1345 * @output: the FILE * for the output
1346 * @doc: the document
1347 *
1348 * Dumps debug information for the document, it's recursive
1349 */
1350void
1351xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1352{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001353 xmlDebugCtxt ctxt;
1354
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001355 if (output == NULL)
Daniel Veillard22cdb842004-10-04 14:09:17 +00001356 output = stdout;
1357 xmlCtxtDumpInitCtxt(&ctxt);
1358 ctxt.output = output;
1359 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001360 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001361}
Owen Taylor3473f882001-02-23 17:55:21 +00001362
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001363/**
1364 * xmlDebugDumpDTD:
1365 * @output: the FILE * for the output
1366 * @dtd: the DTD
1367 *
1368 * Dumps debug information for the DTD
1369 */
1370void
1371xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1372{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001373 xmlDebugCtxt ctxt;
1374
Daniel Veillard7db38712002-02-07 16:39:11 +00001375 if (output == NULL)
1376 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001377 xmlCtxtDumpInitCtxt(&ctxt);
1378 ctxt.output = output;
1379 xmlCtxtDumpDTD(&ctxt, dtd);
Daniel Veillard76821142004-10-09 20:39:04 +00001380 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001381}
1382
Daniel Veillard22cdb842004-10-04 14:09:17 +00001383/************************************************************************
1384 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001385 * Public entry points for checkings *
1386 * *
1387 ************************************************************************/
1388
1389/**
1390 * xmlDebugCheckDocument:
1391 * @output: the FILE * for the output
1392 * @doc: the document
1393 *
1394 * Check the document for potential content problems, and output
1395 * the errors to @output
1396 *
1397 * Returns the number of errors found
1398 */
1399int
1400xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1401{
1402 xmlDebugCtxt ctxt;
1403
1404 if (output == NULL)
1405 output = stdout;
1406 xmlCtxtDumpInitCtxt(&ctxt);
1407 ctxt.output = output;
1408 ctxt.check = 1;
1409 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001410 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001411 return(ctxt.errors);
1412}
1413
1414/************************************************************************
1415 * *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001416 * Helpers for Shell *
1417 * *
1418 ************************************************************************/
Owen Taylor3473f882001-02-23 17:55:21 +00001419
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001420/**
1421 * xmlLsCountNode:
1422 * @node: the node to count
1423 *
1424 * Count the children of @node.
1425 *
1426 * Returns the number of children of @node.
1427 */
1428int
1429xmlLsCountNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001430 int ret = 0;
1431 xmlNodePtr list = NULL;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001432
1433 if (node == NULL)
1434 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001435
1436 switch (node->type) {
1437 case XML_ELEMENT_NODE:
1438 list = node->children;
1439 break;
1440 case XML_DOCUMENT_NODE:
1441 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00001442#ifdef LIBXML_DOCB_ENABLED
1443 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00001444#endif
1445 list = ((xmlDocPtr) node)->children;
1446 break;
1447 case XML_ATTRIBUTE_NODE:
1448 list = ((xmlAttrPtr) node)->children;
1449 break;
1450 case XML_TEXT_NODE:
1451 case XML_CDATA_SECTION_NODE:
1452 case XML_PI_NODE:
1453 case XML_COMMENT_NODE:
1454 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001455 ret = xmlStrlen(node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001456 }
1457 break;
1458 case XML_ENTITY_REF_NODE:
1459 case XML_DOCUMENT_TYPE_NODE:
1460 case XML_ENTITY_NODE:
1461 case XML_DOCUMENT_FRAG_NODE:
1462 case XML_NOTATION_NODE:
1463 case XML_DTD_NODE:
1464 case XML_ELEMENT_DECL:
1465 case XML_ATTRIBUTE_DECL:
1466 case XML_ENTITY_DECL:
1467 case XML_NAMESPACE_DECL:
1468 case XML_XINCLUDE_START:
1469 case XML_XINCLUDE_END:
1470 ret = 1;
1471 break;
1472 }
1473 for (;list != NULL;ret++)
1474 list = list->next;
1475 return(ret);
1476}
1477
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001478/**
1479 * xmlLsOneNode:
1480 * @output: the FILE * for the output
1481 * @node: the node to dump
1482 *
1483 * Dump to @output the type and name of @node.
1484 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001485void
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001486xmlLsOneNode(FILE *output, xmlNodePtr node) {
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001487 if (node == NULL) {
1488 fprintf(output, "NULL\n");
1489 return;
1490 }
Owen Taylor3473f882001-02-23 17:55:21 +00001491 switch (node->type) {
1492 case XML_ELEMENT_NODE:
1493 fprintf(output, "-");
1494 break;
1495 case XML_ATTRIBUTE_NODE:
1496 fprintf(output, "a");
1497 break;
1498 case XML_TEXT_NODE:
1499 fprintf(output, "t");
1500 break;
1501 case XML_CDATA_SECTION_NODE:
Daniel Veillard75be0132002-03-13 10:03:35 +00001502 fprintf(output, "C");
Owen Taylor3473f882001-02-23 17:55:21 +00001503 break;
1504 case XML_ENTITY_REF_NODE:
1505 fprintf(output, "e");
1506 break;
1507 case XML_ENTITY_NODE:
1508 fprintf(output, "E");
1509 break;
1510 case XML_PI_NODE:
1511 fprintf(output, "p");
1512 break;
1513 case XML_COMMENT_NODE:
1514 fprintf(output, "c");
1515 break;
1516 case XML_DOCUMENT_NODE:
1517 fprintf(output, "d");
1518 break;
1519 case XML_HTML_DOCUMENT_NODE:
1520 fprintf(output, "h");
1521 break;
1522 case XML_DOCUMENT_TYPE_NODE:
1523 fprintf(output, "T");
1524 break;
1525 case XML_DOCUMENT_FRAG_NODE:
1526 fprintf(output, "F");
1527 break;
1528 case XML_NOTATION_NODE:
1529 fprintf(output, "N");
1530 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001531 case XML_NAMESPACE_DECL:
1532 fprintf(output, "n");
1533 break;
Owen Taylor3473f882001-02-23 17:55:21 +00001534 default:
1535 fprintf(output, "?");
1536 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00001537 if (node->type != XML_NAMESPACE_DECL) {
1538 if (node->properties != NULL)
1539 fprintf(output, "a");
1540 else
1541 fprintf(output, "-");
1542 if (node->nsDef != NULL)
1543 fprintf(output, "n");
1544 else
1545 fprintf(output, "-");
1546 }
Owen Taylor3473f882001-02-23 17:55:21 +00001547
1548 fprintf(output, " %8d ", xmlLsCountNode(node));
1549
1550 switch (node->type) {
1551 case XML_ELEMENT_NODE:
1552 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001553 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001554 break;
1555 case XML_ATTRIBUTE_NODE:
1556 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001557 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001558 break;
1559 case XML_TEXT_NODE:
1560 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001561 xmlDebugDumpString(output, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001562 }
1563 break;
1564 case XML_CDATA_SECTION_NODE:
1565 break;
1566 case XML_ENTITY_REF_NODE:
1567 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001568 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001569 break;
1570 case XML_ENTITY_NODE:
1571 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001572 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001573 break;
1574 case XML_PI_NODE:
1575 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001576 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001577 break;
1578 case XML_COMMENT_NODE:
1579 break;
1580 case XML_DOCUMENT_NODE:
1581 break;
1582 case XML_HTML_DOCUMENT_NODE:
1583 break;
1584 case XML_DOCUMENT_TYPE_NODE:
1585 break;
1586 case XML_DOCUMENT_FRAG_NODE:
1587 break;
1588 case XML_NOTATION_NODE:
1589 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001590 case XML_NAMESPACE_DECL: {
1591 xmlNsPtr ns = (xmlNsPtr) node;
1592
1593 if (ns->prefix == NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00001594 fprintf(output, "default -> %s", (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001595 else
William M. Brack13dfa872004-09-18 04:52:08 +00001596 fprintf(output, "%s -> %s", (char *)ns->prefix,
1597 (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001598 break;
1599 }
Owen Taylor3473f882001-02-23 17:55:21 +00001600 default:
1601 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001602 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001603 }
1604 fprintf(output, "\n");
1605}
1606
Daniel Veillard78d12092001-10-11 09:12:24 +00001607/**
1608 * xmlBoolToText:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001609 * @boolval: a bool to turn into text
Daniel Veillard78d12092001-10-11 09:12:24 +00001610 *
1611 * Convenient way to turn bool into text
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001612 *
1613 * Returns a pointer to either "True" or "False"
1614 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001615const char *
Daniel Veillardebd38c52001-11-01 08:38:12 +00001616xmlBoolToText(int boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001617{
Daniel Veillardebd38c52001-11-01 08:38:12 +00001618 if (boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001619 return("True");
1620 else
1621 return("False");
1622}
1623
Owen Taylor3473f882001-02-23 17:55:21 +00001624/****************************************************************
1625 * *
1626 * The XML shell related functions *
1627 * *
1628 ****************************************************************/
1629
Daniel Veillard78d12092001-10-11 09:12:24 +00001630
1631
Owen Taylor3473f882001-02-23 17:55:21 +00001632/*
1633 * TODO: Improvement/cleanups for the XML shell
1634 * - allow to shell out an editor on a subpart
1635 * - cleanup function registrations (with help) and calling
1636 * - provide registration routines
1637 */
1638
1639/**
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001640 * xmlShellPrintXPathError:
Daniel Veillard78d12092001-10-11 09:12:24 +00001641 * @errorType: valid xpath error id
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001642 * @arg: the argument that cause xpath to fail
Daniel Veillard78d12092001-10-11 09:12:24 +00001643 *
1644 * Print the xpath error to libxml default error channel
1645 */
1646void
1647xmlShellPrintXPathError(int errorType, const char *arg)
1648{
1649 const char *default_arg = "Result";
1650
1651 if (!arg)
1652 arg = default_arg;
1653
1654 switch (errorType) {
1655 case XPATH_UNDEFINED:
1656 xmlGenericError(xmlGenericErrorContext,
1657 "%s: no such node\n", arg);
1658 break;
1659
1660 case XPATH_BOOLEAN:
1661 xmlGenericError(xmlGenericErrorContext,
1662 "%s is a Boolean\n", arg);
1663 break;
1664 case XPATH_NUMBER:
1665 xmlGenericError(xmlGenericErrorContext,
1666 "%s is a number\n", arg);
1667 break;
1668 case XPATH_STRING:
1669 xmlGenericError(xmlGenericErrorContext,
1670 "%s is a string\n", arg);
1671 break;
1672 case XPATH_POINT:
1673 xmlGenericError(xmlGenericErrorContext,
1674 "%s is a point\n", arg);
1675 break;
1676 case XPATH_RANGE:
1677 xmlGenericError(xmlGenericErrorContext,
1678 "%s is a range\n", arg);
1679 break;
1680 case XPATH_LOCATIONSET:
1681 xmlGenericError(xmlGenericErrorContext,
1682 "%s is a range\n", arg);
1683 break;
1684 case XPATH_USERS:
1685 xmlGenericError(xmlGenericErrorContext,
1686 "%s is user-defined\n", arg);
1687 break;
1688 case XPATH_XSLT_TREE:
1689 xmlGenericError(xmlGenericErrorContext,
1690 "%s is an XSLT value tree\n", arg);
1691 break;
1692 }
1693 xmlGenericError(xmlGenericErrorContext,
1694 "Try casting the result string function (xpath builtin)\n",
1695 arg);
1696}
1697
1698
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001699#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001700/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001701 * xmlShellPrintNodeCtxt:
1702 * @ctxt : a non-null shell context
1703 * @node : a non-null node to print to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001704 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001705 * Print node to the output FILE
1706 */
1707static void
1708xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1709{
Daniel Veillard01992e02002-10-09 10:20:30 +00001710 FILE *fp;
1711
1712 if (!node)
Daniel Veillard321be0c2002-10-08 21:26:42 +00001713 return;
Daniel Veillard01992e02002-10-09 10:20:30 +00001714 if (ctxt == NULL)
1715 fp = stdout;
1716 else
1717 fp = ctxt->output;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001718
1719 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001720 xmlDocDump(fp, (xmlDocPtr) node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001721 else if (node->type == XML_ATTRIBUTE_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001722 xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001723 else
Daniel Veillard01992e02002-10-09 10:20:30 +00001724 xmlElemDump(fp, node->doc, node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001725
Daniel Veillard01992e02002-10-09 10:20:30 +00001726 fprintf(fp, "\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00001727}
1728
1729/**
1730 * xmlShellPrintNode:
1731 * @node : a non-null node to print to the output FILE
1732 *
1733 * Print node to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001734 */
1735void
1736xmlShellPrintNode(xmlNodePtr node)
1737{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001738 xmlShellPrintNodeCtxt(NULL, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001739}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001740#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001741
Daniel Veillard78d12092001-10-11 09:12:24 +00001742/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001743 * xmlShellPrintXPathResultCtxt:
1744 * @ctxt: a valid shell context
Daniel Veillard9d06d302002-01-22 18:15:52 +00001745 * @list: a valid result generated by an xpath evaluation
Daniel Veillard78d12092001-10-11 09:12:24 +00001746 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001747 * Prints result to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001748 */
Daniel Veillard321be0c2002-10-08 21:26:42 +00001749static void
1750xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
Daniel Veillard78d12092001-10-11 09:12:24 +00001751{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001752 if (!ctxt)
1753 return;
Daniel Veillard78d12092001-10-11 09:12:24 +00001754
1755 if (list != NULL) {
1756 switch (list->type) {
1757 case XPATH_NODESET:{
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001758#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001759 int indx;
1760
1761 if (list->nodesetval) {
1762 for (indx = 0; indx < list->nodesetval->nodeNr;
1763 indx++) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001764 xmlShellPrintNodeCtxt(ctxt,
1765 list->nodesetval->nodeTab[indx]);
Daniel Veillard78d12092001-10-11 09:12:24 +00001766 }
1767 } else {
1768 xmlGenericError(xmlGenericErrorContext,
1769 "Empty node set\n");
1770 }
1771 break;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001772#else
1773 xmlGenericError(xmlGenericErrorContext,
1774 "Node set\n");
1775#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001776 }
1777 case XPATH_BOOLEAN:
1778 xmlGenericError(xmlGenericErrorContext,
1779 "Is a Boolean:%s\n",
1780 xmlBoolToText(list->boolval));
1781 break;
1782 case XPATH_NUMBER:
1783 xmlGenericError(xmlGenericErrorContext,
1784 "Is a number:%0g\n", list->floatval);
1785 break;
1786 case XPATH_STRING:
1787 xmlGenericError(xmlGenericErrorContext,
1788 "Is a string:%s\n", list->stringval);
1789 break;
1790
1791 default:
1792 xmlShellPrintXPathError(list->type, NULL);
1793 }
1794 }
1795}
1796
1797/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001798 * xmlShellPrintXPathResult:
1799 * @list: a valid result generated by an xpath evaluation
1800 *
1801 * Prints result to the output FILE
1802 */
1803void
1804xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1805{
1806 xmlShellPrintXPathResultCtxt(NULL, list);
1807}
1808
1809/**
Owen Taylor3473f882001-02-23 17:55:21 +00001810 * xmlShellList:
1811 * @ctxt: the shell context
1812 * @arg: unused
1813 * @node: a node
1814 * @node2: unused
1815 *
1816 * Implements the XML shell function "ls"
1817 * Does an Unix like listing of the given node (like a directory)
1818 *
1819 * Returns 0
1820 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001821int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001822xmlShellList(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001823 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1824 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1825{
Owen Taylor3473f882001-02-23 17:55:21 +00001826 xmlNodePtr cur;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001827 if (!ctxt)
1828 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001829 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001830 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001831 return (0);
1832 }
Owen Taylor3473f882001-02-23 17:55:21 +00001833 if ((node->type == XML_DOCUMENT_NODE) ||
1834 (node->type == XML_HTML_DOCUMENT_NODE)) {
1835 cur = ((xmlDocPtr) node)->children;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001836 } else if (node->type == XML_NAMESPACE_DECL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001837 xmlLsOneNode(ctxt->output, node);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001838 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001839 } else if (node->children != NULL) {
1840 cur = node->children;
1841 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001842 xmlLsOneNode(ctxt->output, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001843 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001844 }
1845 while (cur != NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001846 xmlLsOneNode(ctxt->output, cur);
Daniel Veillard78d12092001-10-11 09:12:24 +00001847 cur = cur->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001848 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001849 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001850}
1851
1852/**
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001853 * xmlShellBase:
1854 * @ctxt: the shell context
1855 * @arg: unused
1856 * @node: a node
1857 * @node2: unused
1858 *
1859 * Implements the XML shell function "base"
1860 * dumps the current XML base of the node
1861 *
1862 * Returns 0
1863 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001864int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001865xmlShellBase(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001866 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1867 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1868{
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001869 xmlChar *base;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001870 if (!ctxt)
1871 return 0;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001872 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001873 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001874 return (0);
1875 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001876
1877 base = xmlNodeGetBase(node->doc, node);
1878
1879 if (base == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001880 fprintf(ctxt->output, " No base found !!!\n");
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001881 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001882 fprintf(ctxt->output, "%s\n", base);
Daniel Veillard78d12092001-10-11 09:12:24 +00001883 xmlFree(base);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001884 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001885 return (0);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001886}
1887
Daniel Veillardb34321c2004-03-04 17:09:47 +00001888#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001889/**
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001890 * xmlShellSetBase:
1891 * @ctxt: the shell context
1892 * @arg: the new base
1893 * @node: a node
1894 * @node2: unused
1895 *
1896 * Implements the XML shell function "setbase"
1897 * change the current XML base of the node
1898 *
1899 * Returns 0
1900 */
1901static int
1902xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1903 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1904 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1905{
1906 xmlNodeSetBase(node, (xmlChar*) arg);
1907 return (0);
1908}
Daniel Veillard2156d432004-03-04 15:59:36 +00001909#endif
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001910
Daniel Veillardbbaa9972004-06-16 14:08:33 +00001911#ifdef LIBXML_XPATH_ENABLED
1912/**
1913 * xmlShellRegisterNamespace:
1914 * @ctxt: the shell context
1915 * @arg: a string in prefix=nsuri format
1916 * @node: unused
1917 * @node2: unused
1918 *
1919 * Implements the XML shell function "setns"
1920 * register/unregister a prefix=namespace pair
1921 * on the XPath context
1922 *
1923 * Returns 0 on success and a negative value otherwise.
1924 */
1925static int
1926xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
1927 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1928{
1929 xmlChar* nsListDup;
1930 xmlChar* prefix;
1931 xmlChar* href;
1932 xmlChar* next;
1933
1934 nsListDup = xmlStrdup((xmlChar *) arg);
1935 next = nsListDup;
1936 while(next != NULL) {
1937 /* skip spaces */
1938 /*while((*next) == ' ') next++;*/
1939 if((*next) == '\0') break;
1940
1941 /* find prefix */
1942 prefix = next;
1943 next = (xmlChar*)xmlStrchr(next, '=');
1944 if(next == NULL) {
1945 fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
1946 xmlFree(nsListDup);
1947 return(-1);
1948 }
1949 *(next++) = '\0';
1950
1951 /* find href */
1952 href = next;
1953 next = (xmlChar*)xmlStrchr(next, ' ');
1954 if(next != NULL) {
1955 *(next++) = '\0';
1956 }
1957
1958 /* do register namespace */
1959 if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
1960 fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
1961 xmlFree(nsListDup);
1962 return(-1);
1963 }
1964 }
1965
1966 xmlFree(nsListDup);
1967 return(0);
1968}
1969#endif
1970
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001971/**
Daniel Veillard1e208222002-10-22 14:25:25 +00001972 * xmlShellGrep:
1973 * @ctxt: the shell context
1974 * @arg: the string or regular expression to find
1975 * @node: a node
1976 * @node2: unused
1977 *
1978 * Implements the XML shell function "grep"
1979 * dumps informations about the node (namespace, attributes, content).
1980 *
1981 * Returns 0
1982 */
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001983static int
Daniel Veillard1e208222002-10-22 14:25:25 +00001984xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1985 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1986{
1987 if (!ctxt)
1988 return (0);
1989 if (node == NULL)
1990 return (0);
1991 if (arg == NULL)
1992 return (0);
1993#ifdef LIBXML_REGEXP_ENABLED
1994 if ((xmlStrchr((xmlChar *) arg, '?')) ||
1995 (xmlStrchr((xmlChar *) arg, '*')) ||
1996 (xmlStrchr((xmlChar *) arg, '.')) ||
1997 (xmlStrchr((xmlChar *) arg, '['))) {
1998 }
1999#endif
2000 while (node != NULL) {
2001 if (node->type == XML_COMMENT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002002 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00002003
2004 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
2005 xmlShellList(ctxt, NULL, node, NULL);
2006 }
2007 } else if (node->type == XML_TEXT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002008 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00002009
2010 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002011 xmlShellList(ctxt, NULL, node->parent, NULL);
Daniel Veillard1e208222002-10-22 14:25:25 +00002012 }
2013 }
2014
2015 /*
2016 * Browse the full subtree, deep first
2017 */
2018
2019 if ((node->type == XML_DOCUMENT_NODE) ||
2020 (node->type == XML_HTML_DOCUMENT_NODE)) {
2021 node = ((xmlDocPtr) node)->children;
2022 } else if ((node->children != NULL)
2023 && (node->type != XML_ENTITY_REF_NODE)) {
2024 /* deep first */
2025 node = node->children;
2026 } else if (node->next != NULL) {
2027 /* then siblings */
2028 node = node->next;
2029 } else {
2030 /* go up to parents->next if needed */
2031 while (node != NULL) {
2032 if (node->parent != NULL) {
2033 node = node->parent;
2034 }
2035 if (node->next != NULL) {
2036 node = node->next;
2037 break;
2038 }
2039 if (node->parent == NULL) {
2040 node = NULL;
2041 break;
2042 }
2043 }
2044 }
2045 }
2046 return (0);
2047}
2048
2049/**
Owen Taylor3473f882001-02-23 17:55:21 +00002050 * xmlShellDir:
2051 * @ctxt: the shell context
2052 * @arg: unused
2053 * @node: a node
2054 * @node2: unused
2055 *
2056 * Implements the XML shell function "dir"
2057 * dumps informations about the node (namespace, attributes, content).
2058 *
2059 * Returns 0
2060 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002061int
2062xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2063 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2064 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2065{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002066 if (!ctxt)
2067 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002068 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002069 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002070 return (0);
2071 }
Owen Taylor3473f882001-02-23 17:55:21 +00002072 if ((node->type == XML_DOCUMENT_NODE) ||
2073 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002074 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
Owen Taylor3473f882001-02-23 17:55:21 +00002075 } else if (node->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002076 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002077 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002078 xmlDebugDumpOneNode(ctxt->output, node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002079 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002080 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002081}
2082
Daniel Veillard29b17482004-08-16 00:39:03 +00002083/**
2084 * xmlShellSetContent:
2085 * @ctxt: the shell context
2086 * @value: the content as a string
2087 * @node: a node
2088 * @node2: unused
2089 *
2090 * Implements the XML shell function "dir"
2091 * dumps informations about the node (namespace, attributes, content).
2092 *
2093 * Returns 0
2094 */
2095static int
2096xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2097 char *value, xmlNodePtr node,
2098 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2099{
2100 xmlNodePtr results;
2101 xmlParserErrors ret;
2102
2103 if (!ctxt)
2104 return (0);
2105 if (node == NULL) {
2106 fprintf(ctxt->output, "NULL\n");
2107 return (0);
2108 }
2109 if (value == NULL) {
2110 fprintf(ctxt->output, "NULL\n");
2111 return (0);
2112 }
2113
2114 ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
2115 if (ret == XML_ERR_OK) {
2116 if (node->children != NULL) {
2117 xmlFreeNodeList(node->children);
2118 node->children = NULL;
2119 node->last = NULL;
2120 }
2121 xmlAddChildList(node, results);
2122 } else {
2123 fprintf(ctxt->output, "failed to parse content\n");
2124 }
2125 return (0);
2126}
2127
Daniel Veillard522bc602004-02-21 11:53:09 +00002128#ifdef LIBXML_SCHEMAS_ENABLED
2129/**
2130 * xmlShellRNGValidate:
2131 * @ctxt: the shell context
2132 * @schemas: the path to the Relax-NG schemas
2133 * @node: a node
2134 * @node2: unused
2135 *
2136 * Implements the XML shell function "relaxng"
2137 * validating the instance against a Relax-NG schemas
2138 *
2139 * Returns 0
2140 */
2141static int
2142xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2143 xmlNodePtr node ATTRIBUTE_UNUSED,
2144 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2145{
2146 xmlRelaxNGPtr relaxngschemas;
2147 xmlRelaxNGParserCtxtPtr ctxt;
2148 xmlRelaxNGValidCtxtPtr vctxt;
2149 int ret;
2150
2151 ctxt = xmlRelaxNGNewParserCtxt(schemas);
2152 xmlRelaxNGSetParserErrors(ctxt,
2153 (xmlRelaxNGValidityErrorFunc) fprintf,
2154 (xmlRelaxNGValidityWarningFunc) fprintf,
2155 stderr);
2156 relaxngschemas = xmlRelaxNGParse(ctxt);
2157 xmlRelaxNGFreeParserCtxt(ctxt);
2158 if (relaxngschemas == NULL) {
2159 xmlGenericError(xmlGenericErrorContext,
2160 "Relax-NG schema %s failed to compile\n", schemas);
2161 return(-1);
2162 }
2163 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2164 xmlRelaxNGSetValidErrors(vctxt,
2165 (xmlRelaxNGValidityErrorFunc) fprintf,
2166 (xmlRelaxNGValidityWarningFunc) fprintf,
2167 stderr);
2168 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2169 if (ret == 0) {
2170 fprintf(stderr, "%s validates\n", sctxt->filename);
2171 } else if (ret > 0) {
2172 fprintf(stderr, "%s fails to validate\n", sctxt->filename);
2173 } else {
2174 fprintf(stderr, "%s validation generated an internal error\n",
2175 sctxt->filename);
2176 }
2177 xmlRelaxNGFreeValidCtxt(vctxt);
2178 if (relaxngschemas != NULL)
2179 xmlRelaxNGFree(relaxngschemas);
2180 return(0);
2181}
2182#endif
2183
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002184#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002185/**
2186 * xmlShellCat:
2187 * @ctxt: the shell context
2188 * @arg: unused
2189 * @node: a node
2190 * @node2: unused
2191 *
2192 * Implements the XML shell function "cat"
2193 * dumps the serialization node content (XML or HTML).
2194 *
2195 * Returns 0
2196 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002197int
2198xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2199 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2200{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002201 if (!ctxt)
2202 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002203 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002204 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002205 return (0);
2206 }
Owen Taylor3473f882001-02-23 17:55:21 +00002207 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2208#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002209 if (node->type == XML_HTML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002210 htmlDocDump(ctxt->output, (htmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002211 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002212 htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002213#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002214 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002215 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002216 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002217 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002218#endif /* LIBXML_HTML_ENABLED */
2219 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00002220 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002221 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002222 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002223 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002224 }
Daniel Veillard321be0c2002-10-08 21:26:42 +00002225 fprintf(ctxt->output, "\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002226 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002227}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002228#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002229
2230/**
2231 * xmlShellLoad:
2232 * @ctxt: the shell context
2233 * @filename: the file name
2234 * @node: unused
2235 * @node2: unused
2236 *
2237 * Implements the XML shell function "load"
2238 * loads a new document specified by the filename
2239 *
2240 * Returns 0 or -1 if loading failed
2241 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002242int
2243xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2244 xmlNodePtr node ATTRIBUTE_UNUSED,
2245 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2246{
Owen Taylor3473f882001-02-23 17:55:21 +00002247 xmlDocPtr doc;
2248 int html = 0;
2249
2250 if (ctxt->doc != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002251 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00002252
2253 if (html) {
2254#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002255 doc = htmlParseFile(filename, NULL);
2256#else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002257 fprintf(ctxt->output, "HTML support not compiled in\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002258 doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002259#endif /* LIBXML_HTML_ENABLED */
2260 } else {
Daniel Veillardebe25d42004-03-25 09:35:49 +00002261 doc = xmlReadFile(filename,NULL,0);
Owen Taylor3473f882001-02-23 17:55:21 +00002262 }
2263 if (doc != NULL) {
2264 if (ctxt->loaded == 1) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002265 xmlFreeDoc(ctxt->doc);
2266 }
2267 ctxt->loaded = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002268#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002269 xmlXPathFreeContext(ctxt->pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002270#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002271 xmlFree(ctxt->filename);
2272 ctxt->doc = doc;
2273 ctxt->node = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002274#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002275 ctxt->pctxt = xmlXPathNewContext(doc);
Owen Taylor3473f882001-02-23 17:55:21 +00002276#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard85095e22003-04-23 13:56:44 +00002277 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002278 } else
Daniel Veillard78d12092001-10-11 09:12:24 +00002279 return (-1);
2280 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002281}
2282
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002283#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002284/**
2285 * xmlShellWrite:
2286 * @ctxt: the shell context
2287 * @filename: the file name
2288 * @node: a node in the tree
2289 * @node2: unused
2290 *
2291 * Implements the XML shell function "write"
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002292 * Write the current node to the filename, it saves the serialization
Owen Taylor3473f882001-02-23 17:55:21 +00002293 * of the subtree under the @node specified
2294 *
2295 * Returns 0 or -1 in case of error
2296 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002297int
Owen Taylor3473f882001-02-23 17:55:21 +00002298xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
Daniel Veillard78d12092001-10-11 09:12:24 +00002299 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2300{
Owen Taylor3473f882001-02-23 17:55:21 +00002301 if (node == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002302 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002303 if ((filename == NULL) || (filename[0] == 0)) {
2304 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002305 "Write command requires a filename argument\n");
2306 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002307 }
2308#ifdef W_OK
2309 if (access((char *) filename, W_OK)) {
2310 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002311 "Cannot write to %s\n", filename);
2312 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002313 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002314#endif
2315 switch (node->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002316 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002317 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2318 xmlGenericError(xmlGenericErrorContext,
2319 "Failed to write to %s\n", filename);
2320 return (-1);
2321 }
2322 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002323 case XML_HTML_DOCUMENT_NODE:
2324#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002325 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2326 xmlGenericError(xmlGenericErrorContext,
2327 "Failed to write to %s\n", filename);
2328 return (-1);
2329 }
Owen Taylor3473f882001-02-23 17:55:21 +00002330#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002331 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2332 xmlGenericError(xmlGenericErrorContext,
2333 "Failed to write to %s\n", filename);
2334 return (-1);
2335 }
Owen Taylor3473f882001-02-23 17:55:21 +00002336#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002337 break;
2338 default:{
2339 FILE *f;
Owen Taylor3473f882001-02-23 17:55:21 +00002340
Daniel Veillard78d12092001-10-11 09:12:24 +00002341 f = fopen((char *) filename, "w");
2342 if (f == NULL) {
2343 xmlGenericError(xmlGenericErrorContext,
2344 "Failed to write to %s\n", filename);
2345 return (-1);
2346 }
2347 xmlElemDump(f, ctxt->doc, node);
2348 fclose(f);
2349 }
Owen Taylor3473f882001-02-23 17:55:21 +00002350 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002351 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002352}
2353
2354/**
2355 * xmlShellSave:
2356 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002357 * @filename: the file name (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002358 * @node: unused
2359 * @node2: unused
2360 *
2361 * Implements the XML shell function "save"
2362 * Write the current document to the filename, or it's original name
2363 *
2364 * Returns 0 or -1 in case of error
2365 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002366int
2367xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2368 xmlNodePtr node ATTRIBUTE_UNUSED,
2369 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2370{
Owen Taylor3473f882001-02-23 17:55:21 +00002371 if (ctxt->doc == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002372 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002373 if ((filename == NULL) || (filename[0] == 0))
2374 filename = ctxt->filename;
2375#ifdef W_OK
2376 if (access((char *) filename, W_OK)) {
2377 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002378 "Cannot save to %s\n", filename);
2379 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002380 }
2381#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002382 switch (ctxt->doc->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002383 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002384 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2385 xmlGenericError(xmlGenericErrorContext,
2386 "Failed to save to %s\n", filename);
2387 }
2388 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002389 case XML_HTML_DOCUMENT_NODE:
2390#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002391 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2392 xmlGenericError(xmlGenericErrorContext,
2393 "Failed to save to %s\n", filename);
2394 }
Owen Taylor3473f882001-02-23 17:55:21 +00002395#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002396 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2397 xmlGenericError(xmlGenericErrorContext,
2398 "Failed to save to %s\n", filename);
2399 }
Owen Taylor3473f882001-02-23 17:55:21 +00002400#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002401 break;
2402 default:
2403 xmlGenericError(xmlGenericErrorContext,
2404 "To save to subparts of a document use the 'write' command\n");
2405 return (-1);
2406
Owen Taylor3473f882001-02-23 17:55:21 +00002407 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002408 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002409}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002410#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002411
Daniel Veillardf54cd532004-02-25 11:52:31 +00002412#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002413/**
2414 * xmlShellValidate:
2415 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002416 * @dtd: the DTD URI (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002417 * @node: unused
2418 * @node2: unused
2419 *
2420 * Implements the XML shell function "validate"
2421 * Validate the document, if a DTD path is provided, then the validation
2422 * is done against the given DTD.
2423 *
2424 * Returns 0 or -1 in case of error
2425 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002426int
2427xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2428 xmlNodePtr node ATTRIBUTE_UNUSED,
2429 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2430{
Owen Taylor3473f882001-02-23 17:55:21 +00002431 xmlValidCtxt vctxt;
2432 int res = -1;
2433
2434 vctxt.userData = stderr;
2435 vctxt.error = (xmlValidityErrorFunc) fprintf;
2436 vctxt.warning = (xmlValidityWarningFunc) fprintf;
2437
2438 if ((dtd == NULL) || (dtd[0] == 0)) {
2439 res = xmlValidateDocument(&vctxt, ctxt->doc);
2440 } else {
2441 xmlDtdPtr subset;
2442
Daniel Veillard78d12092001-10-11 09:12:24 +00002443 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2444 if (subset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002445 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2446
Daniel Veillard78d12092001-10-11 09:12:24 +00002447 xmlFreeDtd(subset);
2448 }
Owen Taylor3473f882001-02-23 17:55:21 +00002449 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002450 return (res);
Owen Taylor3473f882001-02-23 17:55:21 +00002451}
Daniel Veillardf54cd532004-02-25 11:52:31 +00002452#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002453
2454/**
2455 * xmlShellDu:
2456 * @ctxt: the shell context
2457 * @arg: unused
2458 * @tree: a node defining a subtree
2459 * @node2: unused
2460 *
2461 * Implements the XML shell function "du"
2462 * show the structure of the subtree under node @tree
2463 * If @tree is null, the command works on the current node.
2464 *
2465 * Returns 0 or -1 in case of error
2466 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002467int
Daniel Veillard321be0c2002-10-08 21:26:42 +00002468xmlShellDu(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00002469 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2470 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2471{
Owen Taylor3473f882001-02-23 17:55:21 +00002472 xmlNodePtr node;
Daniel Veillard78d12092001-10-11 09:12:24 +00002473 int indent = 0, i;
Owen Taylor3473f882001-02-23 17:55:21 +00002474
Daniel Veillard321be0c2002-10-08 21:26:42 +00002475 if (!ctxt)
2476 return (-1);
2477
Daniel Veillard78d12092001-10-11 09:12:24 +00002478 if (tree == NULL)
2479 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002480 node = tree;
2481 while (node != NULL) {
2482 if ((node->type == XML_DOCUMENT_NODE) ||
2483 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002484 fprintf(ctxt->output, "/\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002485 } else if (node->type == XML_ELEMENT_NODE) {
2486 for (i = 0; i < indent; i++)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002487 fprintf(ctxt->output, " ");
2488 fprintf(ctxt->output, "%s\n", node->name);
Daniel Veillard78d12092001-10-11 09:12:24 +00002489 } else {
2490 }
Owen Taylor3473f882001-02-23 17:55:21 +00002491
Daniel Veillard78d12092001-10-11 09:12:24 +00002492 /*
2493 * Browse the full subtree, deep first
2494 */
Owen Taylor3473f882001-02-23 17:55:21 +00002495
2496 if ((node->type == XML_DOCUMENT_NODE) ||
2497 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002498 node = ((xmlDocPtr) node)->children;
2499 } else if ((node->children != NULL)
2500 && (node->type != XML_ENTITY_REF_NODE)) {
2501 /* deep first */
2502 node = node->children;
2503 indent++;
2504 } else if ((node != tree) && (node->next != NULL)) {
2505 /* then siblings */
2506 node = node->next;
2507 } else if (node != tree) {
2508 /* go up to parents->next if needed */
2509 while (node != tree) {
2510 if (node->parent != NULL) {
2511 node = node->parent;
2512 indent--;
2513 }
2514 if ((node != tree) && (node->next != NULL)) {
2515 node = node->next;
2516 break;
2517 }
2518 if (node->parent == NULL) {
2519 node = NULL;
2520 break;
2521 }
2522 if (node == tree) {
2523 node = NULL;
2524 break;
2525 }
2526 }
2527 /* exit condition */
2528 if (node == tree)
2529 node = NULL;
2530 } else
2531 node = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002532 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002533 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002534}
2535
2536/**
2537 * xmlShellPwd:
2538 * @ctxt: the shell context
2539 * @buffer: the output buffer
Daniel Veillard9d06d302002-01-22 18:15:52 +00002540 * @node: a node
Owen Taylor3473f882001-02-23 17:55:21 +00002541 * @node2: unused
2542 *
2543 * Implements the XML shell function "pwd"
2544 * Show the full path from the root to the node, if needed building
2545 * thumblers when similar elements exists at a given ancestor level.
2546 * The output is compatible with XPath commands.
2547 *
2548 * Returns 0 or -1 in case of error
2549 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002550int
2551xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2552 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2553{
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002554 xmlChar *path;
Owen Taylor3473f882001-02-23 17:55:21 +00002555
Daniel Veillard78d12092001-10-11 09:12:24 +00002556 if (node == NULL)
2557 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002558
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002559 path = xmlGetNodePath(node);
2560 if (path == NULL)
2561 return (-1);
2562
2563 /*
2564 * This test prevents buffer overflow, because this routine
2565 * is only called by xmlShell, in which the second argument is
2566 * 500 chars long.
2567 * It is a dirty hack before a cleaner solution is found.
2568 * Documentation should mention that the second argument must
2569 * be at least 500 chars long, and could be stripped if too long.
2570 */
2571 snprintf(buffer, 499, "%s", path);
2572 buffer[499] = '0';
2573 xmlFree(path);
2574
Daniel Veillard78d12092001-10-11 09:12:24 +00002575 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002576}
2577
2578/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002579 * xmlShell:
Owen Taylor3473f882001-02-23 17:55:21 +00002580 * @doc: the initial document
2581 * @filename: the output buffer
2582 * @input: the line reading function
Daniel Veillard321be0c2002-10-08 21:26:42 +00002583 * @output: the output FILE*, defaults to stdout if NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002584 *
2585 * Implements the XML shell
2586 * This allow to load, validate, view, modify and save a document
2587 * using a environment similar to a UNIX commandline.
2588 */
2589void
2590xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
Daniel Veillard78d12092001-10-11 09:12:24 +00002591 FILE * output)
2592{
Owen Taylor3473f882001-02-23 17:55:21 +00002593 char prompt[500] = "/ > ";
2594 char *cmdline = NULL, *cur;
2595 int nbargs;
2596 char command[100];
2597 char arg[400];
2598 int i;
2599 xmlShellCtxtPtr ctxt;
2600 xmlXPathObjectPtr list;
2601
2602 if (doc == NULL)
2603 return;
2604 if (filename == NULL)
2605 return;
2606 if (input == NULL)
2607 return;
2608 if (output == NULL)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002609 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00002610 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
Daniel Veillard78d12092001-10-11 09:12:24 +00002611 if (ctxt == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002612 return;
2613 ctxt->loaded = 0;
2614 ctxt->doc = doc;
2615 ctxt->input = input;
2616 ctxt->output = output;
2617 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
Daniel Veillard78d12092001-10-11 09:12:24 +00002618 ctxt->node = (xmlNodePtr) ctxt->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002619
2620#ifdef LIBXML_XPATH_ENABLED
2621 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2622 if (ctxt->pctxt == NULL) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002623 xmlFree(ctxt);
2624 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002625 }
2626#endif /* LIBXML_XPATH_ENABLED */
2627 while (1) {
2628 if (ctxt->node == (xmlNodePtr) ctxt->doc)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002629 snprintf(prompt, sizeof(prompt), "%s > ", "/");
Daniel Veillard7a985a12003-07-06 17:57:42 +00002630 else if ((ctxt->node != NULL) && (ctxt->node->name))
Daniel Veillard78d12092001-10-11 09:12:24 +00002631 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002632 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002633 snprintf(prompt, sizeof(prompt), "? > ");
Owen Taylor3473f882001-02-23 17:55:21 +00002634 prompt[sizeof(prompt) - 1] = 0;
2635
Daniel Veillard78d12092001-10-11 09:12:24 +00002636 /*
2637 * Get a new command line
2638 */
Owen Taylor3473f882001-02-23 17:55:21 +00002639 cmdline = ctxt->input(prompt);
Daniel Veillard78d12092001-10-11 09:12:24 +00002640 if (cmdline == NULL)
2641 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002642
Daniel Veillard78d12092001-10-11 09:12:24 +00002643 /*
2644 * Parse the command itself
2645 */
2646 cur = cmdline;
2647 nbargs = 0;
2648 while ((*cur == ' ') || (*cur == '\t'))
2649 cur++;
2650 i = 0;
2651 while ((*cur != ' ') && (*cur != '\t') &&
2652 (*cur != '\n') && (*cur != '\r')) {
2653 if (*cur == 0)
2654 break;
2655 command[i++] = *cur++;
2656 }
2657 command[i] = 0;
2658 if (i == 0)
2659 continue;
2660 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002661
Daniel Veillard78d12092001-10-11 09:12:24 +00002662 /*
2663 * Parse the argument
2664 */
2665 while ((*cur == ' ') || (*cur == '\t'))
2666 cur++;
2667 i = 0;
2668 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2669 if (*cur == 0)
2670 break;
2671 arg[i++] = *cur++;
2672 }
2673 arg[i] = 0;
2674 if (i != 0)
2675 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002676
Daniel Veillard78d12092001-10-11 09:12:24 +00002677 /*
2678 * start interpreting the command
2679 */
Owen Taylor3473f882001-02-23 17:55:21 +00002680 if (!strcmp(command, "exit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002681 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002682 if (!strcmp(command, "quit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002683 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002684 if (!strcmp(command, "bye"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002685 break;
Daniel Veillard5004f422001-11-08 13:53:05 +00002686 if (!strcmp(command, "help")) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002687 fprintf(ctxt->output, "\tbase display XML base of the node\n");
2688 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n");
2689 fprintf(ctxt->output, "\tbye leave shell\n");
2690 fprintf(ctxt->output, "\tcat [node] display node or current node\n");
2691 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n");
2692 fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n");
2693 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n");
2694 fprintf(ctxt->output, "\texit leave shell\n");
2695 fprintf(ctxt->output, "\thelp display this help\n");
2696 fprintf(ctxt->output, "\tfree display memory usage\n");
2697 fprintf(ctxt->output, "\tload [name] load a new document with name\n");
2698 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n");
Daniel Veillardc14c3892004-08-16 12:34:50 +00002699 fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n");
Daniel Veillard2070c482002-01-22 22:12:19 +00002700#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002701 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n");
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002702 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n");
2703 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
Daniel Veillard2070c482002-01-22 22:12:19 +00002704#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard321be0c2002-10-08 21:26:42 +00002705 fprintf(ctxt->output, "\tpwd display current working directory\n");
2706 fprintf(ctxt->output, "\tquit leave shell\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002707#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002708 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00002709 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002710#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf54cd532004-02-25 11:52:31 +00002711#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002712 fprintf(ctxt->output, "\tvalidate check the document for errors\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002713#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard522bc602004-02-21 11:53:09 +00002714#ifdef LIBXML_SCHEMAS_ENABLED
2715 fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n");
2716#endif
Daniel Veillard1e208222002-10-22 14:25:25 +00002717 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002718#ifdef LIBXML_VALID_ENABLED
Daniel Veillard5004f422001-11-08 13:53:05 +00002719 } else if (!strcmp(command, "validate")) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002720 xmlShellValidate(ctxt, arg, NULL, NULL);
Daniel Veillardf54cd532004-02-25 11:52:31 +00002721#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002722 } else if (!strcmp(command, "load")) {
2723 xmlShellLoad(ctxt, arg, NULL, NULL);
Daniel Veillard522bc602004-02-21 11:53:09 +00002724#ifdef LIBXML_SCHEMAS_ENABLED
2725 } else if (!strcmp(command, "relaxng")) {
2726 xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2727#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002728#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002729 } else if (!strcmp(command, "save")) {
2730 xmlShellSave(ctxt, arg, NULL, NULL);
2731 } else if (!strcmp(command, "write")) {
2732 xmlShellWrite(ctxt, arg, NULL, NULL);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002733#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard1e208222002-10-22 14:25:25 +00002734 } else if (!strcmp(command, "grep")) {
2735 xmlShellGrep(ctxt, arg, ctxt->node, NULL);
Daniel Veillard78d12092001-10-11 09:12:24 +00002736 } else if (!strcmp(command, "free")) {
2737 if (arg[0] == 0) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002738 xmlMemShow(ctxt->output, 0);
Daniel Veillard78d12092001-10-11 09:12:24 +00002739 } else {
2740 int len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002741
Daniel Veillard78d12092001-10-11 09:12:24 +00002742 sscanf(arg, "%d", &len);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002743 xmlMemShow(ctxt->output, len);
Daniel Veillard78d12092001-10-11 09:12:24 +00002744 }
2745 } else if (!strcmp(command, "pwd")) {
2746 char dir[500];
Owen Taylor3473f882001-02-23 17:55:21 +00002747
Daniel Veillard78d12092001-10-11 09:12:24 +00002748 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
Daniel Veillard321be0c2002-10-08 21:26:42 +00002749 fprintf(ctxt->output, "%s\n", dir);
Daniel Veillard78d12092001-10-11 09:12:24 +00002750 } else if (!strcmp(command, "du")) {
2751 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2752 } else if (!strcmp(command, "base")) {
2753 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
Daniel Veillard29b17482004-08-16 00:39:03 +00002754 } else if (!strcmp(command, "set")) {
2755 xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2070c482002-01-22 22:12:19 +00002756#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002757 } else if (!strcmp(command, "setns")) {
2758 if (arg[0] == 0) {
2759 xmlGenericError(xmlGenericErrorContext,
2760 "setns: prefix=[nsuri] required\n");
2761 } else {
2762 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
2763 }
Daniel Veillard2070c482002-01-22 22:12:19 +00002764 } else if (!strcmp(command, "xpath")) {
2765 if (arg[0] == 0) {
2766 xmlGenericError(xmlGenericErrorContext,
2767 "xpath: expression required\n");
2768 } else {
2769 ctxt->pctxt->node = ctxt->node;
2770 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002771 xmlXPathDebugDumpObject(ctxt->output, list, 0);
Daniel Veillard2070c482002-01-22 22:12:19 +00002772 xmlXPathFreeObject(list);
2773 }
2774#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard2156d432004-03-04 15:59:36 +00002775#ifdef LIBXML_TREE_ENABLED
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002776 } else if (!strcmp(command, "setbase")) {
2777 xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2156d432004-03-04 15:59:36 +00002778#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002779 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2780 int dir = (!strcmp(command, "dir"));
2781
2782 if (arg[0] == 0) {
2783 if (dir)
2784 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
2785 else
2786 xmlShellList(ctxt, NULL, ctxt->node, NULL);
2787 } else {
2788 ctxt->pctxt->node = ctxt->node;
Daniel Veillard61d80a22001-04-27 17:13:01 +00002789#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002790 ctxt->pctxt->node = ctxt->node;
2791 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2792#else
2793 list = NULL;
2794#endif /* LIBXML_XPATH_ENABLED */
2795 if (list != NULL) {
2796 switch (list->type) {
2797 case XPATH_UNDEFINED:
2798 xmlGenericError(xmlGenericErrorContext,
2799 "%s: no such node\n", arg);
2800 break;
2801 case XPATH_NODESET:{
2802 int indx;
2803
Daniel Veillarda6825e82001-11-07 13:33:59 +00002804 if (list->nodesetval == NULL)
2805 break;
2806
Daniel Veillard78d12092001-10-11 09:12:24 +00002807 for (indx = 0;
2808 indx < list->nodesetval->nodeNr;
2809 indx++) {
2810 if (dir)
2811 xmlShellDir(ctxt, NULL,
2812 list->nodesetval->
2813 nodeTab[indx], NULL);
2814 else
2815 xmlShellList(ctxt, NULL,
2816 list->nodesetval->
2817 nodeTab[indx], NULL);
2818 }
2819 break;
2820 }
2821 case XPATH_BOOLEAN:
2822 xmlGenericError(xmlGenericErrorContext,
2823 "%s is a Boolean\n", arg);
2824 break;
2825 case XPATH_NUMBER:
2826 xmlGenericError(xmlGenericErrorContext,
2827 "%s is a number\n", arg);
2828 break;
2829 case XPATH_STRING:
2830 xmlGenericError(xmlGenericErrorContext,
2831 "%s is a string\n", arg);
2832 break;
2833 case XPATH_POINT:
2834 xmlGenericError(xmlGenericErrorContext,
2835 "%s is a point\n", arg);
2836 break;
2837 case XPATH_RANGE:
2838 xmlGenericError(xmlGenericErrorContext,
2839 "%s is a range\n", arg);
2840 break;
2841 case XPATH_LOCATIONSET:
2842 xmlGenericError(xmlGenericErrorContext,
2843 "%s is a range\n", arg);
2844 break;
2845 case XPATH_USERS:
2846 xmlGenericError(xmlGenericErrorContext,
2847 "%s is user-defined\n", arg);
2848 break;
2849 case XPATH_XSLT_TREE:
2850 xmlGenericError(xmlGenericErrorContext,
2851 "%s is an XSLT value tree\n",
2852 arg);
2853 break;
2854 }
2855#ifdef LIBXML_XPATH_ENABLED
2856 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00002857#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002858 } else {
2859 xmlGenericError(xmlGenericErrorContext,
2860 "%s: no such node\n", arg);
2861 }
2862 ctxt->pctxt->node = NULL;
2863 }
2864 } else if (!strcmp(command, "cd")) {
2865 if (arg[0] == 0) {
2866 ctxt->node = (xmlNodePtr) ctxt->doc;
2867 } else {
2868#ifdef LIBXML_XPATH_ENABLED
2869 ctxt->pctxt->node = ctxt->node;
2870 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2871#else
2872 list = NULL;
2873#endif /* LIBXML_XPATH_ENABLED */
2874 if (list != NULL) {
2875 switch (list->type) {
2876 case XPATH_UNDEFINED:
2877 xmlGenericError(xmlGenericErrorContext,
2878 "%s: no such node\n", arg);
2879 break;
2880 case XPATH_NODESET:
Daniel Veillarda6825e82001-11-07 13:33:59 +00002881 if (list->nodesetval != NULL) {
2882 if (list->nodesetval->nodeNr == 1) {
2883 ctxt->node = list->nodesetval->nodeTab[0];
Daniel Veillard7a985a12003-07-06 17:57:42 +00002884 if ((ctxt->node != NULL) &&
2885 (ctxt->node->type ==
2886 XML_NAMESPACE_DECL)) {
2887 xmlGenericError(xmlGenericErrorContext,
2888 "cannot cd to namespace\n");
2889 ctxt->node = NULL;
2890 }
Daniel Veillarda6825e82001-11-07 13:33:59 +00002891 } else
2892 xmlGenericError(xmlGenericErrorContext,
2893 "%s is a %d Node Set\n",
2894 arg,
2895 list->nodesetval->nodeNr);
Daniel Veillard78d12092001-10-11 09:12:24 +00002896 } else
2897 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6825e82001-11-07 13:33:59 +00002898 "%s is an empty Node Set\n",
2899 arg);
Daniel Veillard78d12092001-10-11 09:12:24 +00002900 break;
2901 case XPATH_BOOLEAN:
2902 xmlGenericError(xmlGenericErrorContext,
2903 "%s is a Boolean\n", arg);
2904 break;
2905 case XPATH_NUMBER:
2906 xmlGenericError(xmlGenericErrorContext,
2907 "%s is a number\n", arg);
2908 break;
2909 case XPATH_STRING:
2910 xmlGenericError(xmlGenericErrorContext,
2911 "%s is a string\n", arg);
2912 break;
2913 case XPATH_POINT:
2914 xmlGenericError(xmlGenericErrorContext,
2915 "%s is a point\n", arg);
2916 break;
2917 case XPATH_RANGE:
2918 xmlGenericError(xmlGenericErrorContext,
2919 "%s is a range\n", arg);
2920 break;
2921 case XPATH_LOCATIONSET:
2922 xmlGenericError(xmlGenericErrorContext,
2923 "%s is a range\n", arg);
2924 break;
2925 case XPATH_USERS:
2926 xmlGenericError(xmlGenericErrorContext,
2927 "%s is user-defined\n", arg);
2928 break;
2929 case XPATH_XSLT_TREE:
2930 xmlGenericError(xmlGenericErrorContext,
2931 "%s is an XSLT value tree\n",
2932 arg);
2933 break;
2934 }
2935#ifdef LIBXML_XPATH_ENABLED
2936 xmlXPathFreeObject(list);
2937#endif
2938 } else {
2939 xmlGenericError(xmlGenericErrorContext,
2940 "%s: no such node\n", arg);
2941 }
2942 ctxt->pctxt->node = NULL;
2943 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002944#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002945 } else if (!strcmp(command, "cat")) {
2946 if (arg[0] == 0) {
2947 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
2948 } else {
2949 ctxt->pctxt->node = ctxt->node;
2950#ifdef LIBXML_XPATH_ENABLED
2951 ctxt->pctxt->node = ctxt->node;
2952 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2953#else
2954 list = NULL;
2955#endif /* LIBXML_XPATH_ENABLED */
2956 if (list != NULL) {
2957 switch (list->type) {
2958 case XPATH_UNDEFINED:
2959 xmlGenericError(xmlGenericErrorContext,
2960 "%s: no such node\n", arg);
2961 break;
2962 case XPATH_NODESET:{
2963 int indx;
2964
Daniel Veillarda6825e82001-11-07 13:33:59 +00002965 if (list->nodesetval == NULL)
2966 break;
2967
Daniel Veillard78d12092001-10-11 09:12:24 +00002968 for (indx = 0;
2969 indx < list->nodesetval->nodeNr;
2970 indx++) {
2971 if (i > 0)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002972 fprintf(ctxt->output, " -------\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002973 xmlShellCat(ctxt, NULL,
2974 list->nodesetval->
2975 nodeTab[indx], NULL);
2976 }
2977 break;
2978 }
2979 case XPATH_BOOLEAN:
2980 xmlGenericError(xmlGenericErrorContext,
2981 "%s is a Boolean\n", arg);
2982 break;
2983 case XPATH_NUMBER:
2984 xmlGenericError(xmlGenericErrorContext,
2985 "%s is a number\n", arg);
2986 break;
2987 case XPATH_STRING:
2988 xmlGenericError(xmlGenericErrorContext,
2989 "%s is a string\n", arg);
2990 break;
2991 case XPATH_POINT:
2992 xmlGenericError(xmlGenericErrorContext,
2993 "%s is a point\n", arg);
2994 break;
2995 case XPATH_RANGE:
2996 xmlGenericError(xmlGenericErrorContext,
2997 "%s is a range\n", arg);
2998 break;
2999 case XPATH_LOCATIONSET:
3000 xmlGenericError(xmlGenericErrorContext,
3001 "%s is a range\n", arg);
3002 break;
3003 case XPATH_USERS:
3004 xmlGenericError(xmlGenericErrorContext,
3005 "%s is user-defined\n", arg);
3006 break;
3007 case XPATH_XSLT_TREE:
3008 xmlGenericError(xmlGenericErrorContext,
3009 "%s is an XSLT value tree\n",
3010 arg);
3011 break;
3012 }
3013#ifdef LIBXML_XPATH_ENABLED
3014 xmlXPathFreeObject(list);
3015#endif
3016 } else {
3017 xmlGenericError(xmlGenericErrorContext,
3018 "%s: no such node\n", arg);
3019 }
3020 ctxt->pctxt->node = NULL;
3021 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003022#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00003023 } else {
3024 xmlGenericError(xmlGenericErrorContext,
3025 "Unknown command %s\n", command);
3026 }
3027 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00003028 }
3029#ifdef LIBXML_XPATH_ENABLED
3030 xmlXPathFreeContext(ctxt->pctxt);
3031#endif /* LIBXML_XPATH_ENABLED */
3032 if (ctxt->loaded) {
3033 xmlFreeDoc(ctxt->doc);
3034 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003035 if (ctxt->filename != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00003036 xmlFree(ctxt->filename);
Owen Taylor3473f882001-02-23 17:55:21 +00003037 xmlFree(ctxt);
3038 if (cmdline != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00003039 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00003040}
3041
3042#endif /* LIBXML_DEBUG_ENABLED */