blob: 1ae239607c1a67e4e943a367311fc99c16818361 [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 Veillardcfa303a2005-08-25 14:03:56 +000037#define DUMP_TEXT_TYPE 1
38
Daniel Veillard22cdb842004-10-04 14:09:17 +000039typedef struct _xmlDebugCtxt xmlDebugCtxt;
40typedef xmlDebugCtxt *xmlDebugCtxtPtr;
41struct _xmlDebugCtxt {
42 FILE *output; /* the output file */
43 char shift[101]; /* used for indenting */
44 int depth; /* current depth */
45 xmlDocPtr doc; /* current document */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000046 xmlNodePtr node; /* current node */
Daniel Veillard03a53c32004-10-26 16:06:51 +000047 xmlDictPtr dict; /* the doc dictionnary */
Daniel Veillard22cdb842004-10-04 14:09:17 +000048 int check; /* do just checkings */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000049 int errors; /* number of errors found */
Daniel Veillard03a53c32004-10-26 16:06:51 +000050 int nodict; /* if the document has no dictionnary */
Daniel Veillardcfa303a2005-08-25 14:03:56 +000051 int options; /* options */
Daniel Veillard22cdb842004-10-04 14:09:17 +000052};
53
54static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
55
56static void
57xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
58{
59 int i;
60
61 ctxt->depth = 0;
62 ctxt->check = 0;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000063 ctxt->errors = 0;
Daniel Veillard22cdb842004-10-04 14:09:17 +000064 ctxt->output = stdout;
Daniel Veillard03a53c32004-10-26 16:06:51 +000065 ctxt->doc = NULL;
66 ctxt->node = NULL;
67 ctxt->dict = NULL;
Daniel Veillard6927b102004-10-27 17:29:04 +000068 ctxt->nodict = 0;
Daniel Veillard22cdb842004-10-04 14:09:17 +000069 for (i = 0; i < 100; i++)
70 ctxt->shift[i] = ' ';
71 ctxt->shift[100] = 0;
72}
73
74static void
William M. Brack9638d4c2004-10-15 18:25:33 +000075xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)
Daniel Veillard76821142004-10-09 20:39:04 +000076{
William M. Brack9638d4c2004-10-15 18:25:33 +000077 /* remove the ATTRIBUTE_UNUSED when this is added */
Daniel Veillard76821142004-10-09 20:39:04 +000078}
79
80/**
Daniel Veillard0d24b112004-10-11 12:28:34 +000081 * xmlNsCheckScope:
82 * @node: the node
83 * @ns: the namespace node
Daniel Veillard76821142004-10-09 20:39:04 +000084 *
Daniel Veillard0d24b112004-10-11 12:28:34 +000085 * Check that a given namespace is in scope on a node.
Daniel Veillard76821142004-10-09 20:39:04 +000086 *
Daniel Veillard0d24b112004-10-11 12:28:34 +000087 * Returns 1 if in scope, -1 in case of argument error,
88 * -2 if the namespace is not in scope, and -3 if not on
89 * an ancestor node.
Daniel Veillard76821142004-10-09 20:39:04 +000090 */
91static int
Daniel Veillard0d24b112004-10-11 12:28:34 +000092xmlNsCheckScope(xmlNodePtr node, xmlNsPtr ns)
Daniel Veillard76821142004-10-09 20:39:04 +000093{
Daniel Veillard0d24b112004-10-11 12:28:34 +000094 xmlNsPtr cur;
Daniel Veillard76821142004-10-09 20:39:04 +000095
Daniel Veillard0d24b112004-10-11 12:28:34 +000096 if ((node == NULL) || (ns == NULL))
97 return(-1);
98
99 if ((node->type != XML_ELEMENT_NODE) &&
100 (node->type != XML_ATTRIBUTE_NODE) &&
101 (node->type != XML_DOCUMENT_NODE) &&
102 (node->type != XML_TEXT_NODE) &&
103 (node->type != XML_HTML_DOCUMENT_NODE) &&
104 (node->type != XML_XINCLUDE_START))
105 return(-2);
106
107 while ((node != NULL) &&
108 ((node->type == XML_ELEMENT_NODE) ||
109 (node->type == XML_ATTRIBUTE_NODE) ||
110 (node->type == XML_TEXT_NODE) ||
111 (node->type == XML_XINCLUDE_START))) {
112 if ((node->type == XML_ELEMENT_NODE) ||
113 (node->type == XML_XINCLUDE_START)) {
114 cur = node->nsDef;
115 while (cur != NULL) {
116 if (cur == ns)
117 return(1);
118 if (xmlStrEqual(cur->prefix, ns->prefix))
119 return(-2);
120 cur = cur->next;
121 }
Daniel Veillard76821142004-10-09 20:39:04 +0000122 }
Daniel Veillard0d24b112004-10-11 12:28:34 +0000123 node = node->parent;
Daniel Veillard76821142004-10-09 20:39:04 +0000124 }
Daniel Veillard0d24b112004-10-11 12:28:34 +0000125 /* the xml namespace may be declared on the document node */
126 if ((node != NULL) &&
127 ((node->type == XML_DOCUMENT_NODE) ||
128 (node->type == XML_HTML_DOCUMENT_NODE))) {
129 xmlNsPtr oldNs = ((xmlDocPtr) node)->oldNs;
130 if (oldNs == ns)
131 return(1);
132 }
133 return(-3);
Daniel Veillard76821142004-10-09 20:39:04 +0000134}
Daniel Veillard76821142004-10-09 20:39:04 +0000135
Daniel Veillard76821142004-10-09 20:39:04 +0000136static void
Daniel Veillard22cdb842004-10-04 14:09:17 +0000137xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
138{
139 if (ctxt->check)
140 return;
141 if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
142 if (ctxt->depth < 50)
143 fprintf(ctxt->output, &ctxt->shift[100 - 2 * ctxt->depth]);
144 else
145 fprintf(ctxt->output, ctxt->shift);
146 }
147}
148
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000149/**
150 * xmlDebugErr:
151 * @ctxt: a debug context
152 * @error: the error code
153 *
154 * Handle a debug error.
155 */
156static void
157xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
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);
165}
166static void
167xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int 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}
176static void
Daniel Veillardc6095782004-10-15 14:50:10 +0000177xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, const char *extra)
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000178{
179 ctxt->errors++;
180 __xmlRaiseError(NULL, NULL, NULL,
181 NULL, ctxt->node, XML_FROM_CHECK,
182 error, XML_ERR_ERROR, NULL, 0,
183 NULL, NULL, NULL, 0, 0,
184 msg, extra);
185}
186
Daniel Veillard0d24b112004-10-11 12:28:34 +0000187/**
188 * xmlCtxtNsCheckScope:
189 * @ctxt: the debugging context
190 * @node: the node
191 * @ns: the namespace node
192 *
193 * Report if a given namespace is is not in scope.
194 */
195static void
196xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt, xmlNodePtr node, xmlNsPtr ns)
197{
198 int ret;
199
200 ret = xmlNsCheckScope(node, ns);
201 if (ret == -2) {
202 if (ns->prefix == NULL)
203 xmlDebugErr(ctxt, XML_CHECK_NS_SCOPE,
204 "Reference to default namespace not in scope\n");
205 else
206 xmlDebugErr3(ctxt, XML_CHECK_NS_SCOPE,
207 "Reference to namespace '%s' not in scope\n",
208 (char *) ns->prefix);
209 }
210 if (ret == -3) {
211 if (ns->prefix == NULL)
212 xmlDebugErr(ctxt, XML_CHECK_NS_ANCESTOR,
213 "Reference to default namespace not on ancestor\n");
214 else
215 xmlDebugErr3(ctxt, XML_CHECK_NS_ANCESTOR,
216 "Reference to namespace '%s' not on ancestor\n",
217 (char *) ns->prefix);
218 }
219}
220
Daniel Veillardc6095782004-10-15 14:50:10 +0000221/**
222 * xmlCtxtCheckString:
223 * @ctxt: the debug context
224 * @str: the string
225 *
226 * Do debugging on the string, currently it just checks the UTF-8 content
227 */
228static void
229xmlCtxtCheckString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
230{
231 if (str == NULL) return;
232 if (ctxt->check) {
233 if (!xmlCheckUTF8(str)) {
Daniel Veillard03a53c32004-10-26 16:06:51 +0000234 xmlDebugErr3(ctxt, XML_CHECK_NOT_UTF8,
Daniel Veillardc6095782004-10-15 14:50:10 +0000235 "String is not UTF-8 %s", (const char *) str);
236 }
237 }
238}
239
Daniel Veillard03a53c32004-10-26 16:06:51 +0000240/**
241 * xmlCtxtCheckName:
242 * @ctxt: the debug context
243 * @name: the name
244 *
245 * Do debugging on the name, for example the dictionnary status and
246 * conformance to the Name production.
247 */
248static void
249xmlCtxtCheckName(xmlDebugCtxtPtr ctxt, const xmlChar * name)
250{
251 if (ctxt->check) {
252 if (name == NULL) {
253 xmlDebugErr(ctxt, XML_CHECK_NO_NAME, "Name is NULL");
254 return;
255 }
256 if (xmlValidateName(name, 0)) {
257 xmlDebugErr3(ctxt, XML_CHECK_NOT_NCNAME,
258 "Name is not an NCName '%s'", (const char *) name);
259 }
260 if ((ctxt->dict != NULL) &&
261 (!xmlDictOwns(ctxt->dict, name))) {
262 xmlDebugErr3(ctxt, XML_CHECK_OUTSIDE_DICT,
263 "Name is not from the document dictionnary '%s'",
264 (const char *) name);
265 }
266 }
267}
268
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000269static void
270xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard03a53c32004-10-26 16:06:51 +0000271 xmlDocPtr doc;
272 xmlDictPtr dict;
273
274 doc = node->doc;
275
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000276 if (node->parent == NULL)
277 xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
278 "Node has no parent\n");
Daniel Veillard03a53c32004-10-26 16:06:51 +0000279 if (node->doc == NULL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000280 xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
281 "Node has no doc\n");
Daniel Veillard03a53c32004-10-26 16:06:51 +0000282 dict = NULL;
283 } else {
284 dict = doc->dict;
285 if ((dict == NULL) && (ctxt->nodict == 0)) {
Daniel Veillard6927b102004-10-27 17:29:04 +0000286#if 0
287 /* desactivated right now as it raises too many errors */
288 if (doc->type == XML_DOCUMENT_NODE)
289 xmlDebugErr(ctxt, XML_CHECK_NO_DICT,
290 "Document has no dictionnary\n");
291#endif
Daniel Veillard03a53c32004-10-26 16:06:51 +0000292 ctxt->nodict = 1;
293 }
294 if (ctxt->doc == NULL)
295 ctxt->doc = doc;
296
297 if (ctxt->dict == NULL) {
298 ctxt->dict = dict;
299 }
300 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000301 if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
302 (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
303 xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
304 "Node doc differs from parent's one\n");
305 if (node->prev == NULL) {
306 if (node->type == XML_ATTRIBUTE_NODE) {
307 if ((node->parent != NULL) &&
308 (node != (xmlNodePtr) node->parent->properties))
309 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
310 "Attr has no prev and not first of attr list\n");
311
312 } else if ((node->parent != NULL) && (node->parent->children != node))
313 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
314 "Node has no prev and not first of parent list\n");
315 } else {
316 if (node->prev->next != node)
317 xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
318 "Node prev->next : back link wrong\n");
319 }
320 if (node->next == NULL) {
321 if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
322 (node->parent->last != node))
323 xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
324 "Node has no next and not last of parent list\n");
325 } else {
326 if (node->next->prev != node)
327 xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
328 "Node next->prev : forward link wrong\n");
Daniel Veillard0d24b112004-10-11 12:28:34 +0000329 if (node->next->parent != node->parent)
330 xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT,
331 "Node next->prev : forward link wrong\n");
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000332 }
Daniel Veillard0d24b112004-10-11 12:28:34 +0000333 if (node->type == XML_ELEMENT_NODE) {
334 xmlNsPtr ns;
335
336 ns = node->nsDef;
337 while (ns != NULL) {
338 xmlCtxtNsCheckScope(ctxt, node, ns);
339 ns = ns->next;
340 }
341 if (node->ns != NULL)
342 xmlCtxtNsCheckScope(ctxt, node, node->ns);
343 } else if (node->type == XML_ATTRIBUTE_NODE) {
344 if (node->ns != NULL)
345 xmlCtxtNsCheckScope(ctxt, node, node->ns);
346 }
347
Daniel Veillardc6095782004-10-15 14:50:10 +0000348 if ((node->type != XML_ELEMENT_NODE) &&
William M. Brack9638d4c2004-10-15 18:25:33 +0000349 (node->type != XML_ATTRIBUTE_NODE) &&
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000350 (node->type != XML_ELEMENT_DECL) &&
William M. Brack9638d4c2004-10-15 18:25:33 +0000351 (node->type != XML_ATTRIBUTE_DECL) &&
352 (node->type != XML_DTD_NODE) &&
William M. Brack0357a302005-07-06 17:39:14 +0000353 (node->type != XML_ELEMENT_DECL) &&
William M. Brack9638d4c2004-10-15 18:25:33 +0000354 (node->type != XML_HTML_DOCUMENT_NODE) &&
355 (node->type != XML_DOCUMENT_NODE)) {
Daniel Veillardc6095782004-10-15 14:50:10 +0000356 if (node->content != NULL)
William M. Brack9638d4c2004-10-15 18:25:33 +0000357 xmlCtxtCheckString(ctxt, (const xmlChar *) node->content);
Daniel Veillardc6095782004-10-15 14:50:10 +0000358 }
Daniel Veillard03a53c32004-10-26 16:06:51 +0000359 switch (node->type) {
360 case XML_ELEMENT_NODE:
361 case XML_ATTRIBUTE_NODE:
362 xmlCtxtCheckName(ctxt, node->name);
363 break;
364 case XML_TEXT_NODE:
365 if ((node->name == xmlStringText) ||
366 (node->name == xmlStringTextNoenc))
367 break;
368 /* some case of entity substitution can lead to this */
369 if ((ctxt->dict != NULL) &&
Daniel Veillard6927b102004-10-27 17:29:04 +0000370 (node->name == xmlDictLookup(ctxt->dict, BAD_CAST "nbktext",
371 7)))
Daniel Veillard03a53c32004-10-26 16:06:51 +0000372 break;
373
374 xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
375 "Text node has wrong name '%s'",
376 (const char *) node->name);
377 break;
378 case XML_COMMENT_NODE:
379 if (node->name == xmlStringComment)
380 break;
381 xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
382 "Comment node has wrong name '%s'",
383 (const char *) node->name);
384 break;
385 case XML_PI_NODE:
386 xmlCtxtCheckName(ctxt, node->name);
387 break;
388 case XML_CDATA_SECTION_NODE:
389 if (node->name == NULL)
390 break;
391 xmlDebugErr3(ctxt, XML_CHECK_NAME_NOT_NULL,
392 "CData section has non NULL name '%s'",
393 (const char *) node->name);
394 break;
395 case XML_ENTITY_REF_NODE:
396 case XML_ENTITY_NODE:
397 case XML_DOCUMENT_TYPE_NODE:
398 case XML_DOCUMENT_FRAG_NODE:
399 case XML_NOTATION_NODE:
400 case XML_DTD_NODE:
401 case XML_ELEMENT_DECL:
402 case XML_ATTRIBUTE_DECL:
403 case XML_ENTITY_DECL:
404 case XML_NAMESPACE_DECL:
405 case XML_XINCLUDE_START:
406 case XML_XINCLUDE_END:
407#ifdef LIBXML_DOCB_ENABLED
408 case XML_DOCB_DOCUMENT_NODE:
409#endif
410 case XML_DOCUMENT_NODE:
411 case XML_HTML_DOCUMENT_NODE:
412 break;
413 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000414}
415
Daniel Veillard22cdb842004-10-04 14:09:17 +0000416static void
417xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
418{
419 int i;
420
Daniel Veillardc6095782004-10-15 14:50:10 +0000421 if (ctxt->check) {
Daniel Veillard22cdb842004-10-04 14:09:17 +0000422 return;
Daniel Veillardc6095782004-10-15 14:50:10 +0000423 }
Daniel Veillard22cdb842004-10-04 14:09:17 +0000424 /* TODO: check UTF8 content of the string */
425 if (str == NULL) {
426 fprintf(ctxt->output, "(NULL)");
427 return;
428 }
429 for (i = 0; i < 40; i++)
430 if (str[i] == 0)
431 return;
432 else if (IS_BLANK_CH(str[i]))
433 fputc(' ', ctxt->output);
434 else if (str[i] >= 0x80)
435 fprintf(ctxt->output, "#%X", str[i]);
436 else
437 fputc(str[i], ctxt->output);
438 fprintf(ctxt->output, "...");
439}
440
441static void
442xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
443{
444 xmlCtxtDumpSpaces(ctxt);
445
446 if (dtd == NULL) {
447 if (!ctxt->check)
448 fprintf(ctxt->output, "DTD node is NULL\n");
449 return;
450 }
451
452 if (dtd->type != XML_DTD_NODE) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000453 xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
454 "Node is not a DTD");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000455 return;
456 }
457 if (!ctxt->check) {
458 if (dtd->name != NULL)
459 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
460 else
461 fprintf(ctxt->output, "DTD");
462 if (dtd->ExternalID != NULL)
463 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
464 if (dtd->SystemID != NULL)
465 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
466 fprintf(ctxt->output, "\n");
467 }
468 /*
469 * Do a bit of checking
470 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000471 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000472}
473
474static void
475xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
476{
477 xmlCtxtDumpSpaces(ctxt);
478
479 if (attr == NULL) {
480 if (!ctxt->check)
481 fprintf(ctxt->output, "Attribute declaration is NULL\n");
482 return;
483 }
484 if (attr->type != XML_ATTRIBUTE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000485 xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
486 "Node is not an attribute declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000487 return;
488 }
489 if (attr->name != NULL) {
490 if (!ctxt->check)
491 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
492 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000493 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
494 "Node attribute declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000495 if (attr->elem != NULL) {
496 if (!ctxt->check)
497 fprintf(ctxt->output, " for %s", (char *) attr->elem);
498 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000499 xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
500 "Node attribute declaration has no element name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000501 if (!ctxt->check) {
502 switch (attr->atype) {
503 case XML_ATTRIBUTE_CDATA:
504 fprintf(ctxt->output, " CDATA");
505 break;
506 case XML_ATTRIBUTE_ID:
507 fprintf(ctxt->output, " ID");
508 break;
509 case XML_ATTRIBUTE_IDREF:
510 fprintf(ctxt->output, " IDREF");
511 break;
512 case XML_ATTRIBUTE_IDREFS:
513 fprintf(ctxt->output, " IDREFS");
514 break;
515 case XML_ATTRIBUTE_ENTITY:
516 fprintf(ctxt->output, " ENTITY");
517 break;
518 case XML_ATTRIBUTE_ENTITIES:
519 fprintf(ctxt->output, " ENTITIES");
520 break;
521 case XML_ATTRIBUTE_NMTOKEN:
522 fprintf(ctxt->output, " NMTOKEN");
523 break;
524 case XML_ATTRIBUTE_NMTOKENS:
525 fprintf(ctxt->output, " NMTOKENS");
526 break;
527 case XML_ATTRIBUTE_ENUMERATION:
528 fprintf(ctxt->output, " ENUMERATION");
529 break;
530 case XML_ATTRIBUTE_NOTATION:
531 fprintf(ctxt->output, " NOTATION ");
532 break;
533 }
534 if (attr->tree != NULL) {
535 int indx;
536 xmlEnumerationPtr cur = attr->tree;
537
538 for (indx = 0; indx < 5; indx++) {
539 if (indx != 0)
540 fprintf(ctxt->output, "|%s", (char *) cur->name);
541 else
542 fprintf(ctxt->output, " (%s", (char *) cur->name);
543 cur = cur->next;
544 if (cur == NULL)
545 break;
546 }
547 if (cur == NULL)
548 fprintf(ctxt->output, ")");
549 else
550 fprintf(ctxt->output, "...)");
551 }
552 switch (attr->def) {
553 case XML_ATTRIBUTE_NONE:
554 break;
555 case XML_ATTRIBUTE_REQUIRED:
556 fprintf(ctxt->output, " REQUIRED");
557 break;
558 case XML_ATTRIBUTE_IMPLIED:
559 fprintf(ctxt->output, " IMPLIED");
560 break;
561 case XML_ATTRIBUTE_FIXED:
562 fprintf(ctxt->output, " FIXED");
563 break;
564 }
565 if (attr->defaultValue != NULL) {
566 fprintf(ctxt->output, "\"");
567 xmlCtxtDumpString(ctxt, attr->defaultValue);
568 fprintf(ctxt->output, "\"");
569 }
570 fprintf(ctxt->output, "\n");
571 }
572
573 /*
574 * Do a bit of checking
575 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000576 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000577}
578
579static void
580xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
581{
582 xmlCtxtDumpSpaces(ctxt);
583
584 if (elem == NULL) {
585 if (!ctxt->check)
586 fprintf(ctxt->output, "Element declaration is NULL\n");
587 return;
588 }
589 if (elem->type != XML_ELEMENT_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000590 xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
591 "Node is not an element declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000592 return;
593 }
594 if (elem->name != NULL) {
595 if (!ctxt->check) {
596 fprintf(ctxt->output, "ELEMDECL(");
597 xmlCtxtDumpString(ctxt, elem->name);
598 fprintf(ctxt->output, ")");
599 }
600 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000601 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
602 "Element declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000603 if (!ctxt->check) {
604 switch (elem->etype) {
605 case XML_ELEMENT_TYPE_UNDEFINED:
606 fprintf(ctxt->output, ", UNDEFINED");
607 break;
608 case XML_ELEMENT_TYPE_EMPTY:
609 fprintf(ctxt->output, ", EMPTY");
610 break;
611 case XML_ELEMENT_TYPE_ANY:
612 fprintf(ctxt->output, ", ANY");
613 break;
614 case XML_ELEMENT_TYPE_MIXED:
615 fprintf(ctxt->output, ", MIXED ");
616 break;
617 case XML_ELEMENT_TYPE_ELEMENT:
618 fprintf(ctxt->output, ", MIXED ");
619 break;
620 }
621 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
622 char buf[5001];
623
624 buf[0] = 0;
625 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
626 buf[5000] = 0;
627 fprintf(ctxt->output, "%s", buf);
628 }
629 fprintf(ctxt->output, "\n");
630 }
631
632 /*
633 * Do a bit of checking
634 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000635 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000636}
637
638static void
639xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
640{
641 xmlCtxtDumpSpaces(ctxt);
642
643 if (ent == NULL) {
644 if (!ctxt->check)
645 fprintf(ctxt->output, "Entity declaration is NULL\n");
646 return;
647 }
648 if (ent->type != XML_ENTITY_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000649 xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
650 "Node is not an entity declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000651 return;
652 }
653 if (ent->name != NULL) {
654 if (!ctxt->check) {
655 fprintf(ctxt->output, "ENTITYDECL(");
656 xmlCtxtDumpString(ctxt, ent->name);
657 fprintf(ctxt->output, ")");
658 }
659 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000660 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
661 "Entity declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000662 if (!ctxt->check) {
663 switch (ent->etype) {
664 case XML_INTERNAL_GENERAL_ENTITY:
665 fprintf(ctxt->output, ", internal\n");
666 break;
667 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
668 fprintf(ctxt->output, ", external parsed\n");
669 break;
670 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
671 fprintf(ctxt->output, ", unparsed\n");
672 break;
673 case XML_INTERNAL_PARAMETER_ENTITY:
674 fprintf(ctxt->output, ", parameter\n");
675 break;
676 case XML_EXTERNAL_PARAMETER_ENTITY:
677 fprintf(ctxt->output, ", external parameter\n");
678 break;
679 case XML_INTERNAL_PREDEFINED_ENTITY:
680 fprintf(ctxt->output, ", predefined\n");
681 break;
682 }
683 if (ent->ExternalID) {
684 xmlCtxtDumpSpaces(ctxt);
685 fprintf(ctxt->output, " ExternalID=%s\n",
686 (char *) ent->ExternalID);
687 }
688 if (ent->SystemID) {
689 xmlCtxtDumpSpaces(ctxt);
690 fprintf(ctxt->output, " SystemID=%s\n",
691 (char *) ent->SystemID);
692 }
693 if (ent->URI != NULL) {
694 xmlCtxtDumpSpaces(ctxt);
695 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
696 }
697 if (ent->content) {
698 xmlCtxtDumpSpaces(ctxt);
699 fprintf(ctxt->output, " content=");
700 xmlCtxtDumpString(ctxt, ent->content);
701 fprintf(ctxt->output, "\n");
702 }
703 }
704
705 /*
706 * Do a bit of checking
707 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000708 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000709}
710
711static void
712xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
713{
714 xmlCtxtDumpSpaces(ctxt);
715
716 if (ns == NULL) {
717 if (!ctxt->check)
718 fprintf(ctxt->output, "namespace node is NULL\n");
719 return;
720 }
721 if (ns->type != XML_NAMESPACE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000722 xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
723 "Node is not a namespace declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000724 return;
725 }
726 if (ns->href == NULL) {
727 if (ns->prefix != NULL)
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000728 xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
729 "Incomplete namespace %s href=NULL\n",
Daniel Veillard22cdb842004-10-04 14:09:17 +0000730 (char *) ns->prefix);
731 else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000732 xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
733 "Incomplete default namespace href=NULL\n");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000734 } else {
735 if (!ctxt->check) {
736 if (ns->prefix != NULL)
737 fprintf(ctxt->output, "namespace %s href=",
738 (char *) ns->prefix);
739 else
740 fprintf(ctxt->output, "default namespace href=");
741
742 xmlCtxtDumpString(ctxt, ns->href);
743 fprintf(ctxt->output, "\n");
744 }
745 }
746}
747
748static void
749xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
750{
751 while (ns != NULL) {
752 xmlCtxtDumpNamespace(ctxt, ns);
753 ns = ns->next;
754 }
755}
756
757static void
758xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
759{
760 xmlCtxtDumpSpaces(ctxt);
761
762 if (ent == NULL) {
763 if (!ctxt->check)
764 fprintf(ctxt->output, "Entity is NULL\n");
765 return;
766 }
767 if (!ctxt->check) {
768 switch (ent->etype) {
769 case XML_INTERNAL_GENERAL_ENTITY:
770 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
771 break;
772 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
773 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
774 break;
775 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
776 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
777 break;
778 case XML_INTERNAL_PARAMETER_ENTITY:
779 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
780 break;
781 case XML_EXTERNAL_PARAMETER_ENTITY:
782 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
783 break;
784 default:
785 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
786 }
787 fprintf(ctxt->output, "%s\n", ent->name);
788 if (ent->ExternalID) {
789 xmlCtxtDumpSpaces(ctxt);
790 fprintf(ctxt->output, "ExternalID=%s\n",
791 (char *) ent->ExternalID);
792 }
793 if (ent->SystemID) {
794 xmlCtxtDumpSpaces(ctxt);
795 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
796 }
797 if (ent->URI) {
798 xmlCtxtDumpSpaces(ctxt);
799 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
800 }
801 if (ent->content) {
802 xmlCtxtDumpSpaces(ctxt);
803 fprintf(ctxt->output, "content=");
804 xmlCtxtDumpString(ctxt, ent->content);
805 fprintf(ctxt->output, "\n");
806 }
807 }
808}
809
810/**
811 * xmlCtxtDumpAttr:
812 * @output: the FILE * for the output
813 * @attr: the attribute
814 * @depth: the indentation level.
815 *
816 * Dumps debug information for the attribute
817 */
818static void
819xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
820{
821 xmlCtxtDumpSpaces(ctxt);
822
823 if (attr == NULL) {
824 if (!ctxt->check)
825 fprintf(ctxt->output, "Attr is NULL");
826 return;
827 }
828 if (!ctxt->check) {
829 fprintf(ctxt->output, "ATTRIBUTE ");
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000830 xmlCtxtDumpString(ctxt, attr->name);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000831 fprintf(ctxt->output, "\n");
832 if (attr->children != NULL) {
833 ctxt->depth++;
834 xmlCtxtDumpNodeList(ctxt, attr->children);
835 ctxt->depth--;
836 }
837 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000838 if (attr->name == NULL)
839 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
840 "Attribute has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000841
842 /*
843 * Do a bit of checking
844 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000845 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000846}
847
848/**
849 * xmlCtxtDumpAttrList:
850 * @output: the FILE * for the output
851 * @attr: the attribute list
852 * @depth: the indentation level.
853 *
854 * Dumps debug information for the attribute list
855 */
856static void
857xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
858{
859 while (attr != NULL) {
860 xmlCtxtDumpAttr(ctxt, attr);
861 attr = attr->next;
862 }
863}
864
865/**
866 * xmlCtxtDumpOneNode:
867 * @output: the FILE * for the output
868 * @node: the node
869 * @depth: the indentation level.
870 *
871 * Dumps debug information for the element node, it is not recursive
872 */
873static void
874xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
875{
876 if (node == NULL) {
877 if (!ctxt->check) {
878 xmlCtxtDumpSpaces(ctxt);
879 fprintf(ctxt->output, "node is NULL\n");
880 }
881 return;
882 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000883 ctxt->node = node;
884
Daniel Veillard22cdb842004-10-04 14:09:17 +0000885 switch (node->type) {
886 case XML_ELEMENT_NODE:
887 if (!ctxt->check) {
888 xmlCtxtDumpSpaces(ctxt);
889 fprintf(ctxt->output, "ELEMENT ");
890 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
891 xmlCtxtDumpString(ctxt, node->ns->prefix);
892 fprintf(ctxt->output, ":");
893 }
894 xmlCtxtDumpString(ctxt, node->name);
895 fprintf(ctxt->output, "\n");
896 }
897 break;
898 case XML_ATTRIBUTE_NODE:
899 if (!ctxt->check)
900 xmlCtxtDumpSpaces(ctxt);
901 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
William M. Brack5a9c1fd2004-12-17 21:38:09 +0000902 xmlCtxtGenericNodeCheck(ctxt, node);
903 return;
Daniel Veillard22cdb842004-10-04 14:09:17 +0000904 case XML_TEXT_NODE:
905 if (!ctxt->check) {
906 xmlCtxtDumpSpaces(ctxt);
907 if (node->name == (const xmlChar *) xmlStringTextNoenc)
Daniel Veillard8874b942005-08-25 13:19:21 +0000908 fprintf(ctxt->output, "TEXT no enc");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000909 else
Daniel Veillard8874b942005-08-25 13:19:21 +0000910 fprintf(ctxt->output, "TEXT");
Daniel Veillardcfa303a2005-08-25 14:03:56 +0000911 if (ctxt->options & DUMP_TEXT_TYPE) {
912 if (node->content == (xmlChar *) &(node->properties))
913 fprintf(ctxt->output, " compact\n");
914 else if (xmlDictOwns(ctxt->dict, node->content) == 1)
915 fprintf(ctxt->output, " interned\n");
916 else
917 fprintf(ctxt->output, "\n");
918 } else
Daniel Veillard8874b942005-08-25 13:19:21 +0000919 fprintf(ctxt->output, "\n");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000920 }
921 break;
922 case XML_CDATA_SECTION_NODE:
923 if (!ctxt->check) {
924 xmlCtxtDumpSpaces(ctxt);
925 fprintf(ctxt->output, "CDATA_SECTION\n");
926 }
927 break;
928 case XML_ENTITY_REF_NODE:
929 if (!ctxt->check) {
930 xmlCtxtDumpSpaces(ctxt);
931 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
932 (char *) node->name);
933 }
934 break;
935 case XML_ENTITY_NODE:
936 if (!ctxt->check) {
937 xmlCtxtDumpSpaces(ctxt);
938 fprintf(ctxt->output, "ENTITY\n");
939 }
940 break;
941 case XML_PI_NODE:
942 if (!ctxt->check) {
943 xmlCtxtDumpSpaces(ctxt);
944 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
945 }
946 break;
947 case XML_COMMENT_NODE:
948 if (!ctxt->check) {
949 xmlCtxtDumpSpaces(ctxt);
950 fprintf(ctxt->output, "COMMENT\n");
951 }
952 break;
953 case XML_DOCUMENT_NODE:
954 case XML_HTML_DOCUMENT_NODE:
955 if (!ctxt->check) {
956 xmlCtxtDumpSpaces(ctxt);
957 }
William M. Brack5a9c1fd2004-12-17 21:38:09 +0000958 fprintf(ctxt->output, "Error, DOCUMENT found here\n");
959 xmlCtxtGenericNodeCheck(ctxt, node);
960 return;
Daniel Veillard22cdb842004-10-04 14:09:17 +0000961 case XML_DOCUMENT_TYPE_NODE:
962 if (!ctxt->check) {
963 xmlCtxtDumpSpaces(ctxt);
964 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
965 }
966 break;
967 case XML_DOCUMENT_FRAG_NODE:
968 if (!ctxt->check) {
969 xmlCtxtDumpSpaces(ctxt);
970 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
971 }
972 break;
973 case XML_NOTATION_NODE:
974 if (!ctxt->check) {
975 xmlCtxtDumpSpaces(ctxt);
976 fprintf(ctxt->output, "NOTATION\n");
977 }
978 break;
979 case XML_DTD_NODE:
980 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
981 return;
982 case XML_ELEMENT_DECL:
983 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
984 return;
985 case XML_ATTRIBUTE_DECL:
986 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
987 return;
988 case XML_ENTITY_DECL:
989 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
990 return;
991 case XML_NAMESPACE_DECL:
992 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
993 return;
994 case XML_XINCLUDE_START:
995 if (!ctxt->check) {
996 xmlCtxtDumpSpaces(ctxt);
997 fprintf(ctxt->output, "INCLUDE START\n");
998 }
999 return;
1000 case XML_XINCLUDE_END:
1001 if (!ctxt->check) {
1002 xmlCtxtDumpSpaces(ctxt);
1003 fprintf(ctxt->output, "INCLUDE END\n");
1004 }
1005 return;
1006 default:
1007 if (!ctxt->check)
1008 xmlCtxtDumpSpaces(ctxt);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001009 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
1010 "Unknown node type %d\n", node->type);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001011 return;
1012 }
1013 if (node->doc == NULL) {
1014 if (!ctxt->check) {
1015 xmlCtxtDumpSpaces(ctxt);
1016 }
1017 fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
1018 }
1019 ctxt->depth++;
Daniel Veillard8874b942005-08-25 13:19:21 +00001020 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
Daniel Veillard22cdb842004-10-04 14:09:17 +00001021 xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
Daniel Veillard8874b942005-08-25 13:19:21 +00001022 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
Daniel Veillard22cdb842004-10-04 14:09:17 +00001023 xmlCtxtDumpAttrList(ctxt, node->properties);
1024 if (node->type != XML_ENTITY_REF_NODE) {
1025 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
1026 if (!ctxt->check) {
1027 xmlCtxtDumpSpaces(ctxt);
1028 fprintf(ctxt->output, "content=");
1029 xmlCtxtDumpString(ctxt, node->content);
1030 fprintf(ctxt->output, "\n");
1031 }
1032 }
1033 } else {
1034 xmlEntityPtr ent;
1035
1036 ent = xmlGetDocEntity(node->doc, node->name);
1037 if (ent != NULL)
1038 xmlCtxtDumpEntity(ctxt, ent);
1039 }
1040 ctxt->depth--;
1041
1042 /*
1043 * Do a bit of checking
1044 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001045 xmlCtxtGenericNodeCheck(ctxt, node);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001046}
1047
1048/**
1049 * xmlCtxtDumpNode:
1050 * @output: the FILE * for the output
1051 * @node: the node
1052 * @depth: the indentation level.
1053 *
1054 * Dumps debug information for the element node, it is recursive
1055 */
1056static void
1057xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1058{
1059 if (node == NULL) {
1060 if (!ctxt->check) {
1061 xmlCtxtDumpSpaces(ctxt);
1062 fprintf(ctxt->output, "node is NULL\n");
1063 }
1064 return;
1065 }
1066 xmlCtxtDumpOneNode(ctxt, node);
1067 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1068 ctxt->depth++;
1069 xmlCtxtDumpNodeList(ctxt, node->children);
1070 ctxt->depth--;
1071 }
1072}
1073
1074/**
1075 * xmlCtxtDumpNodeList:
1076 * @output: the FILE * for the output
1077 * @node: the node list
1078 * @depth: the indentation level.
1079 *
1080 * Dumps debug information for the list of element node, it is recursive
1081 */
1082static void
1083xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1084{
1085 while (node != NULL) {
1086 xmlCtxtDumpNode(ctxt, node);
1087 node = node->next;
1088 }
1089}
1090
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001091static void
1092xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1093{
1094 if (doc == NULL) {
1095 if (!ctxt->check)
1096 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1097 return;
1098 }
1099 ctxt->node = (xmlNodePtr) doc;
1100
1101 switch (doc->type) {
1102 case XML_ELEMENT_NODE:
1103 xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
1104 "Misplaced ELEMENT node\n");
1105 break;
1106 case XML_ATTRIBUTE_NODE:
1107 xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
1108 "Misplaced ATTRIBUTE node\n");
1109 break;
1110 case XML_TEXT_NODE:
1111 xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
1112 "Misplaced TEXT node\n");
1113 break;
1114 case XML_CDATA_SECTION_NODE:
1115 xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
1116 "Misplaced CDATA node\n");
1117 break;
1118 case XML_ENTITY_REF_NODE:
1119 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
1120 "Misplaced ENTITYREF node\n");
1121 break;
1122 case XML_ENTITY_NODE:
1123 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
1124 "Misplaced ENTITY node\n");
1125 break;
1126 case XML_PI_NODE:
1127 xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
1128 "Misplaced PI node\n");
1129 break;
1130 case XML_COMMENT_NODE:
1131 xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
1132 "Misplaced COMMENT node\n");
1133 break;
1134 case XML_DOCUMENT_NODE:
1135 if (!ctxt->check)
1136 fprintf(ctxt->output, "DOCUMENT\n");
1137 break;
1138 case XML_HTML_DOCUMENT_NODE:
1139 if (!ctxt->check)
1140 fprintf(ctxt->output, "HTML DOCUMENT\n");
1141 break;
1142 case XML_DOCUMENT_TYPE_NODE:
1143 xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
1144 "Misplaced DOCTYPE node\n");
1145 break;
1146 case XML_DOCUMENT_FRAG_NODE:
1147 xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
1148 "Misplaced FRAGMENT node\n");
1149 break;
1150 case XML_NOTATION_NODE:
1151 xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
1152 "Misplaced NOTATION node\n");
1153 break;
1154 default:
1155 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
1156 "Unknown node type %d\n", doc->type);
1157 }
1158}
Daniel Veillard22cdb842004-10-04 14:09:17 +00001159
1160/**
1161 * xmlCtxtDumpDocumentHead:
1162 * @output: the FILE * for the output
1163 * @doc: the document
1164 *
1165 * Dumps debug information cncerning the document, not recursive
1166 */
1167static void
1168xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1169{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001170 if (doc == NULL) return;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001171 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001172 if (!ctxt->check) {
1173 if (doc->name != NULL) {
1174 fprintf(ctxt->output, "name=");
1175 xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
1176 fprintf(ctxt->output, "\n");
1177 }
1178 if (doc->version != NULL) {
1179 fprintf(ctxt->output, "version=");
1180 xmlCtxtDumpString(ctxt, doc->version);
1181 fprintf(ctxt->output, "\n");
1182 }
1183 if (doc->encoding != NULL) {
1184 fprintf(ctxt->output, "encoding=");
1185 xmlCtxtDumpString(ctxt, doc->encoding);
1186 fprintf(ctxt->output, "\n");
1187 }
1188 if (doc->URL != NULL) {
1189 fprintf(ctxt->output, "URL=");
1190 xmlCtxtDumpString(ctxt, doc->URL);
1191 fprintf(ctxt->output, "\n");
1192 }
1193 if (doc->standalone)
1194 fprintf(ctxt->output, "standalone=true\n");
1195 }
1196 if (doc->oldNs != NULL)
1197 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
1198}
1199
1200/**
1201 * xmlCtxtDumpDocument:
1202 * @output: the FILE * for the output
1203 * @doc: the document
1204 *
1205 * Dumps debug information for the document, it's recursive
1206 */
1207static void
1208xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1209{
1210 if (doc == NULL) {
1211 if (!ctxt->check)
1212 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1213 return;
1214 }
1215 xmlCtxtDumpDocumentHead(ctxt, doc);
1216 if (((doc->type == XML_DOCUMENT_NODE) ||
1217 (doc->type == XML_HTML_DOCUMENT_NODE))
1218 && (doc->children != NULL)) {
1219 ctxt->depth++;
1220 xmlCtxtDumpNodeList(ctxt, doc->children);
1221 ctxt->depth--;
1222 }
1223}
1224
1225static void
1226xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt)
1227{
1228 if (cur == NULL) {
1229 if (!ctxt->check)
1230 fprintf(ctxt->output, "Entity is NULL");
1231 return;
1232 }
1233 if (!ctxt->check) {
1234 fprintf(ctxt->output, "%s : ", (char *) cur->name);
1235 switch (cur->etype) {
1236 case XML_INTERNAL_GENERAL_ENTITY:
1237 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1238 break;
1239 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1240 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1241 break;
1242 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1243 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1244 break;
1245 case XML_INTERNAL_PARAMETER_ENTITY:
1246 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1247 break;
1248 case XML_EXTERNAL_PARAMETER_ENTITY:
1249 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1250 break;
1251 default:
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001252 xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1253 "Unknown entity type %d\n", cur->etype);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001254 }
1255 if (cur->ExternalID != NULL)
1256 fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1257 if (cur->SystemID != NULL)
1258 fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1259 if (cur->orig != NULL)
1260 fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1261 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1262 fprintf(ctxt->output, "\n content \"%s\"",
1263 (char *) cur->content);
1264 fprintf(ctxt->output, "\n");
1265 }
1266}
1267
1268/**
1269 * xmlCtxtDumpEntities:
1270 * @output: the FILE * for the output
1271 * @doc: the document
1272 *
1273 * Dumps debug information for all the entities in use by the document
1274 */
1275static void
1276xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1277{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001278 if (doc == NULL) return;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001279 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001280 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1281 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1282 doc->intSubset->entities;
1283
1284 if (!ctxt->check)
1285 fprintf(ctxt->output, "Entities in internal subset\n");
1286 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1287 ctxt);
1288 } else
1289 fprintf(ctxt->output, "No entities in internal subset\n");
1290 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1291 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1292 doc->extSubset->entities;
1293
1294 if (!ctxt->check)
1295 fprintf(ctxt->output, "Entities in external subset\n");
1296 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1297 ctxt);
1298 } else if (!ctxt->check)
1299 fprintf(ctxt->output, "No entities in external subset\n");
1300}
1301
1302/**
1303 * xmlCtxtDumpDTD:
1304 * @output: the FILE * for the output
1305 * @dtd: the DTD
1306 *
1307 * Dumps debug information for the DTD
1308 */
1309static void
1310xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1311{
1312 if (dtd == NULL) {
1313 if (!ctxt->check)
1314 fprintf(ctxt->output, "DTD is NULL\n");
1315 return;
1316 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001317 xmlCtxtDumpDtdNode(ctxt, dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001318 if (dtd->children == NULL)
1319 fprintf(ctxt->output, " DTD is empty\n");
1320 else {
1321 ctxt->depth++;
1322 xmlCtxtDumpNodeList(ctxt, dtd->children);
1323 ctxt->depth--;
1324 }
1325}
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001326
Daniel Veillard22cdb842004-10-04 14:09:17 +00001327/************************************************************************
1328 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001329 * Public entry points for dump *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001330 * *
1331 ************************************************************************/
1332
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001333/**
1334 * xmlDebugDumpString:
1335 * @output: the FILE * for the output
1336 * @str: the string
1337 *
1338 * Dumps informations about the string, shorten it if necessary
1339 */
1340void
1341xmlDebugDumpString(FILE * output, const xmlChar * str)
1342{
Owen Taylor3473f882001-02-23 17:55:21 +00001343 int i;
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001344
Daniel Veillard7db38712002-02-07 16:39:11 +00001345 if (output == NULL)
1346 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00001347 if (str == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001348 fprintf(output, "(NULL)");
1349 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001350 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001351 for (i = 0; i < 40; i++)
1352 if (str[i] == 0)
1353 return;
William M. Brack76e95df2003-10-18 16:20:14 +00001354 else if (IS_BLANK_CH(str[i]))
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001355 fputc(' ', output);
1356 else if (str[i] >= 0x80)
1357 fprintf(output, "#%X", str[i]);
1358 else
1359 fputc(str[i], output);
Owen Taylor3473f882001-02-23 17:55:21 +00001360 fprintf(output, "...");
1361}
1362
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001363/**
1364 * xmlDebugDumpAttr:
1365 * @output: the FILE * for the output
1366 * @attr: the attribute
1367 * @depth: the indentation level.
1368 *
1369 * Dumps debug information for the attribute
1370 */
1371void
1372xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
Daniel Veillard22cdb842004-10-04 14:09:17 +00001373 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001374
Daniel Veillarda82b1822004-11-08 16:24:57 +00001375 if (output == NULL) return;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001376 xmlCtxtDumpInitCtxt(&ctxt);
1377 ctxt.output = output;
1378 ctxt.depth = depth;
1379 xmlCtxtDumpAttr(&ctxt, attr);
Daniel Veillard76821142004-10-09 20:39:04 +00001380 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001381}
Owen Taylor3473f882001-02-23 17:55:21 +00001382
Owen Taylor3473f882001-02-23 17:55:21 +00001383
Daniel Veillard22cdb842004-10-04 14:09:17 +00001384/**
1385 * xmlDebugDumpEntities:
1386 * @output: the FILE * for the output
1387 * @doc: the document
1388 *
1389 * Dumps debug information for all the entities in use by the document
1390 */
1391void
1392xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1393{
1394 xmlDebugCtxt ctxt;
1395
Daniel Veillarda82b1822004-11-08 16:24:57 +00001396 if (output == NULL) return;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001397 xmlCtxtDumpInitCtxt(&ctxt);
1398 ctxt.output = output;
1399 xmlCtxtDumpEntities(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001400 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001401}
1402
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001403/**
1404 * xmlDebugDumpAttrList:
1405 * @output: the FILE * for the output
1406 * @attr: the attribute list
1407 * @depth: the indentation level.
1408 *
1409 * Dumps debug information for the attribute list
1410 */
1411void
1412xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1413{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001414 xmlDebugCtxt ctxt;
1415
Daniel Veillarda82b1822004-11-08 16:24:57 +00001416 if (output == NULL) return;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001417 xmlCtxtDumpInitCtxt(&ctxt);
1418 ctxt.output = output;
1419 ctxt.depth = depth;
1420 xmlCtxtDumpAttrList(&ctxt, attr);
Daniel Veillard76821142004-10-09 20:39:04 +00001421 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001422}
1423
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001424/**
1425 * xmlDebugDumpOneNode:
1426 * @output: the FILE * for the output
1427 * @node: the node
1428 * @depth: the indentation level.
1429 *
1430 * Dumps debug information for the element node, it is not recursive
1431 */
1432void
1433xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1434{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001435 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001436
Daniel Veillarda82b1822004-11-08 16:24:57 +00001437 if (output == NULL) return;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001438 xmlCtxtDumpInitCtxt(&ctxt);
1439 ctxt.output = output;
1440 ctxt.depth = depth;
1441 xmlCtxtDumpOneNode(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001442 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001443}
1444
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001445/**
1446 * xmlDebugDumpNode:
1447 * @output: the FILE * for the output
1448 * @node: the node
1449 * @depth: the indentation level.
1450 *
1451 * Dumps debug information for the element node, it is recursive
1452 */
1453void
1454xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1455{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001456 xmlDebugCtxt ctxt;
1457
Daniel Veillard7db38712002-02-07 16:39:11 +00001458 if (output == NULL)
1459 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001460 xmlCtxtDumpInitCtxt(&ctxt);
1461 ctxt.output = output;
1462 ctxt.depth = depth;
1463 xmlCtxtDumpNode(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001464 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001465}
1466
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001467/**
1468 * xmlDebugDumpNodeList:
1469 * @output: the FILE * for the output
1470 * @node: the node list
1471 * @depth: the indentation level.
1472 *
1473 * Dumps debug information for the list of element node, it is recursive
1474 */
1475void
1476xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1477{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001478 xmlDebugCtxt ctxt;
1479
Daniel Veillard7db38712002-02-07 16:39:11 +00001480 if (output == NULL)
1481 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001482 xmlCtxtDumpInitCtxt(&ctxt);
1483 ctxt.output = output;
1484 ctxt.depth = depth;
1485 xmlCtxtDumpNodeList(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001486 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001487}
1488
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001489/**
1490 * xmlDebugDumpDocumentHead:
1491 * @output: the FILE * for the output
1492 * @doc: the document
1493 *
1494 * Dumps debug information cncerning the document, not recursive
1495 */
1496void
1497xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1498{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001499 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001500
Daniel Veillard22cdb842004-10-04 14:09:17 +00001501 if (output == NULL)
1502 output = stdout;
1503 xmlCtxtDumpInitCtxt(&ctxt);
Daniel Veillardcfa303a2005-08-25 14:03:56 +00001504 ctxt.options |= DUMP_TEXT_TYPE;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001505 ctxt.output = output;
1506 xmlCtxtDumpDocumentHead(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001507 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001508}
1509
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001510/**
1511 * xmlDebugDumpDocument:
1512 * @output: the FILE * for the output
1513 * @doc: the document
1514 *
1515 * Dumps debug information for the document, it's recursive
1516 */
1517void
1518xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1519{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001520 xmlDebugCtxt ctxt;
1521
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001522 if (output == NULL)
Daniel Veillard22cdb842004-10-04 14:09:17 +00001523 output = stdout;
1524 xmlCtxtDumpInitCtxt(&ctxt);
Daniel Veillardcfa303a2005-08-25 14:03:56 +00001525 ctxt.options |= DUMP_TEXT_TYPE;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001526 ctxt.output = output;
1527 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001528 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001529}
Owen Taylor3473f882001-02-23 17:55:21 +00001530
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001531/**
1532 * xmlDebugDumpDTD:
1533 * @output: the FILE * for the output
1534 * @dtd: the DTD
1535 *
1536 * Dumps debug information for the DTD
1537 */
1538void
1539xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1540{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001541 xmlDebugCtxt ctxt;
1542
Daniel Veillard7db38712002-02-07 16:39:11 +00001543 if (output == NULL)
1544 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001545 xmlCtxtDumpInitCtxt(&ctxt);
Daniel Veillardcfa303a2005-08-25 14:03:56 +00001546 ctxt.options |= DUMP_TEXT_TYPE;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001547 ctxt.output = output;
1548 xmlCtxtDumpDTD(&ctxt, dtd);
Daniel Veillard76821142004-10-09 20:39:04 +00001549 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001550}
1551
Daniel Veillard22cdb842004-10-04 14:09:17 +00001552/************************************************************************
1553 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001554 * Public entry points for checkings *
1555 * *
1556 ************************************************************************/
1557
1558/**
1559 * xmlDebugCheckDocument:
1560 * @output: the FILE * for the output
1561 * @doc: the document
1562 *
1563 * Check the document for potential content problems, and output
1564 * the errors to @output
1565 *
1566 * Returns the number of errors found
1567 */
1568int
1569xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1570{
1571 xmlDebugCtxt ctxt;
1572
1573 if (output == NULL)
1574 output = stdout;
1575 xmlCtxtDumpInitCtxt(&ctxt);
1576 ctxt.output = output;
1577 ctxt.check = 1;
1578 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001579 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001580 return(ctxt.errors);
1581}
1582
1583/************************************************************************
1584 * *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001585 * Helpers for Shell *
1586 * *
1587 ************************************************************************/
Owen Taylor3473f882001-02-23 17:55:21 +00001588
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001589/**
1590 * xmlLsCountNode:
1591 * @node: the node to count
1592 *
1593 * Count the children of @node.
1594 *
1595 * Returns the number of children of @node.
1596 */
1597int
1598xmlLsCountNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001599 int ret = 0;
1600 xmlNodePtr list = NULL;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001601
1602 if (node == NULL)
1603 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001604
1605 switch (node->type) {
1606 case XML_ELEMENT_NODE:
1607 list = node->children;
1608 break;
1609 case XML_DOCUMENT_NODE:
1610 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00001611#ifdef LIBXML_DOCB_ENABLED
1612 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00001613#endif
1614 list = ((xmlDocPtr) node)->children;
1615 break;
1616 case XML_ATTRIBUTE_NODE:
1617 list = ((xmlAttrPtr) node)->children;
1618 break;
1619 case XML_TEXT_NODE:
1620 case XML_CDATA_SECTION_NODE:
1621 case XML_PI_NODE:
1622 case XML_COMMENT_NODE:
1623 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001624 ret = xmlStrlen(node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001625 }
1626 break;
1627 case XML_ENTITY_REF_NODE:
1628 case XML_DOCUMENT_TYPE_NODE:
1629 case XML_ENTITY_NODE:
1630 case XML_DOCUMENT_FRAG_NODE:
1631 case XML_NOTATION_NODE:
1632 case XML_DTD_NODE:
1633 case XML_ELEMENT_DECL:
1634 case XML_ATTRIBUTE_DECL:
1635 case XML_ENTITY_DECL:
1636 case XML_NAMESPACE_DECL:
1637 case XML_XINCLUDE_START:
1638 case XML_XINCLUDE_END:
1639 ret = 1;
1640 break;
1641 }
1642 for (;list != NULL;ret++)
1643 list = list->next;
1644 return(ret);
1645}
1646
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001647/**
1648 * xmlLsOneNode:
1649 * @output: the FILE * for the output
1650 * @node: the node to dump
1651 *
1652 * Dump to @output the type and name of @node.
1653 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001654void
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001655xmlLsOneNode(FILE *output, xmlNodePtr node) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001656 if (output == NULL) return;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001657 if (node == NULL) {
1658 fprintf(output, "NULL\n");
1659 return;
1660 }
Owen Taylor3473f882001-02-23 17:55:21 +00001661 switch (node->type) {
1662 case XML_ELEMENT_NODE:
1663 fprintf(output, "-");
1664 break;
1665 case XML_ATTRIBUTE_NODE:
1666 fprintf(output, "a");
1667 break;
1668 case XML_TEXT_NODE:
1669 fprintf(output, "t");
1670 break;
1671 case XML_CDATA_SECTION_NODE:
Daniel Veillard75be0132002-03-13 10:03:35 +00001672 fprintf(output, "C");
Owen Taylor3473f882001-02-23 17:55:21 +00001673 break;
1674 case XML_ENTITY_REF_NODE:
1675 fprintf(output, "e");
1676 break;
1677 case XML_ENTITY_NODE:
1678 fprintf(output, "E");
1679 break;
1680 case XML_PI_NODE:
1681 fprintf(output, "p");
1682 break;
1683 case XML_COMMENT_NODE:
1684 fprintf(output, "c");
1685 break;
1686 case XML_DOCUMENT_NODE:
1687 fprintf(output, "d");
1688 break;
1689 case XML_HTML_DOCUMENT_NODE:
1690 fprintf(output, "h");
1691 break;
1692 case XML_DOCUMENT_TYPE_NODE:
1693 fprintf(output, "T");
1694 break;
1695 case XML_DOCUMENT_FRAG_NODE:
1696 fprintf(output, "F");
1697 break;
1698 case XML_NOTATION_NODE:
1699 fprintf(output, "N");
1700 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001701 case XML_NAMESPACE_DECL:
1702 fprintf(output, "n");
1703 break;
Owen Taylor3473f882001-02-23 17:55:21 +00001704 default:
1705 fprintf(output, "?");
1706 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00001707 if (node->type != XML_NAMESPACE_DECL) {
1708 if (node->properties != NULL)
1709 fprintf(output, "a");
1710 else
1711 fprintf(output, "-");
1712 if (node->nsDef != NULL)
1713 fprintf(output, "n");
1714 else
1715 fprintf(output, "-");
1716 }
Owen Taylor3473f882001-02-23 17:55:21 +00001717
1718 fprintf(output, " %8d ", xmlLsCountNode(node));
1719
1720 switch (node->type) {
1721 case XML_ELEMENT_NODE:
1722 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001723 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001724 break;
1725 case XML_ATTRIBUTE_NODE:
1726 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001727 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001728 break;
1729 case XML_TEXT_NODE:
1730 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001731 xmlDebugDumpString(output, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001732 }
1733 break;
1734 case XML_CDATA_SECTION_NODE:
1735 break;
1736 case XML_ENTITY_REF_NODE:
1737 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001738 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001739 break;
1740 case XML_ENTITY_NODE:
1741 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001742 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001743 break;
1744 case XML_PI_NODE:
1745 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001746 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001747 break;
1748 case XML_COMMENT_NODE:
1749 break;
1750 case XML_DOCUMENT_NODE:
1751 break;
1752 case XML_HTML_DOCUMENT_NODE:
1753 break;
1754 case XML_DOCUMENT_TYPE_NODE:
1755 break;
1756 case XML_DOCUMENT_FRAG_NODE:
1757 break;
1758 case XML_NOTATION_NODE:
1759 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001760 case XML_NAMESPACE_DECL: {
1761 xmlNsPtr ns = (xmlNsPtr) node;
1762
1763 if (ns->prefix == NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00001764 fprintf(output, "default -> %s", (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001765 else
William M. Brack13dfa872004-09-18 04:52:08 +00001766 fprintf(output, "%s -> %s", (char *)ns->prefix,
1767 (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001768 break;
1769 }
Owen Taylor3473f882001-02-23 17:55:21 +00001770 default:
1771 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001772 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001773 }
1774 fprintf(output, "\n");
1775}
1776
Daniel Veillard78d12092001-10-11 09:12:24 +00001777/**
1778 * xmlBoolToText:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001779 * @boolval: a bool to turn into text
Daniel Veillard78d12092001-10-11 09:12:24 +00001780 *
1781 * Convenient way to turn bool into text
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001782 *
1783 * Returns a pointer to either "True" or "False"
1784 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001785const char *
Daniel Veillardebd38c52001-11-01 08:38:12 +00001786xmlBoolToText(int boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001787{
Daniel Veillardebd38c52001-11-01 08:38:12 +00001788 if (boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001789 return("True");
1790 else
1791 return("False");
1792}
1793
Daniel Veillardd0cf7f62004-11-09 16:17:02 +00001794#ifdef LIBXML_XPATH_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001795/****************************************************************
1796 * *
1797 * The XML shell related functions *
1798 * *
1799 ****************************************************************/
1800
Daniel Veillard78d12092001-10-11 09:12:24 +00001801
1802
Owen Taylor3473f882001-02-23 17:55:21 +00001803/*
1804 * TODO: Improvement/cleanups for the XML shell
1805 * - allow to shell out an editor on a subpart
1806 * - cleanup function registrations (with help) and calling
1807 * - provide registration routines
1808 */
1809
1810/**
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001811 * xmlShellPrintXPathError:
Daniel Veillard78d12092001-10-11 09:12:24 +00001812 * @errorType: valid xpath error id
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001813 * @arg: the argument that cause xpath to fail
Daniel Veillard78d12092001-10-11 09:12:24 +00001814 *
1815 * Print the xpath error to libxml default error channel
1816 */
1817void
1818xmlShellPrintXPathError(int errorType, const char *arg)
1819{
1820 const char *default_arg = "Result";
1821
1822 if (!arg)
1823 arg = default_arg;
1824
1825 switch (errorType) {
1826 case XPATH_UNDEFINED:
1827 xmlGenericError(xmlGenericErrorContext,
1828 "%s: no such node\n", arg);
1829 break;
1830
1831 case XPATH_BOOLEAN:
1832 xmlGenericError(xmlGenericErrorContext,
1833 "%s is a Boolean\n", arg);
1834 break;
1835 case XPATH_NUMBER:
1836 xmlGenericError(xmlGenericErrorContext,
1837 "%s is a number\n", arg);
1838 break;
1839 case XPATH_STRING:
1840 xmlGenericError(xmlGenericErrorContext,
1841 "%s is a string\n", arg);
1842 break;
1843 case XPATH_POINT:
1844 xmlGenericError(xmlGenericErrorContext,
1845 "%s is a point\n", arg);
1846 break;
1847 case XPATH_RANGE:
1848 xmlGenericError(xmlGenericErrorContext,
1849 "%s is a range\n", arg);
1850 break;
1851 case XPATH_LOCATIONSET:
1852 xmlGenericError(xmlGenericErrorContext,
1853 "%s is a range\n", arg);
1854 break;
1855 case XPATH_USERS:
1856 xmlGenericError(xmlGenericErrorContext,
1857 "%s is user-defined\n", arg);
1858 break;
1859 case XPATH_XSLT_TREE:
1860 xmlGenericError(xmlGenericErrorContext,
1861 "%s is an XSLT value tree\n", arg);
1862 break;
1863 }
Daniel Veillarda82b1822004-11-08 16:24:57 +00001864#if 0
Daniel Veillard78d12092001-10-11 09:12:24 +00001865 xmlGenericError(xmlGenericErrorContext,
1866 "Try casting the result string function (xpath builtin)\n",
1867 arg);
Daniel Veillarda82b1822004-11-08 16:24:57 +00001868#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00001869}
1870
1871
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001872#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001873/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001874 * xmlShellPrintNodeCtxt:
1875 * @ctxt : a non-null shell context
1876 * @node : a non-null node to print to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001877 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001878 * Print node to the output FILE
1879 */
1880static void
1881xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1882{
Daniel Veillard01992e02002-10-09 10:20:30 +00001883 FILE *fp;
1884
1885 if (!node)
Daniel Veillard321be0c2002-10-08 21:26:42 +00001886 return;
Daniel Veillard01992e02002-10-09 10:20:30 +00001887 if (ctxt == NULL)
1888 fp = stdout;
1889 else
1890 fp = ctxt->output;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001891
1892 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001893 xmlDocDump(fp, (xmlDocPtr) node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001894 else if (node->type == XML_ATTRIBUTE_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001895 xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001896 else
Daniel Veillard01992e02002-10-09 10:20:30 +00001897 xmlElemDump(fp, node->doc, node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001898
Daniel Veillard01992e02002-10-09 10:20:30 +00001899 fprintf(fp, "\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00001900}
1901
1902/**
1903 * xmlShellPrintNode:
1904 * @node : a non-null node to print to the output FILE
1905 *
1906 * Print node to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001907 */
1908void
1909xmlShellPrintNode(xmlNodePtr node)
1910{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001911 xmlShellPrintNodeCtxt(NULL, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001912}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001913#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001914
Daniel Veillard78d12092001-10-11 09:12:24 +00001915/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001916 * xmlShellPrintXPathResultCtxt:
1917 * @ctxt: a valid shell context
Daniel Veillard9d06d302002-01-22 18:15:52 +00001918 * @list: a valid result generated by an xpath evaluation
Daniel Veillard78d12092001-10-11 09:12:24 +00001919 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001920 * Prints result to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001921 */
Daniel Veillard321be0c2002-10-08 21:26:42 +00001922static void
1923xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
Daniel Veillard78d12092001-10-11 09:12:24 +00001924{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001925 if (!ctxt)
1926 return;
Daniel Veillard78d12092001-10-11 09:12:24 +00001927
1928 if (list != NULL) {
1929 switch (list->type) {
1930 case XPATH_NODESET:{
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001931#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001932 int indx;
1933
1934 if (list->nodesetval) {
1935 for (indx = 0; indx < list->nodesetval->nodeNr;
1936 indx++) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001937 xmlShellPrintNodeCtxt(ctxt,
1938 list->nodesetval->nodeTab[indx]);
Daniel Veillard78d12092001-10-11 09:12:24 +00001939 }
1940 } else {
1941 xmlGenericError(xmlGenericErrorContext,
1942 "Empty node set\n");
1943 }
1944 break;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001945#else
1946 xmlGenericError(xmlGenericErrorContext,
1947 "Node set\n");
1948#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001949 }
1950 case XPATH_BOOLEAN:
1951 xmlGenericError(xmlGenericErrorContext,
1952 "Is a Boolean:%s\n",
1953 xmlBoolToText(list->boolval));
1954 break;
1955 case XPATH_NUMBER:
1956 xmlGenericError(xmlGenericErrorContext,
1957 "Is a number:%0g\n", list->floatval);
1958 break;
1959 case XPATH_STRING:
1960 xmlGenericError(xmlGenericErrorContext,
1961 "Is a string:%s\n", list->stringval);
1962 break;
1963
1964 default:
1965 xmlShellPrintXPathError(list->type, NULL);
1966 }
1967 }
1968}
1969
1970/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001971 * xmlShellPrintXPathResult:
1972 * @list: a valid result generated by an xpath evaluation
1973 *
1974 * Prints result to the output FILE
1975 */
1976void
1977xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1978{
1979 xmlShellPrintXPathResultCtxt(NULL, list);
1980}
1981
1982/**
Owen Taylor3473f882001-02-23 17:55:21 +00001983 * xmlShellList:
1984 * @ctxt: the shell context
1985 * @arg: unused
1986 * @node: a node
1987 * @node2: unused
1988 *
1989 * Implements the XML shell function "ls"
1990 * Does an Unix like listing of the given node (like a directory)
1991 *
1992 * Returns 0
1993 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001994int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001995xmlShellList(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001996 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1997 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1998{
Owen Taylor3473f882001-02-23 17:55:21 +00001999 xmlNodePtr cur;
Daniel Veillard321be0c2002-10-08 21:26:42 +00002000 if (!ctxt)
2001 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002002 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002003 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002004 return (0);
2005 }
Owen Taylor3473f882001-02-23 17:55:21 +00002006 if ((node->type == XML_DOCUMENT_NODE) ||
2007 (node->type == XML_HTML_DOCUMENT_NODE)) {
2008 cur = ((xmlDocPtr) node)->children;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002009 } else if (node->type == XML_NAMESPACE_DECL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002010 xmlLsOneNode(ctxt->output, node);
Daniel Veillarde6a55192002-01-14 17:11:53 +00002011 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002012 } else if (node->children != NULL) {
2013 cur = node->children;
2014 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002015 xmlLsOneNode(ctxt->output, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002016 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002017 }
2018 while (cur != NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002019 xmlLsOneNode(ctxt->output, cur);
Daniel Veillard78d12092001-10-11 09:12:24 +00002020 cur = cur->next;
Owen Taylor3473f882001-02-23 17:55:21 +00002021 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002022 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002023}
2024
2025/**
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002026 * xmlShellBase:
2027 * @ctxt: the shell context
2028 * @arg: unused
2029 * @node: a node
2030 * @node2: unused
2031 *
2032 * Implements the XML shell function "base"
2033 * dumps the current XML base of the node
2034 *
2035 * Returns 0
2036 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002037int
Daniel Veillard321be0c2002-10-08 21:26:42 +00002038xmlShellBase(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00002039 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2040 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2041{
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002042 xmlChar *base;
Daniel Veillard321be0c2002-10-08 21:26:42 +00002043 if (!ctxt)
2044 return 0;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002045 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002046 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002047 return (0);
2048 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002049
2050 base = xmlNodeGetBase(node->doc, node);
2051
2052 if (base == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002053 fprintf(ctxt->output, " No base found !!!\n");
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002054 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002055 fprintf(ctxt->output, "%s\n", base);
Daniel Veillard78d12092001-10-11 09:12:24 +00002056 xmlFree(base);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002057 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002058 return (0);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002059}
2060
Daniel Veillardb34321c2004-03-04 17:09:47 +00002061#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002062/**
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002063 * xmlShellSetBase:
2064 * @ctxt: the shell context
2065 * @arg: the new base
2066 * @node: a node
2067 * @node2: unused
2068 *
2069 * Implements the XML shell function "setbase"
2070 * change the current XML base of the node
2071 *
2072 * Returns 0
2073 */
2074static int
2075xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2076 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2077 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2078{
2079 xmlNodeSetBase(node, (xmlChar*) arg);
2080 return (0);
2081}
Daniel Veillard2156d432004-03-04 15:59:36 +00002082#endif
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002083
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002084#ifdef LIBXML_XPATH_ENABLED
2085/**
2086 * xmlShellRegisterNamespace:
2087 * @ctxt: the shell context
2088 * @arg: a string in prefix=nsuri format
2089 * @node: unused
2090 * @node2: unused
2091 *
2092 * Implements the XML shell function "setns"
2093 * register/unregister a prefix=namespace pair
2094 * on the XPath context
2095 *
2096 * Returns 0 on success and a negative value otherwise.
2097 */
2098static int
2099xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
2100 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2101{
2102 xmlChar* nsListDup;
2103 xmlChar* prefix;
2104 xmlChar* href;
2105 xmlChar* next;
2106
2107 nsListDup = xmlStrdup((xmlChar *) arg);
2108 next = nsListDup;
2109 while(next != NULL) {
2110 /* skip spaces */
2111 /*while((*next) == ' ') next++;*/
2112 if((*next) == '\0') break;
2113
2114 /* find prefix */
2115 prefix = next;
2116 next = (xmlChar*)xmlStrchr(next, '=');
2117 if(next == NULL) {
2118 fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
2119 xmlFree(nsListDup);
2120 return(-1);
2121 }
2122 *(next++) = '\0';
2123
2124 /* find href */
2125 href = next;
2126 next = (xmlChar*)xmlStrchr(next, ' ');
2127 if(next != NULL) {
2128 *(next++) = '\0';
2129 }
2130
2131 /* do register namespace */
2132 if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
2133 fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
2134 xmlFree(nsListDup);
2135 return(-1);
2136 }
2137 }
2138
2139 xmlFree(nsListDup);
2140 return(0);
2141}
Daniel Veillard20887ee2005-07-04 09:27:40 +00002142/**
2143 * xmlShellRegisterRootNamespaces:
2144 * @ctxt: the shell context
2145 * @arg: unused
2146 * @node: the root element
2147 * @node2: unused
2148 *
2149 * Implements the XML shell function "setrootns"
2150 * which registers all namespaces declarations found on the root element.
2151 *
2152 * Returns 0 on success and a negative value otherwise.
2153 */
2154static int
2155xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2156 xmlNodePtr root, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2157{
2158 xmlNsPtr ns;
2159
2160 if ((root == NULL) || (root->type != XML_ELEMENT_NODE) ||
2161 (root->nsDef == NULL) || (ctxt == NULL) || (ctxt->pctxt == NULL))
2162 return(-1);
2163 ns = root->nsDef;
2164 while (ns != NULL) {
2165 if (ns->prefix == NULL)
2166 xmlXPathRegisterNs(ctxt->pctxt, BAD_CAST "defaultns", ns->href);
2167 else
2168 xmlXPathRegisterNs(ctxt->pctxt, ns->prefix, ns->href);
2169 ns = ns->next;
2170 }
2171 return(0);
2172}
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002173#endif
2174
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002175/**
Daniel Veillard1e208222002-10-22 14:25:25 +00002176 * xmlShellGrep:
2177 * @ctxt: the shell context
2178 * @arg: the string or regular expression to find
2179 * @node: a node
2180 * @node2: unused
2181 *
2182 * Implements the XML shell function "grep"
2183 * dumps informations about the node (namespace, attributes, content).
2184 *
2185 * Returns 0
2186 */
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002187static int
Daniel Veillard1e208222002-10-22 14:25:25 +00002188xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2189 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2190{
2191 if (!ctxt)
2192 return (0);
2193 if (node == NULL)
2194 return (0);
2195 if (arg == NULL)
2196 return (0);
2197#ifdef LIBXML_REGEXP_ENABLED
2198 if ((xmlStrchr((xmlChar *) arg, '?')) ||
2199 (xmlStrchr((xmlChar *) arg, '*')) ||
2200 (xmlStrchr((xmlChar *) arg, '.')) ||
2201 (xmlStrchr((xmlChar *) arg, '['))) {
2202 }
2203#endif
2204 while (node != NULL) {
2205 if (node->type == XML_COMMENT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002206 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00002207
2208 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
2209 xmlShellList(ctxt, NULL, node, NULL);
2210 }
2211 } else if (node->type == XML_TEXT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002212 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00002213
2214 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002215 xmlShellList(ctxt, NULL, node->parent, NULL);
Daniel Veillard1e208222002-10-22 14:25:25 +00002216 }
2217 }
2218
2219 /*
2220 * Browse the full subtree, deep first
2221 */
2222
2223 if ((node->type == XML_DOCUMENT_NODE) ||
2224 (node->type == XML_HTML_DOCUMENT_NODE)) {
2225 node = ((xmlDocPtr) node)->children;
2226 } else if ((node->children != NULL)
2227 && (node->type != XML_ENTITY_REF_NODE)) {
2228 /* deep first */
2229 node = node->children;
2230 } else if (node->next != NULL) {
2231 /* then siblings */
2232 node = node->next;
2233 } else {
2234 /* go up to parents->next if needed */
2235 while (node != NULL) {
2236 if (node->parent != NULL) {
2237 node = node->parent;
2238 }
2239 if (node->next != NULL) {
2240 node = node->next;
2241 break;
2242 }
2243 if (node->parent == NULL) {
2244 node = NULL;
2245 break;
2246 }
2247 }
2248 }
2249 }
2250 return (0);
2251}
2252
2253/**
Owen Taylor3473f882001-02-23 17:55:21 +00002254 * xmlShellDir:
2255 * @ctxt: the shell context
2256 * @arg: unused
2257 * @node: a node
2258 * @node2: unused
2259 *
2260 * Implements the XML shell function "dir"
2261 * dumps informations about the node (namespace, attributes, content).
2262 *
2263 * Returns 0
2264 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002265int
2266xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2267 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2268 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2269{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002270 if (!ctxt)
2271 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002272 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002273 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002274 return (0);
2275 }
Owen Taylor3473f882001-02-23 17:55:21 +00002276 if ((node->type == XML_DOCUMENT_NODE) ||
2277 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002278 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
Owen Taylor3473f882001-02-23 17:55:21 +00002279 } else if (node->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002280 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002281 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002282 xmlDebugDumpOneNode(ctxt->output, node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002283 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002284 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002285}
2286
Daniel Veillard29b17482004-08-16 00:39:03 +00002287/**
2288 * xmlShellSetContent:
2289 * @ctxt: the shell context
2290 * @value: the content as a string
2291 * @node: a node
2292 * @node2: unused
2293 *
2294 * Implements the XML shell function "dir"
2295 * dumps informations about the node (namespace, attributes, content).
2296 *
2297 * Returns 0
2298 */
2299static int
2300xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2301 char *value, xmlNodePtr node,
2302 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2303{
2304 xmlNodePtr results;
2305 xmlParserErrors ret;
2306
2307 if (!ctxt)
2308 return (0);
2309 if (node == NULL) {
2310 fprintf(ctxt->output, "NULL\n");
2311 return (0);
2312 }
2313 if (value == NULL) {
2314 fprintf(ctxt->output, "NULL\n");
2315 return (0);
2316 }
2317
2318 ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
2319 if (ret == XML_ERR_OK) {
2320 if (node->children != NULL) {
2321 xmlFreeNodeList(node->children);
2322 node->children = NULL;
2323 node->last = NULL;
2324 }
2325 xmlAddChildList(node, results);
2326 } else {
2327 fprintf(ctxt->output, "failed to parse content\n");
2328 }
2329 return (0);
2330}
2331
Daniel Veillard522bc602004-02-21 11:53:09 +00002332#ifdef LIBXML_SCHEMAS_ENABLED
2333/**
2334 * xmlShellRNGValidate:
2335 * @ctxt: the shell context
2336 * @schemas: the path to the Relax-NG schemas
2337 * @node: a node
2338 * @node2: unused
2339 *
2340 * Implements the XML shell function "relaxng"
2341 * validating the instance against a Relax-NG schemas
2342 *
2343 * Returns 0
2344 */
2345static int
2346xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2347 xmlNodePtr node ATTRIBUTE_UNUSED,
2348 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2349{
2350 xmlRelaxNGPtr relaxngschemas;
2351 xmlRelaxNGParserCtxtPtr ctxt;
2352 xmlRelaxNGValidCtxtPtr vctxt;
2353 int ret;
2354
2355 ctxt = xmlRelaxNGNewParserCtxt(schemas);
2356 xmlRelaxNGSetParserErrors(ctxt,
2357 (xmlRelaxNGValidityErrorFunc) fprintf,
2358 (xmlRelaxNGValidityWarningFunc) fprintf,
2359 stderr);
2360 relaxngschemas = xmlRelaxNGParse(ctxt);
2361 xmlRelaxNGFreeParserCtxt(ctxt);
2362 if (relaxngschemas == NULL) {
2363 xmlGenericError(xmlGenericErrorContext,
2364 "Relax-NG schema %s failed to compile\n", schemas);
2365 return(-1);
2366 }
2367 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2368 xmlRelaxNGSetValidErrors(vctxt,
2369 (xmlRelaxNGValidityErrorFunc) fprintf,
2370 (xmlRelaxNGValidityWarningFunc) fprintf,
2371 stderr);
2372 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2373 if (ret == 0) {
2374 fprintf(stderr, "%s validates\n", sctxt->filename);
2375 } else if (ret > 0) {
2376 fprintf(stderr, "%s fails to validate\n", sctxt->filename);
2377 } else {
2378 fprintf(stderr, "%s validation generated an internal error\n",
2379 sctxt->filename);
2380 }
2381 xmlRelaxNGFreeValidCtxt(vctxt);
2382 if (relaxngschemas != NULL)
2383 xmlRelaxNGFree(relaxngschemas);
2384 return(0);
2385}
2386#endif
2387
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002388#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002389/**
2390 * xmlShellCat:
2391 * @ctxt: the shell context
2392 * @arg: unused
2393 * @node: a node
2394 * @node2: unused
2395 *
2396 * Implements the XML shell function "cat"
2397 * dumps the serialization node content (XML or HTML).
2398 *
2399 * Returns 0
2400 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002401int
2402xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2403 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2404{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002405 if (!ctxt)
2406 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002407 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002408 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002409 return (0);
2410 }
Owen Taylor3473f882001-02-23 17:55:21 +00002411 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2412#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002413 if (node->type == XML_HTML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002414 htmlDocDump(ctxt->output, (htmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002415 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002416 htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002417#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002418 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002419 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002420 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002421 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002422#endif /* LIBXML_HTML_ENABLED */
2423 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00002424 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002425 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002426 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002427 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002428 }
Daniel Veillard321be0c2002-10-08 21:26:42 +00002429 fprintf(ctxt->output, "\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002430 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002431}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002432#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002433
2434/**
2435 * xmlShellLoad:
2436 * @ctxt: the shell context
2437 * @filename: the file name
2438 * @node: unused
2439 * @node2: unused
2440 *
2441 * Implements the XML shell function "load"
2442 * loads a new document specified by the filename
2443 *
2444 * Returns 0 or -1 if loading failed
2445 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002446int
2447xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2448 xmlNodePtr node ATTRIBUTE_UNUSED,
2449 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2450{
Owen Taylor3473f882001-02-23 17:55:21 +00002451 xmlDocPtr doc;
2452 int html = 0;
2453
Daniel Veillarda82b1822004-11-08 16:24:57 +00002454 if ((ctxt == NULL) || (filename == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002455 if (ctxt->doc != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002456 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00002457
2458 if (html) {
2459#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002460 doc = htmlParseFile(filename, NULL);
2461#else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002462 fprintf(ctxt->output, "HTML support not compiled in\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002463 doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002464#endif /* LIBXML_HTML_ENABLED */
2465 } else {
Daniel Veillardebe25d42004-03-25 09:35:49 +00002466 doc = xmlReadFile(filename,NULL,0);
Owen Taylor3473f882001-02-23 17:55:21 +00002467 }
2468 if (doc != NULL) {
2469 if (ctxt->loaded == 1) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002470 xmlFreeDoc(ctxt->doc);
2471 }
2472 ctxt->loaded = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002473#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002474 xmlXPathFreeContext(ctxt->pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002475#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002476 xmlFree(ctxt->filename);
2477 ctxt->doc = doc;
2478 ctxt->node = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002479#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002480 ctxt->pctxt = xmlXPathNewContext(doc);
Owen Taylor3473f882001-02-23 17:55:21 +00002481#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard85095e22003-04-23 13:56:44 +00002482 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002483 } else
Daniel Veillard78d12092001-10-11 09:12:24 +00002484 return (-1);
2485 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002486}
2487
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002488#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002489/**
2490 * xmlShellWrite:
2491 * @ctxt: the shell context
2492 * @filename: the file name
2493 * @node: a node in the tree
2494 * @node2: unused
2495 *
2496 * Implements the XML shell function "write"
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002497 * Write the current node to the filename, it saves the serialization
Owen Taylor3473f882001-02-23 17:55:21 +00002498 * of the subtree under the @node specified
2499 *
2500 * Returns 0 or -1 in case of error
2501 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002502int
Owen Taylor3473f882001-02-23 17:55:21 +00002503xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
Daniel Veillard78d12092001-10-11 09:12:24 +00002504 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2505{
Owen Taylor3473f882001-02-23 17:55:21 +00002506 if (node == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002507 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002508 if ((filename == NULL) || (filename[0] == 0)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002509 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002510 }
2511#ifdef W_OK
2512 if (access((char *) filename, W_OK)) {
2513 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002514 "Cannot write to %s\n", filename);
2515 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002516 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002517#endif
2518 switch (node->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002519 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002520 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2521 xmlGenericError(xmlGenericErrorContext,
2522 "Failed to write to %s\n", filename);
2523 return (-1);
2524 }
2525 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002526 case XML_HTML_DOCUMENT_NODE:
2527#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002528 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2529 xmlGenericError(xmlGenericErrorContext,
2530 "Failed to write to %s\n", filename);
2531 return (-1);
2532 }
Owen Taylor3473f882001-02-23 17:55:21 +00002533#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002534 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2535 xmlGenericError(xmlGenericErrorContext,
2536 "Failed to write to %s\n", filename);
2537 return (-1);
2538 }
Owen Taylor3473f882001-02-23 17:55:21 +00002539#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002540 break;
2541 default:{
2542 FILE *f;
Owen Taylor3473f882001-02-23 17:55:21 +00002543
Daniel Veillard78d12092001-10-11 09:12:24 +00002544 f = fopen((char *) filename, "w");
2545 if (f == NULL) {
2546 xmlGenericError(xmlGenericErrorContext,
2547 "Failed to write to %s\n", filename);
2548 return (-1);
2549 }
2550 xmlElemDump(f, ctxt->doc, node);
2551 fclose(f);
2552 }
Owen Taylor3473f882001-02-23 17:55:21 +00002553 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002554 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002555}
2556
2557/**
2558 * xmlShellSave:
2559 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002560 * @filename: the file name (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002561 * @node: unused
2562 * @node2: unused
2563 *
2564 * Implements the XML shell function "save"
2565 * Write the current document to the filename, or it's original name
2566 *
2567 * Returns 0 or -1 in case of error
2568 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002569int
2570xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2571 xmlNodePtr node ATTRIBUTE_UNUSED,
2572 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2573{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002574 if ((ctxt == NULL) || (ctxt->doc == NULL))
Daniel Veillard78d12092001-10-11 09:12:24 +00002575 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002576 if ((filename == NULL) || (filename[0] == 0))
2577 filename = ctxt->filename;
Daniel Veillarda82b1822004-11-08 16:24:57 +00002578 if (filename == NULL)
2579 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002580#ifdef W_OK
2581 if (access((char *) filename, W_OK)) {
2582 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002583 "Cannot save to %s\n", filename);
2584 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002585 }
2586#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002587 switch (ctxt->doc->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002588 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002589 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2590 xmlGenericError(xmlGenericErrorContext,
2591 "Failed to save to %s\n", filename);
2592 }
2593 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002594 case XML_HTML_DOCUMENT_NODE:
2595#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002596 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2597 xmlGenericError(xmlGenericErrorContext,
2598 "Failed to save to %s\n", filename);
2599 }
Owen Taylor3473f882001-02-23 17:55:21 +00002600#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002601 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2602 xmlGenericError(xmlGenericErrorContext,
2603 "Failed to save to %s\n", filename);
2604 }
Owen Taylor3473f882001-02-23 17:55:21 +00002605#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002606 break;
2607 default:
2608 xmlGenericError(xmlGenericErrorContext,
2609 "To save to subparts of a document use the 'write' command\n");
2610 return (-1);
2611
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002613 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002614}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002615#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002616
Daniel Veillardf54cd532004-02-25 11:52:31 +00002617#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002618/**
2619 * xmlShellValidate:
2620 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002621 * @dtd: the DTD URI (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002622 * @node: unused
2623 * @node2: unused
2624 *
2625 * Implements the XML shell function "validate"
2626 * Validate the document, if a DTD path is provided, then the validation
2627 * is done against the given DTD.
2628 *
2629 * Returns 0 or -1 in case of error
2630 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002631int
2632xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2633 xmlNodePtr node ATTRIBUTE_UNUSED,
2634 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2635{
Owen Taylor3473f882001-02-23 17:55:21 +00002636 xmlValidCtxt vctxt;
2637 int res = -1;
2638
Daniel Veillarda82b1822004-11-08 16:24:57 +00002639 if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002640 vctxt.userData = stderr;
2641 vctxt.error = (xmlValidityErrorFunc) fprintf;
2642 vctxt.warning = (xmlValidityWarningFunc) fprintf;
2643
2644 if ((dtd == NULL) || (dtd[0] == 0)) {
2645 res = xmlValidateDocument(&vctxt, ctxt->doc);
2646 } else {
2647 xmlDtdPtr subset;
2648
Daniel Veillard78d12092001-10-11 09:12:24 +00002649 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2650 if (subset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002651 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2652
Daniel Veillard78d12092001-10-11 09:12:24 +00002653 xmlFreeDtd(subset);
2654 }
Owen Taylor3473f882001-02-23 17:55:21 +00002655 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002656 return (res);
Owen Taylor3473f882001-02-23 17:55:21 +00002657}
Daniel Veillardf54cd532004-02-25 11:52:31 +00002658#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002659
2660/**
2661 * xmlShellDu:
2662 * @ctxt: the shell context
2663 * @arg: unused
2664 * @tree: a node defining a subtree
2665 * @node2: unused
2666 *
2667 * Implements the XML shell function "du"
2668 * show the structure of the subtree under node @tree
2669 * If @tree is null, the command works on the current node.
2670 *
2671 * Returns 0 or -1 in case of error
2672 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002673int
Daniel Veillard321be0c2002-10-08 21:26:42 +00002674xmlShellDu(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00002675 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2676 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2677{
Owen Taylor3473f882001-02-23 17:55:21 +00002678 xmlNodePtr node;
Daniel Veillard78d12092001-10-11 09:12:24 +00002679 int indent = 0, i;
Owen Taylor3473f882001-02-23 17:55:21 +00002680
Daniel Veillard321be0c2002-10-08 21:26:42 +00002681 if (!ctxt)
2682 return (-1);
2683
Daniel Veillard78d12092001-10-11 09:12:24 +00002684 if (tree == NULL)
2685 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002686 node = tree;
2687 while (node != NULL) {
2688 if ((node->type == XML_DOCUMENT_NODE) ||
2689 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002690 fprintf(ctxt->output, "/\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002691 } else if (node->type == XML_ELEMENT_NODE) {
2692 for (i = 0; i < indent; i++)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002693 fprintf(ctxt->output, " ");
2694 fprintf(ctxt->output, "%s\n", node->name);
Daniel Veillard78d12092001-10-11 09:12:24 +00002695 } else {
2696 }
Owen Taylor3473f882001-02-23 17:55:21 +00002697
Daniel Veillard78d12092001-10-11 09:12:24 +00002698 /*
2699 * Browse the full subtree, deep first
2700 */
Owen Taylor3473f882001-02-23 17:55:21 +00002701
2702 if ((node->type == XML_DOCUMENT_NODE) ||
2703 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002704 node = ((xmlDocPtr) node)->children;
2705 } else if ((node->children != NULL)
2706 && (node->type != XML_ENTITY_REF_NODE)) {
2707 /* deep first */
2708 node = node->children;
2709 indent++;
2710 } else if ((node != tree) && (node->next != NULL)) {
2711 /* then siblings */
2712 node = node->next;
2713 } else if (node != tree) {
2714 /* go up to parents->next if needed */
2715 while (node != tree) {
2716 if (node->parent != NULL) {
2717 node = node->parent;
2718 indent--;
2719 }
2720 if ((node != tree) && (node->next != NULL)) {
2721 node = node->next;
2722 break;
2723 }
2724 if (node->parent == NULL) {
2725 node = NULL;
2726 break;
2727 }
2728 if (node == tree) {
2729 node = NULL;
2730 break;
2731 }
2732 }
2733 /* exit condition */
2734 if (node == tree)
2735 node = NULL;
2736 } else
2737 node = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002738 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002739 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002740}
2741
2742/**
2743 * xmlShellPwd:
2744 * @ctxt: the shell context
2745 * @buffer: the output buffer
Daniel Veillard9d06d302002-01-22 18:15:52 +00002746 * @node: a node
Owen Taylor3473f882001-02-23 17:55:21 +00002747 * @node2: unused
2748 *
2749 * Implements the XML shell function "pwd"
2750 * Show the full path from the root to the node, if needed building
2751 * thumblers when similar elements exists at a given ancestor level.
2752 * The output is compatible with XPath commands.
2753 *
2754 * Returns 0 or -1 in case of error
2755 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002756int
2757xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2758 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2759{
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002760 xmlChar *path;
Owen Taylor3473f882001-02-23 17:55:21 +00002761
Daniel Veillarda82b1822004-11-08 16:24:57 +00002762 if ((node == NULL) || (buffer == NULL))
Daniel Veillard78d12092001-10-11 09:12:24 +00002763 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002764
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002765 path = xmlGetNodePath(node);
2766 if (path == NULL)
2767 return (-1);
2768
2769 /*
2770 * This test prevents buffer overflow, because this routine
2771 * is only called by xmlShell, in which the second argument is
2772 * 500 chars long.
2773 * It is a dirty hack before a cleaner solution is found.
2774 * Documentation should mention that the second argument must
2775 * be at least 500 chars long, and could be stripped if too long.
2776 */
2777 snprintf(buffer, 499, "%s", path);
2778 buffer[499] = '0';
2779 xmlFree(path);
2780
Daniel Veillard78d12092001-10-11 09:12:24 +00002781 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002782}
2783
2784/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002785 * xmlShell:
Owen Taylor3473f882001-02-23 17:55:21 +00002786 * @doc: the initial document
2787 * @filename: the output buffer
2788 * @input: the line reading function
Daniel Veillard321be0c2002-10-08 21:26:42 +00002789 * @output: the output FILE*, defaults to stdout if NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002790 *
2791 * Implements the XML shell
2792 * This allow to load, validate, view, modify and save a document
2793 * using a environment similar to a UNIX commandline.
2794 */
2795void
2796xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
Daniel Veillard78d12092001-10-11 09:12:24 +00002797 FILE * output)
2798{
Owen Taylor3473f882001-02-23 17:55:21 +00002799 char prompt[500] = "/ > ";
2800 char *cmdline = NULL, *cur;
2801 int nbargs;
2802 char command[100];
2803 char arg[400];
2804 int i;
2805 xmlShellCtxtPtr ctxt;
2806 xmlXPathObjectPtr list;
2807
2808 if (doc == NULL)
2809 return;
2810 if (filename == NULL)
2811 return;
2812 if (input == NULL)
2813 return;
2814 if (output == NULL)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002815 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00002816 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
Daniel Veillard78d12092001-10-11 09:12:24 +00002817 if (ctxt == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002818 return;
2819 ctxt->loaded = 0;
2820 ctxt->doc = doc;
2821 ctxt->input = input;
2822 ctxt->output = output;
2823 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
Daniel Veillard78d12092001-10-11 09:12:24 +00002824 ctxt->node = (xmlNodePtr) ctxt->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002825
2826#ifdef LIBXML_XPATH_ENABLED
2827 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2828 if (ctxt->pctxt == NULL) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002829 xmlFree(ctxt);
2830 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002831 }
2832#endif /* LIBXML_XPATH_ENABLED */
2833 while (1) {
2834 if (ctxt->node == (xmlNodePtr) ctxt->doc)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002835 snprintf(prompt, sizeof(prompt), "%s > ", "/");
Daniel Veillard7a985a12003-07-06 17:57:42 +00002836 else if ((ctxt->node != NULL) && (ctxt->node->name))
Daniel Veillard78d12092001-10-11 09:12:24 +00002837 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002838 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002839 snprintf(prompt, sizeof(prompt), "? > ");
Owen Taylor3473f882001-02-23 17:55:21 +00002840 prompt[sizeof(prompt) - 1] = 0;
2841
Daniel Veillard78d12092001-10-11 09:12:24 +00002842 /*
2843 * Get a new command line
2844 */
Owen Taylor3473f882001-02-23 17:55:21 +00002845 cmdline = ctxt->input(prompt);
Daniel Veillard78d12092001-10-11 09:12:24 +00002846 if (cmdline == NULL)
2847 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002848
Daniel Veillard78d12092001-10-11 09:12:24 +00002849 /*
2850 * Parse the command itself
2851 */
2852 cur = cmdline;
2853 nbargs = 0;
2854 while ((*cur == ' ') || (*cur == '\t'))
2855 cur++;
2856 i = 0;
2857 while ((*cur != ' ') && (*cur != '\t') &&
2858 (*cur != '\n') && (*cur != '\r')) {
2859 if (*cur == 0)
2860 break;
2861 command[i++] = *cur++;
2862 }
2863 command[i] = 0;
2864 if (i == 0)
2865 continue;
2866 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002867
Daniel Veillard78d12092001-10-11 09:12:24 +00002868 /*
2869 * Parse the argument
2870 */
2871 while ((*cur == ' ') || (*cur == '\t'))
2872 cur++;
2873 i = 0;
2874 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2875 if (*cur == 0)
2876 break;
2877 arg[i++] = *cur++;
2878 }
2879 arg[i] = 0;
2880 if (i != 0)
2881 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002882
Daniel Veillard78d12092001-10-11 09:12:24 +00002883 /*
2884 * start interpreting the command
2885 */
Owen Taylor3473f882001-02-23 17:55:21 +00002886 if (!strcmp(command, "exit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002887 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002888 if (!strcmp(command, "quit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002889 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002890 if (!strcmp(command, "bye"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002891 break;
Daniel Veillard5004f422001-11-08 13:53:05 +00002892 if (!strcmp(command, "help")) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002893 fprintf(ctxt->output, "\tbase display XML base of the node\n");
2894 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n");
2895 fprintf(ctxt->output, "\tbye leave shell\n");
2896 fprintf(ctxt->output, "\tcat [node] display node or current node\n");
2897 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n");
2898 fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n");
2899 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n");
2900 fprintf(ctxt->output, "\texit leave shell\n");
2901 fprintf(ctxt->output, "\thelp display this help\n");
2902 fprintf(ctxt->output, "\tfree display memory usage\n");
2903 fprintf(ctxt->output, "\tload [name] load a new document with name\n");
2904 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n");
Daniel Veillardc14c3892004-08-16 12:34:50 +00002905 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 +00002906#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002907 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n");
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002908 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n");
2909 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
Daniel Veillard20887ee2005-07-04 09:27:40 +00002910 fprintf(ctxt->output, "\tsetrootns register all namespace found on the root element\n");
2911 fprintf(ctxt->output, "\t the default namespace if any uses 'defaultns' prefix\n");
Daniel Veillard2070c482002-01-22 22:12:19 +00002912#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard321be0c2002-10-08 21:26:42 +00002913 fprintf(ctxt->output, "\tpwd display current working directory\n");
2914 fprintf(ctxt->output, "\tquit leave shell\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002915#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002916 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00002917 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002918#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf54cd532004-02-25 11:52:31 +00002919#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002920 fprintf(ctxt->output, "\tvalidate check the document for errors\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002921#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard522bc602004-02-21 11:53:09 +00002922#ifdef LIBXML_SCHEMAS_ENABLED
2923 fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n");
2924#endif
Daniel Veillard1e208222002-10-22 14:25:25 +00002925 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002926#ifdef LIBXML_VALID_ENABLED
Daniel Veillard5004f422001-11-08 13:53:05 +00002927 } else if (!strcmp(command, "validate")) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002928 xmlShellValidate(ctxt, arg, NULL, NULL);
Daniel Veillardf54cd532004-02-25 11:52:31 +00002929#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002930 } else if (!strcmp(command, "load")) {
2931 xmlShellLoad(ctxt, arg, NULL, NULL);
Daniel Veillard522bc602004-02-21 11:53:09 +00002932#ifdef LIBXML_SCHEMAS_ENABLED
2933 } else if (!strcmp(command, "relaxng")) {
2934 xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2935#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002936#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002937 } else if (!strcmp(command, "save")) {
2938 xmlShellSave(ctxt, arg, NULL, NULL);
2939 } else if (!strcmp(command, "write")) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00002940 if ((arg == NULL) || (arg[0] == 0))
2941 xmlGenericError(xmlGenericErrorContext,
2942 "Write command requires a filename argument\n");
2943 else
2944 xmlShellWrite(ctxt, arg, NULL, NULL);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002945#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard1e208222002-10-22 14:25:25 +00002946 } else if (!strcmp(command, "grep")) {
2947 xmlShellGrep(ctxt, arg, ctxt->node, NULL);
Daniel Veillard78d12092001-10-11 09:12:24 +00002948 } else if (!strcmp(command, "free")) {
2949 if (arg[0] == 0) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002950 xmlMemShow(ctxt->output, 0);
Daniel Veillard78d12092001-10-11 09:12:24 +00002951 } else {
2952 int len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002953
Daniel Veillard78d12092001-10-11 09:12:24 +00002954 sscanf(arg, "%d", &len);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002955 xmlMemShow(ctxt->output, len);
Daniel Veillard78d12092001-10-11 09:12:24 +00002956 }
2957 } else if (!strcmp(command, "pwd")) {
2958 char dir[500];
Owen Taylor3473f882001-02-23 17:55:21 +00002959
Daniel Veillard78d12092001-10-11 09:12:24 +00002960 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
Daniel Veillard321be0c2002-10-08 21:26:42 +00002961 fprintf(ctxt->output, "%s\n", dir);
Daniel Veillard78d12092001-10-11 09:12:24 +00002962 } else if (!strcmp(command, "du")) {
2963 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2964 } else if (!strcmp(command, "base")) {
2965 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
Daniel Veillard29b17482004-08-16 00:39:03 +00002966 } else if (!strcmp(command, "set")) {
2967 xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2070c482002-01-22 22:12:19 +00002968#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002969 } else if (!strcmp(command, "setns")) {
2970 if (arg[0] == 0) {
2971 xmlGenericError(xmlGenericErrorContext,
2972 "setns: prefix=[nsuri] required\n");
2973 } else {
2974 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
2975 }
Daniel Veillard20887ee2005-07-04 09:27:40 +00002976 } else if (!strcmp(command, "setrootns")) {
2977 xmlNodePtr root;
2978
2979 root = xmlDocGetRootElement(ctxt->doc);
2980 xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL);
Daniel Veillard2070c482002-01-22 22:12:19 +00002981 } else if (!strcmp(command, "xpath")) {
2982 if (arg[0] == 0) {
2983 xmlGenericError(xmlGenericErrorContext,
2984 "xpath: expression required\n");
2985 } else {
2986 ctxt->pctxt->node = ctxt->node;
2987 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002988 xmlXPathDebugDumpObject(ctxt->output, list, 0);
Daniel Veillard2070c482002-01-22 22:12:19 +00002989 xmlXPathFreeObject(list);
2990 }
2991#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard2156d432004-03-04 15:59:36 +00002992#ifdef LIBXML_TREE_ENABLED
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002993 } else if (!strcmp(command, "setbase")) {
2994 xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2156d432004-03-04 15:59:36 +00002995#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002996 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2997 int dir = (!strcmp(command, "dir"));
2998
2999 if (arg[0] == 0) {
3000 if (dir)
3001 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
3002 else
3003 xmlShellList(ctxt, NULL, ctxt->node, NULL);
3004 } else {
3005 ctxt->pctxt->node = ctxt->node;
Daniel Veillard61d80a22001-04-27 17:13:01 +00003006#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00003007 ctxt->pctxt->node = ctxt->node;
3008 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3009#else
3010 list = NULL;
3011#endif /* LIBXML_XPATH_ENABLED */
3012 if (list != NULL) {
3013 switch (list->type) {
3014 case XPATH_UNDEFINED:
3015 xmlGenericError(xmlGenericErrorContext,
3016 "%s: no such node\n", arg);
3017 break;
3018 case XPATH_NODESET:{
3019 int indx;
3020
Daniel Veillarda6825e82001-11-07 13:33:59 +00003021 if (list->nodesetval == NULL)
3022 break;
3023
Daniel Veillard78d12092001-10-11 09:12:24 +00003024 for (indx = 0;
3025 indx < list->nodesetval->nodeNr;
3026 indx++) {
3027 if (dir)
3028 xmlShellDir(ctxt, NULL,
3029 list->nodesetval->
3030 nodeTab[indx], NULL);
3031 else
3032 xmlShellList(ctxt, NULL,
3033 list->nodesetval->
3034 nodeTab[indx], NULL);
3035 }
3036 break;
3037 }
3038 case XPATH_BOOLEAN:
3039 xmlGenericError(xmlGenericErrorContext,
3040 "%s is a Boolean\n", arg);
3041 break;
3042 case XPATH_NUMBER:
3043 xmlGenericError(xmlGenericErrorContext,
3044 "%s is a number\n", arg);
3045 break;
3046 case XPATH_STRING:
3047 xmlGenericError(xmlGenericErrorContext,
3048 "%s is a string\n", arg);
3049 break;
3050 case XPATH_POINT:
3051 xmlGenericError(xmlGenericErrorContext,
3052 "%s is a point\n", arg);
3053 break;
3054 case XPATH_RANGE:
3055 xmlGenericError(xmlGenericErrorContext,
3056 "%s is a range\n", arg);
3057 break;
3058 case XPATH_LOCATIONSET:
3059 xmlGenericError(xmlGenericErrorContext,
3060 "%s is a range\n", arg);
3061 break;
3062 case XPATH_USERS:
3063 xmlGenericError(xmlGenericErrorContext,
3064 "%s is user-defined\n", arg);
3065 break;
3066 case XPATH_XSLT_TREE:
3067 xmlGenericError(xmlGenericErrorContext,
3068 "%s is an XSLT value tree\n",
3069 arg);
3070 break;
3071 }
3072#ifdef LIBXML_XPATH_ENABLED
3073 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00003074#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00003075 } else {
3076 xmlGenericError(xmlGenericErrorContext,
3077 "%s: no such node\n", arg);
3078 }
3079 ctxt->pctxt->node = NULL;
3080 }
3081 } else if (!strcmp(command, "cd")) {
3082 if (arg[0] == 0) {
3083 ctxt->node = (xmlNodePtr) ctxt->doc;
3084 } else {
3085#ifdef LIBXML_XPATH_ENABLED
3086 ctxt->pctxt->node = ctxt->node;
3087 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3088#else
3089 list = NULL;
3090#endif /* LIBXML_XPATH_ENABLED */
3091 if (list != NULL) {
3092 switch (list->type) {
3093 case XPATH_UNDEFINED:
3094 xmlGenericError(xmlGenericErrorContext,
3095 "%s: no such node\n", arg);
3096 break;
3097 case XPATH_NODESET:
Daniel Veillarda6825e82001-11-07 13:33:59 +00003098 if (list->nodesetval != NULL) {
3099 if (list->nodesetval->nodeNr == 1) {
3100 ctxt->node = list->nodesetval->nodeTab[0];
Daniel Veillard7a985a12003-07-06 17:57:42 +00003101 if ((ctxt->node != NULL) &&
3102 (ctxt->node->type ==
3103 XML_NAMESPACE_DECL)) {
3104 xmlGenericError(xmlGenericErrorContext,
3105 "cannot cd to namespace\n");
3106 ctxt->node = NULL;
3107 }
Daniel Veillarda6825e82001-11-07 13:33:59 +00003108 } else
3109 xmlGenericError(xmlGenericErrorContext,
3110 "%s is a %d Node Set\n",
3111 arg,
3112 list->nodesetval->nodeNr);
Daniel Veillard78d12092001-10-11 09:12:24 +00003113 } else
3114 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6825e82001-11-07 13:33:59 +00003115 "%s is an empty Node Set\n",
3116 arg);
Daniel Veillard78d12092001-10-11 09:12:24 +00003117 break;
3118 case XPATH_BOOLEAN:
3119 xmlGenericError(xmlGenericErrorContext,
3120 "%s is a Boolean\n", arg);
3121 break;
3122 case XPATH_NUMBER:
3123 xmlGenericError(xmlGenericErrorContext,
3124 "%s is a number\n", arg);
3125 break;
3126 case XPATH_STRING:
3127 xmlGenericError(xmlGenericErrorContext,
3128 "%s is a string\n", arg);
3129 break;
3130 case XPATH_POINT:
3131 xmlGenericError(xmlGenericErrorContext,
3132 "%s is a point\n", arg);
3133 break;
3134 case XPATH_RANGE:
3135 xmlGenericError(xmlGenericErrorContext,
3136 "%s is a range\n", arg);
3137 break;
3138 case XPATH_LOCATIONSET:
3139 xmlGenericError(xmlGenericErrorContext,
3140 "%s is a range\n", arg);
3141 break;
3142 case XPATH_USERS:
3143 xmlGenericError(xmlGenericErrorContext,
3144 "%s is user-defined\n", arg);
3145 break;
3146 case XPATH_XSLT_TREE:
3147 xmlGenericError(xmlGenericErrorContext,
3148 "%s is an XSLT value tree\n",
3149 arg);
3150 break;
3151 }
3152#ifdef LIBXML_XPATH_ENABLED
3153 xmlXPathFreeObject(list);
3154#endif
3155 } else {
3156 xmlGenericError(xmlGenericErrorContext,
3157 "%s: no such node\n", arg);
3158 }
3159 ctxt->pctxt->node = NULL;
3160 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003161#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00003162 } else if (!strcmp(command, "cat")) {
3163 if (arg[0] == 0) {
3164 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
3165 } else {
3166 ctxt->pctxt->node = ctxt->node;
3167#ifdef LIBXML_XPATH_ENABLED
3168 ctxt->pctxt->node = ctxt->node;
3169 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
3170#else
3171 list = NULL;
3172#endif /* LIBXML_XPATH_ENABLED */
3173 if (list != NULL) {
3174 switch (list->type) {
3175 case XPATH_UNDEFINED:
3176 xmlGenericError(xmlGenericErrorContext,
3177 "%s: no such node\n", arg);
3178 break;
3179 case XPATH_NODESET:{
3180 int indx;
3181
Daniel Veillarda6825e82001-11-07 13:33:59 +00003182 if (list->nodesetval == NULL)
3183 break;
3184
Daniel Veillard78d12092001-10-11 09:12:24 +00003185 for (indx = 0;
3186 indx < list->nodesetval->nodeNr;
3187 indx++) {
3188 if (i > 0)
Daniel Veillard321be0c2002-10-08 21:26:42 +00003189 fprintf(ctxt->output, " -------\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00003190 xmlShellCat(ctxt, NULL,
3191 list->nodesetval->
3192 nodeTab[indx], NULL);
3193 }
3194 break;
3195 }
3196 case XPATH_BOOLEAN:
3197 xmlGenericError(xmlGenericErrorContext,
3198 "%s is a Boolean\n", arg);
3199 break;
3200 case XPATH_NUMBER:
3201 xmlGenericError(xmlGenericErrorContext,
3202 "%s is a number\n", arg);
3203 break;
3204 case XPATH_STRING:
3205 xmlGenericError(xmlGenericErrorContext,
3206 "%s is a string\n", arg);
3207 break;
3208 case XPATH_POINT:
3209 xmlGenericError(xmlGenericErrorContext,
3210 "%s is a point\n", arg);
3211 break;
3212 case XPATH_RANGE:
3213 xmlGenericError(xmlGenericErrorContext,
3214 "%s is a range\n", arg);
3215 break;
3216 case XPATH_LOCATIONSET:
3217 xmlGenericError(xmlGenericErrorContext,
3218 "%s is a range\n", arg);
3219 break;
3220 case XPATH_USERS:
3221 xmlGenericError(xmlGenericErrorContext,
3222 "%s is user-defined\n", arg);
3223 break;
3224 case XPATH_XSLT_TREE:
3225 xmlGenericError(xmlGenericErrorContext,
3226 "%s is an XSLT value tree\n",
3227 arg);
3228 break;
3229 }
3230#ifdef LIBXML_XPATH_ENABLED
3231 xmlXPathFreeObject(list);
3232#endif
3233 } else {
3234 xmlGenericError(xmlGenericErrorContext,
3235 "%s: no such node\n", arg);
3236 }
3237 ctxt->pctxt->node = NULL;
3238 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003239#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00003240 } else {
3241 xmlGenericError(xmlGenericErrorContext,
3242 "Unknown command %s\n", command);
3243 }
3244 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00003245 }
3246#ifdef LIBXML_XPATH_ENABLED
3247 xmlXPathFreeContext(ctxt->pctxt);
3248#endif /* LIBXML_XPATH_ENABLED */
3249 if (ctxt->loaded) {
3250 xmlFreeDoc(ctxt->doc);
3251 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003252 if (ctxt->filename != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00003253 xmlFree(ctxt->filename);
Owen Taylor3473f882001-02-23 17:55:21 +00003254 xmlFree(ctxt);
3255 if (cmdline != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00003256 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00003257}
3258
Daniel Veillardd0cf7f62004-11-09 16:17:02 +00003259#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003260#define bottom_debugXML
3261#include "elfgcchack.h"
Owen Taylor3473f882001-02-23 17:55:21 +00003262#endif /* LIBXML_DEBUG_ENABLED */