blob: 00f29e0ae2aacb4e8f2e4ae72278aad975f77818 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * debugXML.c : This is a set of routines used for debugging the tree
3 * produced by the XML parser.
4 *
5 * See Copyright for the status of this software.
6 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00007 * Daniel Veillard <daniel@veillard.com>
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012#ifdef LIBXML_DEBUG_ENABLED
13
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18#ifdef HAVE_STRING_H
19#include <string.h>
20#endif
21#include <libxml/xmlmemory.h>
22#include <libxml/tree.h>
23#include <libxml/parser.h>
Daniel Veillard567e1b42001-08-01 15:53:47 +000024#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000025#include <libxml/valid.h>
26#include <libxml/debugXML.h>
27#include <libxml/HTMLtree.h>
28#include <libxml/HTMLparser.h>
29#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000030#include <libxml/globals.h>
Daniel Veillard0ba59232002-02-10 13:20:39 +000031#include <libxml/xpathInternals.h>
Igor Zlatkovicc06bb622003-04-27 15:59:00 +000032#include <libxml/uri.h>
Daniel Veillard522bc602004-02-21 11:53:09 +000033#ifdef LIBXML_SCHEMAS_ENABLED
34#include <libxml/relaxng.h>
35#endif
Owen Taylor3473f882001-02-23 17:55:21 +000036
Daniel Veillard22cdb842004-10-04 14:09:17 +000037typedef struct _xmlDebugCtxt xmlDebugCtxt;
38typedef xmlDebugCtxt *xmlDebugCtxtPtr;
39struct _xmlDebugCtxt {
40 FILE *output; /* the output file */
41 char shift[101]; /* used for indenting */
42 int depth; /* current depth */
43 xmlDocPtr doc; /* current document */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000044 xmlNodePtr node; /* current node */
Daniel Veillard22cdb842004-10-04 14:09:17 +000045 int check; /* do just checkings */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000046 int errors; /* number of errors found */
Daniel Veillard22cdb842004-10-04 14:09:17 +000047};
48
49static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
50
51static void
52xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
53{
54 int i;
55
56 ctxt->depth = 0;
57 ctxt->check = 0;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000058 ctxt->errors = 0;
Daniel Veillard22cdb842004-10-04 14:09:17 +000059 ctxt->output = stdout;
60 for (i = 0; i < 100; i++)
61 ctxt->shift[i] = ' ';
62 ctxt->shift[100] = 0;
63}
64
65static void
66xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
67{
68 if (ctxt->check)
69 return;
70 if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
71 if (ctxt->depth < 50)
72 fprintf(ctxt->output, &ctxt->shift[100 - 2 * ctxt->depth]);
73 else
74 fprintf(ctxt->output, ctxt->shift);
75 }
76}
77
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000078/**
79 * xmlDebugErr:
80 * @ctxt: a debug context
81 * @error: the error code
82 *
83 * Handle a debug error.
84 */
85static void
86xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
87{
88 ctxt->errors++;
89 __xmlRaiseError(NULL, NULL, NULL,
90 NULL, ctxt->node, XML_FROM_CHECK,
91 error, XML_ERR_ERROR, NULL, 0,
92 NULL, NULL, NULL, 0, 0,
93 msg);
94}
95static void
96xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra)
97{
98 ctxt->errors++;
99 __xmlRaiseError(NULL, NULL, NULL,
100 NULL, ctxt->node, XML_FROM_CHECK,
101 error, XML_ERR_ERROR, NULL, 0,
102 NULL, NULL, NULL, 0, 0,
103 msg, extra);
104}
105static void
106xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, char *extra)
107{
108 ctxt->errors++;
109 __xmlRaiseError(NULL, NULL, NULL,
110 NULL, ctxt->node, XML_FROM_CHECK,
111 error, XML_ERR_ERROR, NULL, 0,
112 NULL, NULL, NULL, 0, 0,
113 msg, extra);
114}
115
116static void
117xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
118 if (node->parent == NULL)
119 xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
120 "Node has no parent\n");
121 if (node->doc == NULL)
122 xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
123 "Node has no doc\n");
124 if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
125 (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
126 xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
127 "Node doc differs from parent's one\n");
128 if (node->prev == NULL) {
129 if (node->type == XML_ATTRIBUTE_NODE) {
130 if ((node->parent != NULL) &&
131 (node != (xmlNodePtr) node->parent->properties))
132 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
133 "Attr has no prev and not first of attr list\n");
134
135 } else if ((node->parent != NULL) && (node->parent->children != node))
136 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
137 "Node has no prev and not first of parent list\n");
138 } else {
139 if (node->prev->next != node)
140 xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
141 "Node prev->next : back link wrong\n");
142 }
143 if (node->next == NULL) {
144 if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
145 (node->parent->last != node))
146 xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
147 "Node has no next and not last of parent list\n");
148 } else {
149 if (node->next->prev != node)
150 xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
151 "Node next->prev : forward link wrong\n");
152 }
153}
154
Daniel Veillard22cdb842004-10-04 14:09:17 +0000155static void
156xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
157{
158 int i;
159
160 if (ctxt->check)
161 return;
162 /* TODO: check UTF8 content of the string */
163 if (str == NULL) {
164 fprintf(ctxt->output, "(NULL)");
165 return;
166 }
167 for (i = 0; i < 40; i++)
168 if (str[i] == 0)
169 return;
170 else if (IS_BLANK_CH(str[i]))
171 fputc(' ', ctxt->output);
172 else if (str[i] >= 0x80)
173 fprintf(ctxt->output, "#%X", str[i]);
174 else
175 fputc(str[i], ctxt->output);
176 fprintf(ctxt->output, "...");
177}
178
179static void
180xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
181{
182 xmlCtxtDumpSpaces(ctxt);
183
184 if (dtd == NULL) {
185 if (!ctxt->check)
186 fprintf(ctxt->output, "DTD node is NULL\n");
187 return;
188 }
189
190 if (dtd->type != XML_DTD_NODE) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000191 xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
192 "Node is not a DTD");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000193 return;
194 }
195 if (!ctxt->check) {
196 if (dtd->name != NULL)
197 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
198 else
199 fprintf(ctxt->output, "DTD");
200 if (dtd->ExternalID != NULL)
201 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
202 if (dtd->SystemID != NULL)
203 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
204 fprintf(ctxt->output, "\n");
205 }
206 /*
207 * Do a bit of checking
208 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000209 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000210}
211
212static void
213xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
214{
215 xmlCtxtDumpSpaces(ctxt);
216
217 if (attr == NULL) {
218 if (!ctxt->check)
219 fprintf(ctxt->output, "Attribute declaration is NULL\n");
220 return;
221 }
222 if (attr->type != XML_ATTRIBUTE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000223 xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
224 "Node is not an attribute declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000225 return;
226 }
227 if (attr->name != NULL) {
228 if (!ctxt->check)
229 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
230 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000231 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
232 "Node attribute declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000233 if (attr->elem != NULL) {
234 if (!ctxt->check)
235 fprintf(ctxt->output, " for %s", (char *) attr->elem);
236 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000237 xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
238 "Node attribute declaration has no element name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000239 if (!ctxt->check) {
240 switch (attr->atype) {
241 case XML_ATTRIBUTE_CDATA:
242 fprintf(ctxt->output, " CDATA");
243 break;
244 case XML_ATTRIBUTE_ID:
245 fprintf(ctxt->output, " ID");
246 break;
247 case XML_ATTRIBUTE_IDREF:
248 fprintf(ctxt->output, " IDREF");
249 break;
250 case XML_ATTRIBUTE_IDREFS:
251 fprintf(ctxt->output, " IDREFS");
252 break;
253 case XML_ATTRIBUTE_ENTITY:
254 fprintf(ctxt->output, " ENTITY");
255 break;
256 case XML_ATTRIBUTE_ENTITIES:
257 fprintf(ctxt->output, " ENTITIES");
258 break;
259 case XML_ATTRIBUTE_NMTOKEN:
260 fprintf(ctxt->output, " NMTOKEN");
261 break;
262 case XML_ATTRIBUTE_NMTOKENS:
263 fprintf(ctxt->output, " NMTOKENS");
264 break;
265 case XML_ATTRIBUTE_ENUMERATION:
266 fprintf(ctxt->output, " ENUMERATION");
267 break;
268 case XML_ATTRIBUTE_NOTATION:
269 fprintf(ctxt->output, " NOTATION ");
270 break;
271 }
272 if (attr->tree != NULL) {
273 int indx;
274 xmlEnumerationPtr cur = attr->tree;
275
276 for (indx = 0; indx < 5; indx++) {
277 if (indx != 0)
278 fprintf(ctxt->output, "|%s", (char *) cur->name);
279 else
280 fprintf(ctxt->output, " (%s", (char *) cur->name);
281 cur = cur->next;
282 if (cur == NULL)
283 break;
284 }
285 if (cur == NULL)
286 fprintf(ctxt->output, ")");
287 else
288 fprintf(ctxt->output, "...)");
289 }
290 switch (attr->def) {
291 case XML_ATTRIBUTE_NONE:
292 break;
293 case XML_ATTRIBUTE_REQUIRED:
294 fprintf(ctxt->output, " REQUIRED");
295 break;
296 case XML_ATTRIBUTE_IMPLIED:
297 fprintf(ctxt->output, " IMPLIED");
298 break;
299 case XML_ATTRIBUTE_FIXED:
300 fprintf(ctxt->output, " FIXED");
301 break;
302 }
303 if (attr->defaultValue != NULL) {
304 fprintf(ctxt->output, "\"");
305 xmlCtxtDumpString(ctxt, attr->defaultValue);
306 fprintf(ctxt->output, "\"");
307 }
308 fprintf(ctxt->output, "\n");
309 }
310
311 /*
312 * Do a bit of checking
313 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000314 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000315}
316
317static void
318xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
319{
320 xmlCtxtDumpSpaces(ctxt);
321
322 if (elem == NULL) {
323 if (!ctxt->check)
324 fprintf(ctxt->output, "Element declaration is NULL\n");
325 return;
326 }
327 if (elem->type != XML_ELEMENT_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000328 xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
329 "Node is not an element declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000330 return;
331 }
332 if (elem->name != NULL) {
333 if (!ctxt->check) {
334 fprintf(ctxt->output, "ELEMDECL(");
335 xmlCtxtDumpString(ctxt, elem->name);
336 fprintf(ctxt->output, ")");
337 }
338 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000339 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
340 "Element declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000341 if (!ctxt->check) {
342 switch (elem->etype) {
343 case XML_ELEMENT_TYPE_UNDEFINED:
344 fprintf(ctxt->output, ", UNDEFINED");
345 break;
346 case XML_ELEMENT_TYPE_EMPTY:
347 fprintf(ctxt->output, ", EMPTY");
348 break;
349 case XML_ELEMENT_TYPE_ANY:
350 fprintf(ctxt->output, ", ANY");
351 break;
352 case XML_ELEMENT_TYPE_MIXED:
353 fprintf(ctxt->output, ", MIXED ");
354 break;
355 case XML_ELEMENT_TYPE_ELEMENT:
356 fprintf(ctxt->output, ", MIXED ");
357 break;
358 }
359 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
360 char buf[5001];
361
362 buf[0] = 0;
363 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
364 buf[5000] = 0;
365 fprintf(ctxt->output, "%s", buf);
366 }
367 fprintf(ctxt->output, "\n");
368 }
369
370 /*
371 * Do a bit of checking
372 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000373 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000374}
375
376static void
377xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
378{
379 xmlCtxtDumpSpaces(ctxt);
380
381 if (ent == NULL) {
382 if (!ctxt->check)
383 fprintf(ctxt->output, "Entity declaration is NULL\n");
384 return;
385 }
386 if (ent->type != XML_ENTITY_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000387 xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
388 "Node is not an entity declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000389 return;
390 }
391 if (ent->name != NULL) {
392 if (!ctxt->check) {
393 fprintf(ctxt->output, "ENTITYDECL(");
394 xmlCtxtDumpString(ctxt, ent->name);
395 fprintf(ctxt->output, ")");
396 }
397 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000398 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
399 "Entity declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000400 if (!ctxt->check) {
401 switch (ent->etype) {
402 case XML_INTERNAL_GENERAL_ENTITY:
403 fprintf(ctxt->output, ", internal\n");
404 break;
405 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
406 fprintf(ctxt->output, ", external parsed\n");
407 break;
408 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
409 fprintf(ctxt->output, ", unparsed\n");
410 break;
411 case XML_INTERNAL_PARAMETER_ENTITY:
412 fprintf(ctxt->output, ", parameter\n");
413 break;
414 case XML_EXTERNAL_PARAMETER_ENTITY:
415 fprintf(ctxt->output, ", external parameter\n");
416 break;
417 case XML_INTERNAL_PREDEFINED_ENTITY:
418 fprintf(ctxt->output, ", predefined\n");
419 break;
420 }
421 if (ent->ExternalID) {
422 xmlCtxtDumpSpaces(ctxt);
423 fprintf(ctxt->output, " ExternalID=%s\n",
424 (char *) ent->ExternalID);
425 }
426 if (ent->SystemID) {
427 xmlCtxtDumpSpaces(ctxt);
428 fprintf(ctxt->output, " SystemID=%s\n",
429 (char *) ent->SystemID);
430 }
431 if (ent->URI != NULL) {
432 xmlCtxtDumpSpaces(ctxt);
433 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
434 }
435 if (ent->content) {
436 xmlCtxtDumpSpaces(ctxt);
437 fprintf(ctxt->output, " content=");
438 xmlCtxtDumpString(ctxt, ent->content);
439 fprintf(ctxt->output, "\n");
440 }
441 }
442
443 /*
444 * Do a bit of checking
445 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000446 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000447}
448
449static void
450xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
451{
452 xmlCtxtDumpSpaces(ctxt);
453
454 if (ns == NULL) {
455 if (!ctxt->check)
456 fprintf(ctxt->output, "namespace node is NULL\n");
457 return;
458 }
459 if (ns->type != XML_NAMESPACE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000460 xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
461 "Node is not a namespace declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000462 return;
463 }
464 if (ns->href == NULL) {
465 if (ns->prefix != NULL)
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000466 xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
467 "Incomplete namespace %s href=NULL\n",
Daniel Veillard22cdb842004-10-04 14:09:17 +0000468 (char *) ns->prefix);
469 else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000470 xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
471 "Incomplete default namespace href=NULL\n");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000472 } else {
473 if (!ctxt->check) {
474 if (ns->prefix != NULL)
475 fprintf(ctxt->output, "namespace %s href=",
476 (char *) ns->prefix);
477 else
478 fprintf(ctxt->output, "default namespace href=");
479
480 xmlCtxtDumpString(ctxt, ns->href);
481 fprintf(ctxt->output, "\n");
482 }
483 }
484}
485
486static void
487xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
488{
489 while (ns != NULL) {
490 xmlCtxtDumpNamespace(ctxt, ns);
491 ns = ns->next;
492 }
493}
494
495static void
496xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
497{
498 xmlCtxtDumpSpaces(ctxt);
499
500 if (ent == NULL) {
501 if (!ctxt->check)
502 fprintf(ctxt->output, "Entity is NULL\n");
503 return;
504 }
505 if (!ctxt->check) {
506 switch (ent->etype) {
507 case XML_INTERNAL_GENERAL_ENTITY:
508 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
509 break;
510 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
511 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
512 break;
513 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
514 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
515 break;
516 case XML_INTERNAL_PARAMETER_ENTITY:
517 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
518 break;
519 case XML_EXTERNAL_PARAMETER_ENTITY:
520 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
521 break;
522 default:
523 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
524 }
525 fprintf(ctxt->output, "%s\n", ent->name);
526 if (ent->ExternalID) {
527 xmlCtxtDumpSpaces(ctxt);
528 fprintf(ctxt->output, "ExternalID=%s\n",
529 (char *) ent->ExternalID);
530 }
531 if (ent->SystemID) {
532 xmlCtxtDumpSpaces(ctxt);
533 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
534 }
535 if (ent->URI) {
536 xmlCtxtDumpSpaces(ctxt);
537 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
538 }
539 if (ent->content) {
540 xmlCtxtDumpSpaces(ctxt);
541 fprintf(ctxt->output, "content=");
542 xmlCtxtDumpString(ctxt, ent->content);
543 fprintf(ctxt->output, "\n");
544 }
545 }
546}
547
548/**
549 * xmlCtxtDumpAttr:
550 * @output: the FILE * for the output
551 * @attr: the attribute
552 * @depth: the indentation level.
553 *
554 * Dumps debug information for the attribute
555 */
556static void
557xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
558{
559 xmlCtxtDumpSpaces(ctxt);
560
561 if (attr == NULL) {
562 if (!ctxt->check)
563 fprintf(ctxt->output, "Attr is NULL");
564 return;
565 }
566 if (!ctxt->check) {
567 fprintf(ctxt->output, "ATTRIBUTE ");
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000568 xmlCtxtDumpString(ctxt, attr->name);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000569 fprintf(ctxt->output, "\n");
570 if (attr->children != NULL) {
571 ctxt->depth++;
572 xmlCtxtDumpNodeList(ctxt, attr->children);
573 ctxt->depth--;
574 }
575 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000576 if (attr->name == NULL)
577 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
578 "Attribute has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000579
580 /*
581 * Do a bit of checking
582 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000583 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000584}
585
586/**
587 * xmlCtxtDumpAttrList:
588 * @output: the FILE * for the output
589 * @attr: the attribute list
590 * @depth: the indentation level.
591 *
592 * Dumps debug information for the attribute list
593 */
594static void
595xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
596{
597 while (attr != NULL) {
598 xmlCtxtDumpAttr(ctxt, attr);
599 attr = attr->next;
600 }
601}
602
603/**
604 * xmlCtxtDumpOneNode:
605 * @output: the FILE * for the output
606 * @node: the node
607 * @depth: the indentation level.
608 *
609 * Dumps debug information for the element node, it is not recursive
610 */
611static void
612xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
613{
614 if (node == NULL) {
615 if (!ctxt->check) {
616 xmlCtxtDumpSpaces(ctxt);
617 fprintf(ctxt->output, "node is NULL\n");
618 }
619 return;
620 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000621 ctxt->node = node;
622
Daniel Veillard22cdb842004-10-04 14:09:17 +0000623 switch (node->type) {
624 case XML_ELEMENT_NODE:
625 if (!ctxt->check) {
626 xmlCtxtDumpSpaces(ctxt);
627 fprintf(ctxt->output, "ELEMENT ");
628 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
629 xmlCtxtDumpString(ctxt, node->ns->prefix);
630 fprintf(ctxt->output, ":");
631 }
632 xmlCtxtDumpString(ctxt, node->name);
633 fprintf(ctxt->output, "\n");
634 }
635 break;
636 case XML_ATTRIBUTE_NODE:
637 if (!ctxt->check)
638 xmlCtxtDumpSpaces(ctxt);
639 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
640 break;
641 case XML_TEXT_NODE:
642 if (!ctxt->check) {
643 xmlCtxtDumpSpaces(ctxt);
644 if (node->name == (const xmlChar *) xmlStringTextNoenc)
645 fprintf(ctxt->output, "TEXT no enc\n");
646 else
647 fprintf(ctxt->output, "TEXT\n");
648 }
649 break;
650 case XML_CDATA_SECTION_NODE:
651 if (!ctxt->check) {
652 xmlCtxtDumpSpaces(ctxt);
653 fprintf(ctxt->output, "CDATA_SECTION\n");
654 }
655 break;
656 case XML_ENTITY_REF_NODE:
657 if (!ctxt->check) {
658 xmlCtxtDumpSpaces(ctxt);
659 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
660 (char *) node->name);
661 }
662 break;
663 case XML_ENTITY_NODE:
664 if (!ctxt->check) {
665 xmlCtxtDumpSpaces(ctxt);
666 fprintf(ctxt->output, "ENTITY\n");
667 }
668 break;
669 case XML_PI_NODE:
670 if (!ctxt->check) {
671 xmlCtxtDumpSpaces(ctxt);
672 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
673 }
674 break;
675 case XML_COMMENT_NODE:
676 if (!ctxt->check) {
677 xmlCtxtDumpSpaces(ctxt);
678 fprintf(ctxt->output, "COMMENT\n");
679 }
680 break;
681 case XML_DOCUMENT_NODE:
682 case XML_HTML_DOCUMENT_NODE:
683 if (!ctxt->check) {
684 xmlCtxtDumpSpaces(ctxt);
685 }
686 fprintf(ctxt->output, "PBM: DOCUMENT found here\n");
687 break;
688 case XML_DOCUMENT_TYPE_NODE:
689 if (!ctxt->check) {
690 xmlCtxtDumpSpaces(ctxt);
691 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
692 }
693 break;
694 case XML_DOCUMENT_FRAG_NODE:
695 if (!ctxt->check) {
696 xmlCtxtDumpSpaces(ctxt);
697 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
698 }
699 break;
700 case XML_NOTATION_NODE:
701 if (!ctxt->check) {
702 xmlCtxtDumpSpaces(ctxt);
703 fprintf(ctxt->output, "NOTATION\n");
704 }
705 break;
706 case XML_DTD_NODE:
707 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
708 return;
709 case XML_ELEMENT_DECL:
710 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
711 return;
712 case XML_ATTRIBUTE_DECL:
713 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
714 return;
715 case XML_ENTITY_DECL:
716 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
717 return;
718 case XML_NAMESPACE_DECL:
719 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
720 return;
721 case XML_XINCLUDE_START:
722 if (!ctxt->check) {
723 xmlCtxtDumpSpaces(ctxt);
724 fprintf(ctxt->output, "INCLUDE START\n");
725 }
726 return;
727 case XML_XINCLUDE_END:
728 if (!ctxt->check) {
729 xmlCtxtDumpSpaces(ctxt);
730 fprintf(ctxt->output, "INCLUDE END\n");
731 }
732 return;
733 default:
734 if (!ctxt->check)
735 xmlCtxtDumpSpaces(ctxt);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000736 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
737 "Unknown node type %d\n", node->type);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000738 return;
739 }
740 if (node->doc == NULL) {
741 if (!ctxt->check) {
742 xmlCtxtDumpSpaces(ctxt);
743 }
744 fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
745 }
746 ctxt->depth++;
747 if (node->nsDef != NULL)
748 xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
749 if (node->properties != NULL)
750 xmlCtxtDumpAttrList(ctxt, node->properties);
751 if (node->type != XML_ENTITY_REF_NODE) {
752 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
753 if (!ctxt->check) {
754 xmlCtxtDumpSpaces(ctxt);
755 fprintf(ctxt->output, "content=");
756 xmlCtxtDumpString(ctxt, node->content);
757 fprintf(ctxt->output, "\n");
758 }
759 }
760 } else {
761 xmlEntityPtr ent;
762
763 ent = xmlGetDocEntity(node->doc, node->name);
764 if (ent != NULL)
765 xmlCtxtDumpEntity(ctxt, ent);
766 }
767 ctxt->depth--;
768
769 /*
770 * Do a bit of checking
771 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000772 xmlCtxtGenericNodeCheck(ctxt, node);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000773}
774
775/**
776 * xmlCtxtDumpNode:
777 * @output: the FILE * for the output
778 * @node: the node
779 * @depth: the indentation level.
780 *
781 * Dumps debug information for the element node, it is recursive
782 */
783static void
784xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
785{
786 if (node == NULL) {
787 if (!ctxt->check) {
788 xmlCtxtDumpSpaces(ctxt);
789 fprintf(ctxt->output, "node is NULL\n");
790 }
791 return;
792 }
793 xmlCtxtDumpOneNode(ctxt, node);
794 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
795 ctxt->depth++;
796 xmlCtxtDumpNodeList(ctxt, node->children);
797 ctxt->depth--;
798 }
799}
800
801/**
802 * xmlCtxtDumpNodeList:
803 * @output: the FILE * for the output
804 * @node: the node list
805 * @depth: the indentation level.
806 *
807 * Dumps debug information for the list of element node, it is recursive
808 */
809static void
810xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
811{
812 while (node != NULL) {
813 xmlCtxtDumpNode(ctxt, node);
814 node = node->next;
815 }
816}
817
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000818static void
819xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
820{
821 if (doc == NULL) {
822 if (!ctxt->check)
823 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
824 return;
825 }
826 ctxt->node = (xmlNodePtr) doc;
827
828 switch (doc->type) {
829 case XML_ELEMENT_NODE:
830 xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
831 "Misplaced ELEMENT node\n");
832 break;
833 case XML_ATTRIBUTE_NODE:
834 xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
835 "Misplaced ATTRIBUTE node\n");
836 break;
837 case XML_TEXT_NODE:
838 xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
839 "Misplaced TEXT node\n");
840 break;
841 case XML_CDATA_SECTION_NODE:
842 xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
843 "Misplaced CDATA node\n");
844 break;
845 case XML_ENTITY_REF_NODE:
846 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
847 "Misplaced ENTITYREF node\n");
848 break;
849 case XML_ENTITY_NODE:
850 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
851 "Misplaced ENTITY node\n");
852 break;
853 case XML_PI_NODE:
854 xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
855 "Misplaced PI node\n");
856 break;
857 case XML_COMMENT_NODE:
858 xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
859 "Misplaced COMMENT node\n");
860 break;
861 case XML_DOCUMENT_NODE:
862 if (!ctxt->check)
863 fprintf(ctxt->output, "DOCUMENT\n");
864 break;
865 case XML_HTML_DOCUMENT_NODE:
866 if (!ctxt->check)
867 fprintf(ctxt->output, "HTML DOCUMENT\n");
868 break;
869 case XML_DOCUMENT_TYPE_NODE:
870 xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
871 "Misplaced DOCTYPE node\n");
872 break;
873 case XML_DOCUMENT_FRAG_NODE:
874 xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
875 "Misplaced FRAGMENT node\n");
876 break;
877 case XML_NOTATION_NODE:
878 xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
879 "Misplaced NOTATION node\n");
880 break;
881 default:
882 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
883 "Unknown node type %d\n", doc->type);
884 }
885}
Daniel Veillard22cdb842004-10-04 14:09:17 +0000886
887/**
888 * xmlCtxtDumpDocumentHead:
889 * @output: the FILE * for the output
890 * @doc: the document
891 *
892 * Dumps debug information cncerning the document, not recursive
893 */
894static void
895xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
896{
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000897 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000898 if (!ctxt->check) {
899 if (doc->name != NULL) {
900 fprintf(ctxt->output, "name=");
901 xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
902 fprintf(ctxt->output, "\n");
903 }
904 if (doc->version != NULL) {
905 fprintf(ctxt->output, "version=");
906 xmlCtxtDumpString(ctxt, doc->version);
907 fprintf(ctxt->output, "\n");
908 }
909 if (doc->encoding != NULL) {
910 fprintf(ctxt->output, "encoding=");
911 xmlCtxtDumpString(ctxt, doc->encoding);
912 fprintf(ctxt->output, "\n");
913 }
914 if (doc->URL != NULL) {
915 fprintf(ctxt->output, "URL=");
916 xmlCtxtDumpString(ctxt, doc->URL);
917 fprintf(ctxt->output, "\n");
918 }
919 if (doc->standalone)
920 fprintf(ctxt->output, "standalone=true\n");
921 }
922 if (doc->oldNs != NULL)
923 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
924}
925
926/**
927 * xmlCtxtDumpDocument:
928 * @output: the FILE * for the output
929 * @doc: the document
930 *
931 * Dumps debug information for the document, it's recursive
932 */
933static void
934xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
935{
936 if (doc == NULL) {
937 if (!ctxt->check)
938 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
939 return;
940 }
941 xmlCtxtDumpDocumentHead(ctxt, doc);
942 if (((doc->type == XML_DOCUMENT_NODE) ||
943 (doc->type == XML_HTML_DOCUMENT_NODE))
944 && (doc->children != NULL)) {
945 ctxt->depth++;
946 xmlCtxtDumpNodeList(ctxt, doc->children);
947 ctxt->depth--;
948 }
949}
950
951static void
952xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt)
953{
954 if (cur == NULL) {
955 if (!ctxt->check)
956 fprintf(ctxt->output, "Entity is NULL");
957 return;
958 }
959 if (!ctxt->check) {
960 fprintf(ctxt->output, "%s : ", (char *) cur->name);
961 switch (cur->etype) {
962 case XML_INTERNAL_GENERAL_ENTITY:
963 fprintf(ctxt->output, "INTERNAL GENERAL, ");
964 break;
965 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
966 fprintf(ctxt->output, "EXTERNAL PARSED, ");
967 break;
968 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
969 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
970 break;
971 case XML_INTERNAL_PARAMETER_ENTITY:
972 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
973 break;
974 case XML_EXTERNAL_PARAMETER_ENTITY:
975 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
976 break;
977 default:
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000978 xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
979 "Unknown entity type %d\n", cur->etype);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000980 }
981 if (cur->ExternalID != NULL)
982 fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
983 if (cur->SystemID != NULL)
984 fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
985 if (cur->orig != NULL)
986 fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
987 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
988 fprintf(ctxt->output, "\n content \"%s\"",
989 (char *) cur->content);
990 fprintf(ctxt->output, "\n");
991 }
992}
993
994/**
995 * xmlCtxtDumpEntities:
996 * @output: the FILE * for the output
997 * @doc: the document
998 *
999 * Dumps debug information for all the entities in use by the document
1000 */
1001static void
1002xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1003{
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001004 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001005 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1006 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1007 doc->intSubset->entities;
1008
1009 if (!ctxt->check)
1010 fprintf(ctxt->output, "Entities in internal subset\n");
1011 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1012 ctxt);
1013 } else
1014 fprintf(ctxt->output, "No entities in internal subset\n");
1015 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1016 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1017 doc->extSubset->entities;
1018
1019 if (!ctxt->check)
1020 fprintf(ctxt->output, "Entities in external subset\n");
1021 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1022 ctxt);
1023 } else if (!ctxt->check)
1024 fprintf(ctxt->output, "No entities in external subset\n");
1025}
1026
1027/**
1028 * xmlCtxtDumpDTD:
1029 * @output: the FILE * for the output
1030 * @dtd: the DTD
1031 *
1032 * Dumps debug information for the DTD
1033 */
1034static void
1035xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1036{
1037 if (dtd == NULL) {
1038 if (!ctxt->check)
1039 fprintf(ctxt->output, "DTD is NULL\n");
1040 return;
1041 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001042 xmlCtxtDumpDtdNode(ctxt, dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001043 if (dtd->children == NULL)
1044 fprintf(ctxt->output, " DTD is empty\n");
1045 else {
1046 ctxt->depth++;
1047 xmlCtxtDumpNodeList(ctxt, dtd->children);
1048 ctxt->depth--;
1049 }
1050}
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001051
Daniel Veillard22cdb842004-10-04 14:09:17 +00001052/************************************************************************
1053 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001054 * Public entry points for dump *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001055 * *
1056 ************************************************************************/
1057
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001058/**
1059 * xmlDebugDumpString:
1060 * @output: the FILE * for the output
1061 * @str: the string
1062 *
1063 * Dumps informations about the string, shorten it if necessary
1064 */
1065void
1066xmlDebugDumpString(FILE * output, const xmlChar * str)
1067{
Owen Taylor3473f882001-02-23 17:55:21 +00001068 int i;
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001069
Daniel Veillard7db38712002-02-07 16:39:11 +00001070 if (output == NULL)
1071 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00001072 if (str == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001073 fprintf(output, "(NULL)");
1074 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001075 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001076 for (i = 0; i < 40; i++)
1077 if (str[i] == 0)
1078 return;
William M. Brack76e95df2003-10-18 16:20:14 +00001079 else if (IS_BLANK_CH(str[i]))
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001080 fputc(' ', output);
1081 else if (str[i] >= 0x80)
1082 fprintf(output, "#%X", str[i]);
1083 else
1084 fputc(str[i], output);
Owen Taylor3473f882001-02-23 17:55:21 +00001085 fprintf(output, "...");
1086}
1087
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001088/**
1089 * xmlDebugDumpAttr:
1090 * @output: the FILE * for the output
1091 * @attr: the attribute
1092 * @depth: the indentation level.
1093 *
1094 * Dumps debug information for the attribute
1095 */
1096void
1097xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
Daniel Veillard22cdb842004-10-04 14:09:17 +00001098 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001099
Daniel Veillard22cdb842004-10-04 14:09:17 +00001100 xmlCtxtDumpInitCtxt(&ctxt);
1101 ctxt.output = output;
1102 ctxt.depth = depth;
1103 xmlCtxtDumpAttr(&ctxt, attr);
1104}
Owen Taylor3473f882001-02-23 17:55:21 +00001105
Owen Taylor3473f882001-02-23 17:55:21 +00001106
Daniel Veillard22cdb842004-10-04 14:09:17 +00001107/**
1108 * xmlDebugDumpEntities:
1109 * @output: the FILE * for the output
1110 * @doc: the document
1111 *
1112 * Dumps debug information for all the entities in use by the document
1113 */
1114void
1115xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1116{
1117 xmlDebugCtxt ctxt;
1118
1119 xmlCtxtDumpInitCtxt(&ctxt);
1120 ctxt.output = output;
1121 xmlCtxtDumpEntities(&ctxt, doc);
Owen Taylor3473f882001-02-23 17:55:21 +00001122}
1123
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001124/**
1125 * xmlDebugDumpAttrList:
1126 * @output: the FILE * for the output
1127 * @attr: the attribute list
1128 * @depth: the indentation level.
1129 *
1130 * Dumps debug information for the attribute list
1131 */
1132void
1133xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1134{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001135 xmlDebugCtxt ctxt;
1136
1137 xmlCtxtDumpInitCtxt(&ctxt);
1138 ctxt.output = output;
1139 ctxt.depth = depth;
1140 xmlCtxtDumpAttrList(&ctxt, attr);
Owen Taylor3473f882001-02-23 17:55:21 +00001141}
1142
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001143/**
1144 * xmlDebugDumpOneNode:
1145 * @output: the FILE * for the output
1146 * @node: the node
1147 * @depth: the indentation level.
1148 *
1149 * Dumps debug information for the element node, it is not recursive
1150 */
1151void
1152xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1153{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001154 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001155
Daniel Veillard22cdb842004-10-04 14:09:17 +00001156 xmlCtxtDumpInitCtxt(&ctxt);
1157 ctxt.output = output;
1158 ctxt.depth = depth;
1159 xmlCtxtDumpOneNode(&ctxt, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001160}
1161
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001162/**
1163 * xmlDebugDumpNode:
1164 * @output: the FILE * for the output
1165 * @node: the node
1166 * @depth: the indentation level.
1167 *
1168 * Dumps debug information for the element node, it is recursive
1169 */
1170void
1171xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1172{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001173 xmlDebugCtxt ctxt;
1174
Daniel Veillard7db38712002-02-07 16:39:11 +00001175 if (output == NULL)
1176 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001177 xmlCtxtDumpInitCtxt(&ctxt);
1178 ctxt.output = output;
1179 ctxt.depth = depth;
1180 xmlCtxtDumpNode(&ctxt, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001181}
1182
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001183/**
1184 * xmlDebugDumpNodeList:
1185 * @output: the FILE * for the output
1186 * @node: the node list
1187 * @depth: the indentation level.
1188 *
1189 * Dumps debug information for the list of element node, it is recursive
1190 */
1191void
1192xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1193{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001194 xmlDebugCtxt ctxt;
1195
Daniel Veillard7db38712002-02-07 16:39:11 +00001196 if (output == NULL)
1197 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001198 xmlCtxtDumpInitCtxt(&ctxt);
1199 ctxt.output = output;
1200 ctxt.depth = depth;
1201 xmlCtxtDumpNodeList(&ctxt, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001202}
1203
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001204/**
1205 * xmlDebugDumpDocumentHead:
1206 * @output: the FILE * for the output
1207 * @doc: the document
1208 *
1209 * Dumps debug information cncerning the document, not recursive
1210 */
1211void
1212xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1213{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001214 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001215
Daniel Veillard22cdb842004-10-04 14:09:17 +00001216 if (output == NULL)
1217 output = stdout;
1218 xmlCtxtDumpInitCtxt(&ctxt);
1219 ctxt.output = output;
1220 xmlCtxtDumpDocumentHead(&ctxt, doc);
Owen Taylor3473f882001-02-23 17:55:21 +00001221}
1222
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001223/**
1224 * xmlDebugDumpDocument:
1225 * @output: the FILE * for the output
1226 * @doc: the document
1227 *
1228 * Dumps debug information for the document, it's recursive
1229 */
1230void
1231xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1232{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001233 xmlDebugCtxt ctxt;
1234
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001235 if (output == NULL)
Daniel Veillard22cdb842004-10-04 14:09:17 +00001236 output = stdout;
1237 xmlCtxtDumpInitCtxt(&ctxt);
1238 ctxt.output = output;
1239 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001240}
Owen Taylor3473f882001-02-23 17:55:21 +00001241
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001242/**
1243 * xmlDebugDumpDTD:
1244 * @output: the FILE * for the output
1245 * @dtd: the DTD
1246 *
1247 * Dumps debug information for the DTD
1248 */
1249void
1250xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1251{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001252 xmlDebugCtxt ctxt;
1253
Daniel Veillard7db38712002-02-07 16:39:11 +00001254 if (output == NULL)
1255 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001256 xmlCtxtDumpInitCtxt(&ctxt);
1257 ctxt.output = output;
1258 xmlCtxtDumpDTD(&ctxt, dtd);
Owen Taylor3473f882001-02-23 17:55:21 +00001259}
1260
Daniel Veillard22cdb842004-10-04 14:09:17 +00001261/************************************************************************
1262 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001263 * Public entry points for checkings *
1264 * *
1265 ************************************************************************/
1266
1267/**
1268 * xmlDebugCheckDocument:
1269 * @output: the FILE * for the output
1270 * @doc: the document
1271 *
1272 * Check the document for potential content problems, and output
1273 * the errors to @output
1274 *
1275 * Returns the number of errors found
1276 */
1277int
1278xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1279{
1280 xmlDebugCtxt ctxt;
1281
1282 if (output == NULL)
1283 output = stdout;
1284 xmlCtxtDumpInitCtxt(&ctxt);
1285 ctxt.output = output;
1286 ctxt.check = 1;
1287 xmlCtxtDumpDocument(&ctxt, doc);
1288 return(ctxt.errors);
1289}
1290
1291/************************************************************************
1292 * *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001293 * Helpers for Shell *
1294 * *
1295 ************************************************************************/
Owen Taylor3473f882001-02-23 17:55:21 +00001296
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001297/**
1298 * xmlLsCountNode:
1299 * @node: the node to count
1300 *
1301 * Count the children of @node.
1302 *
1303 * Returns the number of children of @node.
1304 */
1305int
1306xmlLsCountNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001307 int ret = 0;
1308 xmlNodePtr list = NULL;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001309
1310 if (node == NULL)
1311 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001312
1313 switch (node->type) {
1314 case XML_ELEMENT_NODE:
1315 list = node->children;
1316 break;
1317 case XML_DOCUMENT_NODE:
1318 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00001319#ifdef LIBXML_DOCB_ENABLED
1320 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00001321#endif
1322 list = ((xmlDocPtr) node)->children;
1323 break;
1324 case XML_ATTRIBUTE_NODE:
1325 list = ((xmlAttrPtr) node)->children;
1326 break;
1327 case XML_TEXT_NODE:
1328 case XML_CDATA_SECTION_NODE:
1329 case XML_PI_NODE:
1330 case XML_COMMENT_NODE:
1331 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001332 ret = xmlStrlen(node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001333 }
1334 break;
1335 case XML_ENTITY_REF_NODE:
1336 case XML_DOCUMENT_TYPE_NODE:
1337 case XML_ENTITY_NODE:
1338 case XML_DOCUMENT_FRAG_NODE:
1339 case XML_NOTATION_NODE:
1340 case XML_DTD_NODE:
1341 case XML_ELEMENT_DECL:
1342 case XML_ATTRIBUTE_DECL:
1343 case XML_ENTITY_DECL:
1344 case XML_NAMESPACE_DECL:
1345 case XML_XINCLUDE_START:
1346 case XML_XINCLUDE_END:
1347 ret = 1;
1348 break;
1349 }
1350 for (;list != NULL;ret++)
1351 list = list->next;
1352 return(ret);
1353}
1354
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001355/**
1356 * xmlLsOneNode:
1357 * @output: the FILE * for the output
1358 * @node: the node to dump
1359 *
1360 * Dump to @output the type and name of @node.
1361 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001362void
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001363xmlLsOneNode(FILE *output, xmlNodePtr node) {
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001364 if (node == NULL) {
1365 fprintf(output, "NULL\n");
1366 return;
1367 }
Owen Taylor3473f882001-02-23 17:55:21 +00001368 switch (node->type) {
1369 case XML_ELEMENT_NODE:
1370 fprintf(output, "-");
1371 break;
1372 case XML_ATTRIBUTE_NODE:
1373 fprintf(output, "a");
1374 break;
1375 case XML_TEXT_NODE:
1376 fprintf(output, "t");
1377 break;
1378 case XML_CDATA_SECTION_NODE:
Daniel Veillard75be0132002-03-13 10:03:35 +00001379 fprintf(output, "C");
Owen Taylor3473f882001-02-23 17:55:21 +00001380 break;
1381 case XML_ENTITY_REF_NODE:
1382 fprintf(output, "e");
1383 break;
1384 case XML_ENTITY_NODE:
1385 fprintf(output, "E");
1386 break;
1387 case XML_PI_NODE:
1388 fprintf(output, "p");
1389 break;
1390 case XML_COMMENT_NODE:
1391 fprintf(output, "c");
1392 break;
1393 case XML_DOCUMENT_NODE:
1394 fprintf(output, "d");
1395 break;
1396 case XML_HTML_DOCUMENT_NODE:
1397 fprintf(output, "h");
1398 break;
1399 case XML_DOCUMENT_TYPE_NODE:
1400 fprintf(output, "T");
1401 break;
1402 case XML_DOCUMENT_FRAG_NODE:
1403 fprintf(output, "F");
1404 break;
1405 case XML_NOTATION_NODE:
1406 fprintf(output, "N");
1407 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001408 case XML_NAMESPACE_DECL:
1409 fprintf(output, "n");
1410 break;
Owen Taylor3473f882001-02-23 17:55:21 +00001411 default:
1412 fprintf(output, "?");
1413 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00001414 if (node->type != XML_NAMESPACE_DECL) {
1415 if (node->properties != NULL)
1416 fprintf(output, "a");
1417 else
1418 fprintf(output, "-");
1419 if (node->nsDef != NULL)
1420 fprintf(output, "n");
1421 else
1422 fprintf(output, "-");
1423 }
Owen Taylor3473f882001-02-23 17:55:21 +00001424
1425 fprintf(output, " %8d ", xmlLsCountNode(node));
1426
1427 switch (node->type) {
1428 case XML_ELEMENT_NODE:
1429 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001430 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001431 break;
1432 case XML_ATTRIBUTE_NODE:
1433 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001434 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001435 break;
1436 case XML_TEXT_NODE:
1437 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001438 xmlDebugDumpString(output, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001439 }
1440 break;
1441 case XML_CDATA_SECTION_NODE:
1442 break;
1443 case XML_ENTITY_REF_NODE:
1444 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001445 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001446 break;
1447 case XML_ENTITY_NODE:
1448 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001449 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001450 break;
1451 case XML_PI_NODE:
1452 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001453 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001454 break;
1455 case XML_COMMENT_NODE:
1456 break;
1457 case XML_DOCUMENT_NODE:
1458 break;
1459 case XML_HTML_DOCUMENT_NODE:
1460 break;
1461 case XML_DOCUMENT_TYPE_NODE:
1462 break;
1463 case XML_DOCUMENT_FRAG_NODE:
1464 break;
1465 case XML_NOTATION_NODE:
1466 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001467 case XML_NAMESPACE_DECL: {
1468 xmlNsPtr ns = (xmlNsPtr) node;
1469
1470 if (ns->prefix == NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00001471 fprintf(output, "default -> %s", (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001472 else
William M. Brack13dfa872004-09-18 04:52:08 +00001473 fprintf(output, "%s -> %s", (char *)ns->prefix,
1474 (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001475 break;
1476 }
Owen Taylor3473f882001-02-23 17:55:21 +00001477 default:
1478 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001479 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001480 }
1481 fprintf(output, "\n");
1482}
1483
Daniel Veillard78d12092001-10-11 09:12:24 +00001484/**
1485 * xmlBoolToText:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001486 * @boolval: a bool to turn into text
Daniel Veillard78d12092001-10-11 09:12:24 +00001487 *
1488 * Convenient way to turn bool into text
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001489 *
1490 * Returns a pointer to either "True" or "False"
1491 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001492const char *
Daniel Veillardebd38c52001-11-01 08:38:12 +00001493xmlBoolToText(int boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001494{
Daniel Veillardebd38c52001-11-01 08:38:12 +00001495 if (boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001496 return("True");
1497 else
1498 return("False");
1499}
1500
Owen Taylor3473f882001-02-23 17:55:21 +00001501/****************************************************************
1502 * *
1503 * The XML shell related functions *
1504 * *
1505 ****************************************************************/
1506
Daniel Veillard78d12092001-10-11 09:12:24 +00001507
1508
Owen Taylor3473f882001-02-23 17:55:21 +00001509/*
1510 * TODO: Improvement/cleanups for the XML shell
1511 * - allow to shell out an editor on a subpart
1512 * - cleanup function registrations (with help) and calling
1513 * - provide registration routines
1514 */
1515
1516/**
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001517 * xmlShellPrintXPathError:
Daniel Veillard78d12092001-10-11 09:12:24 +00001518 * @errorType: valid xpath error id
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001519 * @arg: the argument that cause xpath to fail
Daniel Veillard78d12092001-10-11 09:12:24 +00001520 *
1521 * Print the xpath error to libxml default error channel
1522 */
1523void
1524xmlShellPrintXPathError(int errorType, const char *arg)
1525{
1526 const char *default_arg = "Result";
1527
1528 if (!arg)
1529 arg = default_arg;
1530
1531 switch (errorType) {
1532 case XPATH_UNDEFINED:
1533 xmlGenericError(xmlGenericErrorContext,
1534 "%s: no such node\n", arg);
1535 break;
1536
1537 case XPATH_BOOLEAN:
1538 xmlGenericError(xmlGenericErrorContext,
1539 "%s is a Boolean\n", arg);
1540 break;
1541 case XPATH_NUMBER:
1542 xmlGenericError(xmlGenericErrorContext,
1543 "%s is a number\n", arg);
1544 break;
1545 case XPATH_STRING:
1546 xmlGenericError(xmlGenericErrorContext,
1547 "%s is a string\n", arg);
1548 break;
1549 case XPATH_POINT:
1550 xmlGenericError(xmlGenericErrorContext,
1551 "%s is a point\n", arg);
1552 break;
1553 case XPATH_RANGE:
1554 xmlGenericError(xmlGenericErrorContext,
1555 "%s is a range\n", arg);
1556 break;
1557 case XPATH_LOCATIONSET:
1558 xmlGenericError(xmlGenericErrorContext,
1559 "%s is a range\n", arg);
1560 break;
1561 case XPATH_USERS:
1562 xmlGenericError(xmlGenericErrorContext,
1563 "%s is user-defined\n", arg);
1564 break;
1565 case XPATH_XSLT_TREE:
1566 xmlGenericError(xmlGenericErrorContext,
1567 "%s is an XSLT value tree\n", arg);
1568 break;
1569 }
1570 xmlGenericError(xmlGenericErrorContext,
1571 "Try casting the result string function (xpath builtin)\n",
1572 arg);
1573}
1574
1575
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001576#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001577/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001578 * xmlShellPrintNodeCtxt:
1579 * @ctxt : a non-null shell context
1580 * @node : a non-null node to print to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001581 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001582 * Print node to the output FILE
1583 */
1584static void
1585xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1586{
Daniel Veillard01992e02002-10-09 10:20:30 +00001587 FILE *fp;
1588
1589 if (!node)
Daniel Veillard321be0c2002-10-08 21:26:42 +00001590 return;
Daniel Veillard01992e02002-10-09 10:20:30 +00001591 if (ctxt == NULL)
1592 fp = stdout;
1593 else
1594 fp = ctxt->output;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001595
1596 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001597 xmlDocDump(fp, (xmlDocPtr) node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001598 else if (node->type == XML_ATTRIBUTE_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001599 xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001600 else
Daniel Veillard01992e02002-10-09 10:20:30 +00001601 xmlElemDump(fp, node->doc, node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001602
Daniel Veillard01992e02002-10-09 10:20:30 +00001603 fprintf(fp, "\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00001604}
1605
1606/**
1607 * xmlShellPrintNode:
1608 * @node : a non-null node to print to the output FILE
1609 *
1610 * Print node to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001611 */
1612void
1613xmlShellPrintNode(xmlNodePtr node)
1614{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001615 xmlShellPrintNodeCtxt(NULL, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001616}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001617#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001618
Daniel Veillard78d12092001-10-11 09:12:24 +00001619/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001620 * xmlShellPrintXPathResultCtxt:
1621 * @ctxt: a valid shell context
Daniel Veillard9d06d302002-01-22 18:15:52 +00001622 * @list: a valid result generated by an xpath evaluation
Daniel Veillard78d12092001-10-11 09:12:24 +00001623 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001624 * Prints result to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001625 */
Daniel Veillard321be0c2002-10-08 21:26:42 +00001626static void
1627xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
Daniel Veillard78d12092001-10-11 09:12:24 +00001628{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001629 if (!ctxt)
1630 return;
Daniel Veillard78d12092001-10-11 09:12:24 +00001631
1632 if (list != NULL) {
1633 switch (list->type) {
1634 case XPATH_NODESET:{
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001635#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001636 int indx;
1637
1638 if (list->nodesetval) {
1639 for (indx = 0; indx < list->nodesetval->nodeNr;
1640 indx++) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001641 xmlShellPrintNodeCtxt(ctxt,
1642 list->nodesetval->nodeTab[indx]);
Daniel Veillard78d12092001-10-11 09:12:24 +00001643 }
1644 } else {
1645 xmlGenericError(xmlGenericErrorContext,
1646 "Empty node set\n");
1647 }
1648 break;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001649#else
1650 xmlGenericError(xmlGenericErrorContext,
1651 "Node set\n");
1652#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001653 }
1654 case XPATH_BOOLEAN:
1655 xmlGenericError(xmlGenericErrorContext,
1656 "Is a Boolean:%s\n",
1657 xmlBoolToText(list->boolval));
1658 break;
1659 case XPATH_NUMBER:
1660 xmlGenericError(xmlGenericErrorContext,
1661 "Is a number:%0g\n", list->floatval);
1662 break;
1663 case XPATH_STRING:
1664 xmlGenericError(xmlGenericErrorContext,
1665 "Is a string:%s\n", list->stringval);
1666 break;
1667
1668 default:
1669 xmlShellPrintXPathError(list->type, NULL);
1670 }
1671 }
1672}
1673
1674/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001675 * xmlShellPrintXPathResult:
1676 * @list: a valid result generated by an xpath evaluation
1677 *
1678 * Prints result to the output FILE
1679 */
1680void
1681xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1682{
1683 xmlShellPrintXPathResultCtxt(NULL, list);
1684}
1685
1686/**
Owen Taylor3473f882001-02-23 17:55:21 +00001687 * xmlShellList:
1688 * @ctxt: the shell context
1689 * @arg: unused
1690 * @node: a node
1691 * @node2: unused
1692 *
1693 * Implements the XML shell function "ls"
1694 * Does an Unix like listing of the given node (like a directory)
1695 *
1696 * Returns 0
1697 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001698int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001699xmlShellList(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001700 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1701 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1702{
Owen Taylor3473f882001-02-23 17:55:21 +00001703 xmlNodePtr cur;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001704 if (!ctxt)
1705 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001706 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001707 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001708 return (0);
1709 }
Owen Taylor3473f882001-02-23 17:55:21 +00001710 if ((node->type == XML_DOCUMENT_NODE) ||
1711 (node->type == XML_HTML_DOCUMENT_NODE)) {
1712 cur = ((xmlDocPtr) node)->children;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001713 } else if (node->type == XML_NAMESPACE_DECL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001714 xmlLsOneNode(ctxt->output, node);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001715 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001716 } else if (node->children != NULL) {
1717 cur = node->children;
1718 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001719 xmlLsOneNode(ctxt->output, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001720 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001721 }
1722 while (cur != NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001723 xmlLsOneNode(ctxt->output, cur);
Daniel Veillard78d12092001-10-11 09:12:24 +00001724 cur = cur->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001725 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001726 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001727}
1728
1729/**
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001730 * xmlShellBase:
1731 * @ctxt: the shell context
1732 * @arg: unused
1733 * @node: a node
1734 * @node2: unused
1735 *
1736 * Implements the XML shell function "base"
1737 * dumps the current XML base of the node
1738 *
1739 * Returns 0
1740 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001741int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001742xmlShellBase(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001743 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1744 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1745{
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001746 xmlChar *base;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001747 if (!ctxt)
1748 return 0;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001749 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001750 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001751 return (0);
1752 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001753
1754 base = xmlNodeGetBase(node->doc, node);
1755
1756 if (base == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001757 fprintf(ctxt->output, " No base found !!!\n");
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001758 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001759 fprintf(ctxt->output, "%s\n", base);
Daniel Veillard78d12092001-10-11 09:12:24 +00001760 xmlFree(base);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001761 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001762 return (0);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001763}
1764
Daniel Veillardb34321c2004-03-04 17:09:47 +00001765#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001766/**
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001767 * xmlShellSetBase:
1768 * @ctxt: the shell context
1769 * @arg: the new base
1770 * @node: a node
1771 * @node2: unused
1772 *
1773 * Implements the XML shell function "setbase"
1774 * change the current XML base of the node
1775 *
1776 * Returns 0
1777 */
1778static int
1779xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1780 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1781 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1782{
1783 xmlNodeSetBase(node, (xmlChar*) arg);
1784 return (0);
1785}
Daniel Veillard2156d432004-03-04 15:59:36 +00001786#endif
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001787
Daniel Veillardbbaa9972004-06-16 14:08:33 +00001788#ifdef LIBXML_XPATH_ENABLED
1789/**
1790 * xmlShellRegisterNamespace:
1791 * @ctxt: the shell context
1792 * @arg: a string in prefix=nsuri format
1793 * @node: unused
1794 * @node2: unused
1795 *
1796 * Implements the XML shell function "setns"
1797 * register/unregister a prefix=namespace pair
1798 * on the XPath context
1799 *
1800 * Returns 0 on success and a negative value otherwise.
1801 */
1802static int
1803xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
1804 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1805{
1806 xmlChar* nsListDup;
1807 xmlChar* prefix;
1808 xmlChar* href;
1809 xmlChar* next;
1810
1811 nsListDup = xmlStrdup((xmlChar *) arg);
1812 next = nsListDup;
1813 while(next != NULL) {
1814 /* skip spaces */
1815 /*while((*next) == ' ') next++;*/
1816 if((*next) == '\0') break;
1817
1818 /* find prefix */
1819 prefix = next;
1820 next = (xmlChar*)xmlStrchr(next, '=');
1821 if(next == NULL) {
1822 fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
1823 xmlFree(nsListDup);
1824 return(-1);
1825 }
1826 *(next++) = '\0';
1827
1828 /* find href */
1829 href = next;
1830 next = (xmlChar*)xmlStrchr(next, ' ');
1831 if(next != NULL) {
1832 *(next++) = '\0';
1833 }
1834
1835 /* do register namespace */
1836 if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
1837 fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
1838 xmlFree(nsListDup);
1839 return(-1);
1840 }
1841 }
1842
1843 xmlFree(nsListDup);
1844 return(0);
1845}
1846#endif
1847
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001848/**
Daniel Veillard1e208222002-10-22 14:25:25 +00001849 * xmlShellGrep:
1850 * @ctxt: the shell context
1851 * @arg: the string or regular expression to find
1852 * @node: a node
1853 * @node2: unused
1854 *
1855 * Implements the XML shell function "grep"
1856 * dumps informations about the node (namespace, attributes, content).
1857 *
1858 * Returns 0
1859 */
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001860static int
Daniel Veillard1e208222002-10-22 14:25:25 +00001861xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1862 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1863{
1864 if (!ctxt)
1865 return (0);
1866 if (node == NULL)
1867 return (0);
1868 if (arg == NULL)
1869 return (0);
1870#ifdef LIBXML_REGEXP_ENABLED
1871 if ((xmlStrchr((xmlChar *) arg, '?')) ||
1872 (xmlStrchr((xmlChar *) arg, '*')) ||
1873 (xmlStrchr((xmlChar *) arg, '.')) ||
1874 (xmlStrchr((xmlChar *) arg, '['))) {
1875 }
1876#endif
1877 while (node != NULL) {
1878 if (node->type == XML_COMMENT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001879 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00001880
1881 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
1882 xmlShellList(ctxt, NULL, node, NULL);
1883 }
1884 } else if (node->type == XML_TEXT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001885 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00001886
1887 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001888 xmlShellList(ctxt, NULL, node->parent, NULL);
Daniel Veillard1e208222002-10-22 14:25:25 +00001889 }
1890 }
1891
1892 /*
1893 * Browse the full subtree, deep first
1894 */
1895
1896 if ((node->type == XML_DOCUMENT_NODE) ||
1897 (node->type == XML_HTML_DOCUMENT_NODE)) {
1898 node = ((xmlDocPtr) node)->children;
1899 } else if ((node->children != NULL)
1900 && (node->type != XML_ENTITY_REF_NODE)) {
1901 /* deep first */
1902 node = node->children;
1903 } else if (node->next != NULL) {
1904 /* then siblings */
1905 node = node->next;
1906 } else {
1907 /* go up to parents->next if needed */
1908 while (node != NULL) {
1909 if (node->parent != NULL) {
1910 node = node->parent;
1911 }
1912 if (node->next != NULL) {
1913 node = node->next;
1914 break;
1915 }
1916 if (node->parent == NULL) {
1917 node = NULL;
1918 break;
1919 }
1920 }
1921 }
1922 }
1923 return (0);
1924}
1925
1926/**
Owen Taylor3473f882001-02-23 17:55:21 +00001927 * xmlShellDir:
1928 * @ctxt: the shell context
1929 * @arg: unused
1930 * @node: a node
1931 * @node2: unused
1932 *
1933 * Implements the XML shell function "dir"
1934 * dumps informations about the node (namespace, attributes, content).
1935 *
1936 * Returns 0
1937 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001938int
1939xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1940 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1941 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1942{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001943 if (!ctxt)
1944 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001945 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001946 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001947 return (0);
1948 }
Owen Taylor3473f882001-02-23 17:55:21 +00001949 if ((node->type == XML_DOCUMENT_NODE) ||
1950 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001951 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
Owen Taylor3473f882001-02-23 17:55:21 +00001952 } else if (node->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001953 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001954 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001955 xmlDebugDumpOneNode(ctxt->output, node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001956 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001957 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001958}
1959
Daniel Veillard29b17482004-08-16 00:39:03 +00001960/**
1961 * xmlShellSetContent:
1962 * @ctxt: the shell context
1963 * @value: the content as a string
1964 * @node: a node
1965 * @node2: unused
1966 *
1967 * Implements the XML shell function "dir"
1968 * dumps informations about the node (namespace, attributes, content).
1969 *
1970 * Returns 0
1971 */
1972static int
1973xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1974 char *value, xmlNodePtr node,
1975 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1976{
1977 xmlNodePtr results;
1978 xmlParserErrors ret;
1979
1980 if (!ctxt)
1981 return (0);
1982 if (node == NULL) {
1983 fprintf(ctxt->output, "NULL\n");
1984 return (0);
1985 }
1986 if (value == NULL) {
1987 fprintf(ctxt->output, "NULL\n");
1988 return (0);
1989 }
1990
1991 ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
1992 if (ret == XML_ERR_OK) {
1993 if (node->children != NULL) {
1994 xmlFreeNodeList(node->children);
1995 node->children = NULL;
1996 node->last = NULL;
1997 }
1998 xmlAddChildList(node, results);
1999 } else {
2000 fprintf(ctxt->output, "failed to parse content\n");
2001 }
2002 return (0);
2003}
2004
Daniel Veillard522bc602004-02-21 11:53:09 +00002005#ifdef LIBXML_SCHEMAS_ENABLED
2006/**
2007 * xmlShellRNGValidate:
2008 * @ctxt: the shell context
2009 * @schemas: the path to the Relax-NG schemas
2010 * @node: a node
2011 * @node2: unused
2012 *
2013 * Implements the XML shell function "relaxng"
2014 * validating the instance against a Relax-NG schemas
2015 *
2016 * Returns 0
2017 */
2018static int
2019xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2020 xmlNodePtr node ATTRIBUTE_UNUSED,
2021 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2022{
2023 xmlRelaxNGPtr relaxngschemas;
2024 xmlRelaxNGParserCtxtPtr ctxt;
2025 xmlRelaxNGValidCtxtPtr vctxt;
2026 int ret;
2027
2028 ctxt = xmlRelaxNGNewParserCtxt(schemas);
2029 xmlRelaxNGSetParserErrors(ctxt,
2030 (xmlRelaxNGValidityErrorFunc) fprintf,
2031 (xmlRelaxNGValidityWarningFunc) fprintf,
2032 stderr);
2033 relaxngschemas = xmlRelaxNGParse(ctxt);
2034 xmlRelaxNGFreeParserCtxt(ctxt);
2035 if (relaxngschemas == NULL) {
2036 xmlGenericError(xmlGenericErrorContext,
2037 "Relax-NG schema %s failed to compile\n", schemas);
2038 return(-1);
2039 }
2040 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2041 xmlRelaxNGSetValidErrors(vctxt,
2042 (xmlRelaxNGValidityErrorFunc) fprintf,
2043 (xmlRelaxNGValidityWarningFunc) fprintf,
2044 stderr);
2045 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2046 if (ret == 0) {
2047 fprintf(stderr, "%s validates\n", sctxt->filename);
2048 } else if (ret > 0) {
2049 fprintf(stderr, "%s fails to validate\n", sctxt->filename);
2050 } else {
2051 fprintf(stderr, "%s validation generated an internal error\n",
2052 sctxt->filename);
2053 }
2054 xmlRelaxNGFreeValidCtxt(vctxt);
2055 if (relaxngschemas != NULL)
2056 xmlRelaxNGFree(relaxngschemas);
2057 return(0);
2058}
2059#endif
2060
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002061#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002062/**
2063 * xmlShellCat:
2064 * @ctxt: the shell context
2065 * @arg: unused
2066 * @node: a node
2067 * @node2: unused
2068 *
2069 * Implements the XML shell function "cat"
2070 * dumps the serialization node content (XML or HTML).
2071 *
2072 * Returns 0
2073 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002074int
2075xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2076 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2077{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002078 if (!ctxt)
2079 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002080 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002081 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002082 return (0);
2083 }
Owen Taylor3473f882001-02-23 17:55:21 +00002084 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2085#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002086 if (node->type == XML_HTML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002087 htmlDocDump(ctxt->output, (htmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002088 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002089 htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002090#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002091 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002092 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002093 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002094 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002095#endif /* LIBXML_HTML_ENABLED */
2096 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00002097 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002098 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002099 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002100 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002101 }
Daniel Veillard321be0c2002-10-08 21:26:42 +00002102 fprintf(ctxt->output, "\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002103 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002104}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002105#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002106
2107/**
2108 * xmlShellLoad:
2109 * @ctxt: the shell context
2110 * @filename: the file name
2111 * @node: unused
2112 * @node2: unused
2113 *
2114 * Implements the XML shell function "load"
2115 * loads a new document specified by the filename
2116 *
2117 * Returns 0 or -1 if loading failed
2118 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002119int
2120xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2121 xmlNodePtr node ATTRIBUTE_UNUSED,
2122 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2123{
Owen Taylor3473f882001-02-23 17:55:21 +00002124 xmlDocPtr doc;
2125 int html = 0;
2126
2127 if (ctxt->doc != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002128 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00002129
2130 if (html) {
2131#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002132 doc = htmlParseFile(filename, NULL);
2133#else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002134 fprintf(ctxt->output, "HTML support not compiled in\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002135 doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002136#endif /* LIBXML_HTML_ENABLED */
2137 } else {
Daniel Veillardebe25d42004-03-25 09:35:49 +00002138 doc = xmlReadFile(filename,NULL,0);
Owen Taylor3473f882001-02-23 17:55:21 +00002139 }
2140 if (doc != NULL) {
2141 if (ctxt->loaded == 1) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002142 xmlFreeDoc(ctxt->doc);
2143 }
2144 ctxt->loaded = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002145#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002146 xmlXPathFreeContext(ctxt->pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002147#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002148 xmlFree(ctxt->filename);
2149 ctxt->doc = doc;
2150 ctxt->node = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002151#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002152 ctxt->pctxt = xmlXPathNewContext(doc);
Owen Taylor3473f882001-02-23 17:55:21 +00002153#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard85095e22003-04-23 13:56:44 +00002154 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002155 } else
Daniel Veillard78d12092001-10-11 09:12:24 +00002156 return (-1);
2157 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002158}
2159
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002160#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002161/**
2162 * xmlShellWrite:
2163 * @ctxt: the shell context
2164 * @filename: the file name
2165 * @node: a node in the tree
2166 * @node2: unused
2167 *
2168 * Implements the XML shell function "write"
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002169 * Write the current node to the filename, it saves the serialization
Owen Taylor3473f882001-02-23 17:55:21 +00002170 * of the subtree under the @node specified
2171 *
2172 * Returns 0 or -1 in case of error
2173 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002174int
Owen Taylor3473f882001-02-23 17:55:21 +00002175xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
Daniel Veillard78d12092001-10-11 09:12:24 +00002176 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2177{
Owen Taylor3473f882001-02-23 17:55:21 +00002178 if (node == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002179 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002180 if ((filename == NULL) || (filename[0] == 0)) {
2181 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002182 "Write command requires a filename argument\n");
2183 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002184 }
2185#ifdef W_OK
2186 if (access((char *) filename, W_OK)) {
2187 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002188 "Cannot write to %s\n", filename);
2189 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002190 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002191#endif
2192 switch (node->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002193 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002194 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2195 xmlGenericError(xmlGenericErrorContext,
2196 "Failed to write to %s\n", filename);
2197 return (-1);
2198 }
2199 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002200 case XML_HTML_DOCUMENT_NODE:
2201#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002202 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2203 xmlGenericError(xmlGenericErrorContext,
2204 "Failed to write to %s\n", filename);
2205 return (-1);
2206 }
Owen Taylor3473f882001-02-23 17:55:21 +00002207#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002208 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2209 xmlGenericError(xmlGenericErrorContext,
2210 "Failed to write to %s\n", filename);
2211 return (-1);
2212 }
Owen Taylor3473f882001-02-23 17:55:21 +00002213#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002214 break;
2215 default:{
2216 FILE *f;
Owen Taylor3473f882001-02-23 17:55:21 +00002217
Daniel Veillard78d12092001-10-11 09:12:24 +00002218 f = fopen((char *) filename, "w");
2219 if (f == NULL) {
2220 xmlGenericError(xmlGenericErrorContext,
2221 "Failed to write to %s\n", filename);
2222 return (-1);
2223 }
2224 xmlElemDump(f, ctxt->doc, node);
2225 fclose(f);
2226 }
Owen Taylor3473f882001-02-23 17:55:21 +00002227 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002228 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002229}
2230
2231/**
2232 * xmlShellSave:
2233 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002234 * @filename: the file name (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002235 * @node: unused
2236 * @node2: unused
2237 *
2238 * Implements the XML shell function "save"
2239 * Write the current document to the filename, or it's original name
2240 *
2241 * Returns 0 or -1 in case of error
2242 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002243int
2244xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2245 xmlNodePtr node ATTRIBUTE_UNUSED,
2246 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2247{
Owen Taylor3473f882001-02-23 17:55:21 +00002248 if (ctxt->doc == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002249 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002250 if ((filename == NULL) || (filename[0] == 0))
2251 filename = ctxt->filename;
2252#ifdef W_OK
2253 if (access((char *) filename, W_OK)) {
2254 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002255 "Cannot save to %s\n", filename);
2256 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002257 }
2258#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002259 switch (ctxt->doc->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002260 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002261 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2262 xmlGenericError(xmlGenericErrorContext,
2263 "Failed to save to %s\n", filename);
2264 }
2265 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002266 case XML_HTML_DOCUMENT_NODE:
2267#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002268 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2269 xmlGenericError(xmlGenericErrorContext,
2270 "Failed to save to %s\n", filename);
2271 }
Owen Taylor3473f882001-02-23 17:55:21 +00002272#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002273 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2274 xmlGenericError(xmlGenericErrorContext,
2275 "Failed to save to %s\n", filename);
2276 }
Owen Taylor3473f882001-02-23 17:55:21 +00002277#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002278 break;
2279 default:
2280 xmlGenericError(xmlGenericErrorContext,
2281 "To save to subparts of a document use the 'write' command\n");
2282 return (-1);
2283
Owen Taylor3473f882001-02-23 17:55:21 +00002284 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002285 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002286}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002287#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002288
Daniel Veillardf54cd532004-02-25 11:52:31 +00002289#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002290/**
2291 * xmlShellValidate:
2292 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002293 * @dtd: the DTD URI (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002294 * @node: unused
2295 * @node2: unused
2296 *
2297 * Implements the XML shell function "validate"
2298 * Validate the document, if a DTD path is provided, then the validation
2299 * is done against the given DTD.
2300 *
2301 * Returns 0 or -1 in case of error
2302 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002303int
2304xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2305 xmlNodePtr node ATTRIBUTE_UNUSED,
2306 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2307{
Owen Taylor3473f882001-02-23 17:55:21 +00002308 xmlValidCtxt vctxt;
2309 int res = -1;
2310
2311 vctxt.userData = stderr;
2312 vctxt.error = (xmlValidityErrorFunc) fprintf;
2313 vctxt.warning = (xmlValidityWarningFunc) fprintf;
2314
2315 if ((dtd == NULL) || (dtd[0] == 0)) {
2316 res = xmlValidateDocument(&vctxt, ctxt->doc);
2317 } else {
2318 xmlDtdPtr subset;
2319
Daniel Veillard78d12092001-10-11 09:12:24 +00002320 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2321 if (subset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002322 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2323
Daniel Veillard78d12092001-10-11 09:12:24 +00002324 xmlFreeDtd(subset);
2325 }
Owen Taylor3473f882001-02-23 17:55:21 +00002326 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002327 return (res);
Owen Taylor3473f882001-02-23 17:55:21 +00002328}
Daniel Veillardf54cd532004-02-25 11:52:31 +00002329#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002330
2331/**
2332 * xmlShellDu:
2333 * @ctxt: the shell context
2334 * @arg: unused
2335 * @tree: a node defining a subtree
2336 * @node2: unused
2337 *
2338 * Implements the XML shell function "du"
2339 * show the structure of the subtree under node @tree
2340 * If @tree is null, the command works on the current node.
2341 *
2342 * Returns 0 or -1 in case of error
2343 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002344int
Daniel Veillard321be0c2002-10-08 21:26:42 +00002345xmlShellDu(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00002346 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2347 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2348{
Owen Taylor3473f882001-02-23 17:55:21 +00002349 xmlNodePtr node;
Daniel Veillard78d12092001-10-11 09:12:24 +00002350 int indent = 0, i;
Owen Taylor3473f882001-02-23 17:55:21 +00002351
Daniel Veillard321be0c2002-10-08 21:26:42 +00002352 if (!ctxt)
2353 return (-1);
2354
Daniel Veillard78d12092001-10-11 09:12:24 +00002355 if (tree == NULL)
2356 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002357 node = tree;
2358 while (node != NULL) {
2359 if ((node->type == XML_DOCUMENT_NODE) ||
2360 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002361 fprintf(ctxt->output, "/\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002362 } else if (node->type == XML_ELEMENT_NODE) {
2363 for (i = 0; i < indent; i++)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002364 fprintf(ctxt->output, " ");
2365 fprintf(ctxt->output, "%s\n", node->name);
Daniel Veillard78d12092001-10-11 09:12:24 +00002366 } else {
2367 }
Owen Taylor3473f882001-02-23 17:55:21 +00002368
Daniel Veillard78d12092001-10-11 09:12:24 +00002369 /*
2370 * Browse the full subtree, deep first
2371 */
Owen Taylor3473f882001-02-23 17:55:21 +00002372
2373 if ((node->type == XML_DOCUMENT_NODE) ||
2374 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002375 node = ((xmlDocPtr) node)->children;
2376 } else if ((node->children != NULL)
2377 && (node->type != XML_ENTITY_REF_NODE)) {
2378 /* deep first */
2379 node = node->children;
2380 indent++;
2381 } else if ((node != tree) && (node->next != NULL)) {
2382 /* then siblings */
2383 node = node->next;
2384 } else if (node != tree) {
2385 /* go up to parents->next if needed */
2386 while (node != tree) {
2387 if (node->parent != NULL) {
2388 node = node->parent;
2389 indent--;
2390 }
2391 if ((node != tree) && (node->next != NULL)) {
2392 node = node->next;
2393 break;
2394 }
2395 if (node->parent == NULL) {
2396 node = NULL;
2397 break;
2398 }
2399 if (node == tree) {
2400 node = NULL;
2401 break;
2402 }
2403 }
2404 /* exit condition */
2405 if (node == tree)
2406 node = NULL;
2407 } else
2408 node = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002409 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002410 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002411}
2412
2413/**
2414 * xmlShellPwd:
2415 * @ctxt: the shell context
2416 * @buffer: the output buffer
Daniel Veillard9d06d302002-01-22 18:15:52 +00002417 * @node: a node
Owen Taylor3473f882001-02-23 17:55:21 +00002418 * @node2: unused
2419 *
2420 * Implements the XML shell function "pwd"
2421 * Show the full path from the root to the node, if needed building
2422 * thumblers when similar elements exists at a given ancestor level.
2423 * The output is compatible with XPath commands.
2424 *
2425 * Returns 0 or -1 in case of error
2426 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002427int
2428xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2429 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2430{
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002431 xmlChar *path;
Owen Taylor3473f882001-02-23 17:55:21 +00002432
Daniel Veillard78d12092001-10-11 09:12:24 +00002433 if (node == NULL)
2434 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002435
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002436 path = xmlGetNodePath(node);
2437 if (path == NULL)
2438 return (-1);
2439
2440 /*
2441 * This test prevents buffer overflow, because this routine
2442 * is only called by xmlShell, in which the second argument is
2443 * 500 chars long.
2444 * It is a dirty hack before a cleaner solution is found.
2445 * Documentation should mention that the second argument must
2446 * be at least 500 chars long, and could be stripped if too long.
2447 */
2448 snprintf(buffer, 499, "%s", path);
2449 buffer[499] = '0';
2450 xmlFree(path);
2451
Daniel Veillard78d12092001-10-11 09:12:24 +00002452 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002453}
2454
2455/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002456 * xmlShell:
Owen Taylor3473f882001-02-23 17:55:21 +00002457 * @doc: the initial document
2458 * @filename: the output buffer
2459 * @input: the line reading function
Daniel Veillard321be0c2002-10-08 21:26:42 +00002460 * @output: the output FILE*, defaults to stdout if NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002461 *
2462 * Implements the XML shell
2463 * This allow to load, validate, view, modify and save a document
2464 * using a environment similar to a UNIX commandline.
2465 */
2466void
2467xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
Daniel Veillard78d12092001-10-11 09:12:24 +00002468 FILE * output)
2469{
Owen Taylor3473f882001-02-23 17:55:21 +00002470 char prompt[500] = "/ > ";
2471 char *cmdline = NULL, *cur;
2472 int nbargs;
2473 char command[100];
2474 char arg[400];
2475 int i;
2476 xmlShellCtxtPtr ctxt;
2477 xmlXPathObjectPtr list;
2478
2479 if (doc == NULL)
2480 return;
2481 if (filename == NULL)
2482 return;
2483 if (input == NULL)
2484 return;
2485 if (output == NULL)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002486 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00002487 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
Daniel Veillard78d12092001-10-11 09:12:24 +00002488 if (ctxt == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002489 return;
2490 ctxt->loaded = 0;
2491 ctxt->doc = doc;
2492 ctxt->input = input;
2493 ctxt->output = output;
2494 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
Daniel Veillard78d12092001-10-11 09:12:24 +00002495 ctxt->node = (xmlNodePtr) ctxt->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002496
2497#ifdef LIBXML_XPATH_ENABLED
2498 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2499 if (ctxt->pctxt == NULL) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002500 xmlFree(ctxt);
2501 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002502 }
2503#endif /* LIBXML_XPATH_ENABLED */
2504 while (1) {
2505 if (ctxt->node == (xmlNodePtr) ctxt->doc)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002506 snprintf(prompt, sizeof(prompt), "%s > ", "/");
Daniel Veillard7a985a12003-07-06 17:57:42 +00002507 else if ((ctxt->node != NULL) && (ctxt->node->name))
Daniel Veillard78d12092001-10-11 09:12:24 +00002508 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002509 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002510 snprintf(prompt, sizeof(prompt), "? > ");
Owen Taylor3473f882001-02-23 17:55:21 +00002511 prompt[sizeof(prompt) - 1] = 0;
2512
Daniel Veillard78d12092001-10-11 09:12:24 +00002513 /*
2514 * Get a new command line
2515 */
Owen Taylor3473f882001-02-23 17:55:21 +00002516 cmdline = ctxt->input(prompt);
Daniel Veillard78d12092001-10-11 09:12:24 +00002517 if (cmdline == NULL)
2518 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002519
Daniel Veillard78d12092001-10-11 09:12:24 +00002520 /*
2521 * Parse the command itself
2522 */
2523 cur = cmdline;
2524 nbargs = 0;
2525 while ((*cur == ' ') || (*cur == '\t'))
2526 cur++;
2527 i = 0;
2528 while ((*cur != ' ') && (*cur != '\t') &&
2529 (*cur != '\n') && (*cur != '\r')) {
2530 if (*cur == 0)
2531 break;
2532 command[i++] = *cur++;
2533 }
2534 command[i] = 0;
2535 if (i == 0)
2536 continue;
2537 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002538
Daniel Veillard78d12092001-10-11 09:12:24 +00002539 /*
2540 * Parse the argument
2541 */
2542 while ((*cur == ' ') || (*cur == '\t'))
2543 cur++;
2544 i = 0;
2545 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2546 if (*cur == 0)
2547 break;
2548 arg[i++] = *cur++;
2549 }
2550 arg[i] = 0;
2551 if (i != 0)
2552 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002553
Daniel Veillard78d12092001-10-11 09:12:24 +00002554 /*
2555 * start interpreting the command
2556 */
Owen Taylor3473f882001-02-23 17:55:21 +00002557 if (!strcmp(command, "exit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002558 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002559 if (!strcmp(command, "quit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002560 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002561 if (!strcmp(command, "bye"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002562 break;
Daniel Veillard5004f422001-11-08 13:53:05 +00002563 if (!strcmp(command, "help")) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002564 fprintf(ctxt->output, "\tbase display XML base of the node\n");
2565 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n");
2566 fprintf(ctxt->output, "\tbye leave shell\n");
2567 fprintf(ctxt->output, "\tcat [node] display node or current node\n");
2568 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n");
2569 fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n");
2570 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n");
2571 fprintf(ctxt->output, "\texit leave shell\n");
2572 fprintf(ctxt->output, "\thelp display this help\n");
2573 fprintf(ctxt->output, "\tfree display memory usage\n");
2574 fprintf(ctxt->output, "\tload [name] load a new document with name\n");
2575 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n");
Daniel Veillardc14c3892004-08-16 12:34:50 +00002576 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 +00002577#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002578 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n");
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002579 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n");
2580 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
Daniel Veillard2070c482002-01-22 22:12:19 +00002581#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard321be0c2002-10-08 21:26:42 +00002582 fprintf(ctxt->output, "\tpwd display current working directory\n");
2583 fprintf(ctxt->output, "\tquit leave shell\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002584#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002585 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00002586 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002587#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf54cd532004-02-25 11:52:31 +00002588#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002589 fprintf(ctxt->output, "\tvalidate check the document for errors\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002590#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard522bc602004-02-21 11:53:09 +00002591#ifdef LIBXML_SCHEMAS_ENABLED
2592 fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n");
2593#endif
Daniel Veillard1e208222002-10-22 14:25:25 +00002594 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002595#ifdef LIBXML_VALID_ENABLED
Daniel Veillard5004f422001-11-08 13:53:05 +00002596 } else if (!strcmp(command, "validate")) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002597 xmlShellValidate(ctxt, arg, NULL, NULL);
Daniel Veillardf54cd532004-02-25 11:52:31 +00002598#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002599 } else if (!strcmp(command, "load")) {
2600 xmlShellLoad(ctxt, arg, NULL, NULL);
Daniel Veillard522bc602004-02-21 11:53:09 +00002601#ifdef LIBXML_SCHEMAS_ENABLED
2602 } else if (!strcmp(command, "relaxng")) {
2603 xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2604#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002605#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002606 } else if (!strcmp(command, "save")) {
2607 xmlShellSave(ctxt, arg, NULL, NULL);
2608 } else if (!strcmp(command, "write")) {
2609 xmlShellWrite(ctxt, arg, NULL, NULL);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002610#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard1e208222002-10-22 14:25:25 +00002611 } else if (!strcmp(command, "grep")) {
2612 xmlShellGrep(ctxt, arg, ctxt->node, NULL);
Daniel Veillard78d12092001-10-11 09:12:24 +00002613 } else if (!strcmp(command, "free")) {
2614 if (arg[0] == 0) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002615 xmlMemShow(ctxt->output, 0);
Daniel Veillard78d12092001-10-11 09:12:24 +00002616 } else {
2617 int len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002618
Daniel Veillard78d12092001-10-11 09:12:24 +00002619 sscanf(arg, "%d", &len);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002620 xmlMemShow(ctxt->output, len);
Daniel Veillard78d12092001-10-11 09:12:24 +00002621 }
2622 } else if (!strcmp(command, "pwd")) {
2623 char dir[500];
Owen Taylor3473f882001-02-23 17:55:21 +00002624
Daniel Veillard78d12092001-10-11 09:12:24 +00002625 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
Daniel Veillard321be0c2002-10-08 21:26:42 +00002626 fprintf(ctxt->output, "%s\n", dir);
Daniel Veillard78d12092001-10-11 09:12:24 +00002627 } else if (!strcmp(command, "du")) {
2628 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2629 } else if (!strcmp(command, "base")) {
2630 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
Daniel Veillard29b17482004-08-16 00:39:03 +00002631 } else if (!strcmp(command, "set")) {
2632 xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2070c482002-01-22 22:12:19 +00002633#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002634 } else if (!strcmp(command, "setns")) {
2635 if (arg[0] == 0) {
2636 xmlGenericError(xmlGenericErrorContext,
2637 "setns: prefix=[nsuri] required\n");
2638 } else {
2639 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
2640 }
Daniel Veillard2070c482002-01-22 22:12:19 +00002641 } else if (!strcmp(command, "xpath")) {
2642 if (arg[0] == 0) {
2643 xmlGenericError(xmlGenericErrorContext,
2644 "xpath: expression required\n");
2645 } else {
2646 ctxt->pctxt->node = ctxt->node;
2647 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002648 xmlXPathDebugDumpObject(ctxt->output, list, 0);
Daniel Veillard2070c482002-01-22 22:12:19 +00002649 xmlXPathFreeObject(list);
2650 }
2651#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard2156d432004-03-04 15:59:36 +00002652#ifdef LIBXML_TREE_ENABLED
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002653 } else if (!strcmp(command, "setbase")) {
2654 xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2156d432004-03-04 15:59:36 +00002655#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002656 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2657 int dir = (!strcmp(command, "dir"));
2658
2659 if (arg[0] == 0) {
2660 if (dir)
2661 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
2662 else
2663 xmlShellList(ctxt, NULL, ctxt->node, NULL);
2664 } else {
2665 ctxt->pctxt->node = ctxt->node;
Daniel Veillard61d80a22001-04-27 17:13:01 +00002666#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002667 ctxt->pctxt->node = ctxt->node;
2668 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2669#else
2670 list = NULL;
2671#endif /* LIBXML_XPATH_ENABLED */
2672 if (list != NULL) {
2673 switch (list->type) {
2674 case XPATH_UNDEFINED:
2675 xmlGenericError(xmlGenericErrorContext,
2676 "%s: no such node\n", arg);
2677 break;
2678 case XPATH_NODESET:{
2679 int indx;
2680
Daniel Veillarda6825e82001-11-07 13:33:59 +00002681 if (list->nodesetval == NULL)
2682 break;
2683
Daniel Veillard78d12092001-10-11 09:12:24 +00002684 for (indx = 0;
2685 indx < list->nodesetval->nodeNr;
2686 indx++) {
2687 if (dir)
2688 xmlShellDir(ctxt, NULL,
2689 list->nodesetval->
2690 nodeTab[indx], NULL);
2691 else
2692 xmlShellList(ctxt, NULL,
2693 list->nodesetval->
2694 nodeTab[indx], NULL);
2695 }
2696 break;
2697 }
2698 case XPATH_BOOLEAN:
2699 xmlGenericError(xmlGenericErrorContext,
2700 "%s is a Boolean\n", arg);
2701 break;
2702 case XPATH_NUMBER:
2703 xmlGenericError(xmlGenericErrorContext,
2704 "%s is a number\n", arg);
2705 break;
2706 case XPATH_STRING:
2707 xmlGenericError(xmlGenericErrorContext,
2708 "%s is a string\n", arg);
2709 break;
2710 case XPATH_POINT:
2711 xmlGenericError(xmlGenericErrorContext,
2712 "%s is a point\n", arg);
2713 break;
2714 case XPATH_RANGE:
2715 xmlGenericError(xmlGenericErrorContext,
2716 "%s is a range\n", arg);
2717 break;
2718 case XPATH_LOCATIONSET:
2719 xmlGenericError(xmlGenericErrorContext,
2720 "%s is a range\n", arg);
2721 break;
2722 case XPATH_USERS:
2723 xmlGenericError(xmlGenericErrorContext,
2724 "%s is user-defined\n", arg);
2725 break;
2726 case XPATH_XSLT_TREE:
2727 xmlGenericError(xmlGenericErrorContext,
2728 "%s is an XSLT value tree\n",
2729 arg);
2730 break;
2731 }
2732#ifdef LIBXML_XPATH_ENABLED
2733 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00002734#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002735 } else {
2736 xmlGenericError(xmlGenericErrorContext,
2737 "%s: no such node\n", arg);
2738 }
2739 ctxt->pctxt->node = NULL;
2740 }
2741 } else if (!strcmp(command, "cd")) {
2742 if (arg[0] == 0) {
2743 ctxt->node = (xmlNodePtr) ctxt->doc;
2744 } else {
2745#ifdef LIBXML_XPATH_ENABLED
2746 ctxt->pctxt->node = ctxt->node;
2747 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2748#else
2749 list = NULL;
2750#endif /* LIBXML_XPATH_ENABLED */
2751 if (list != NULL) {
2752 switch (list->type) {
2753 case XPATH_UNDEFINED:
2754 xmlGenericError(xmlGenericErrorContext,
2755 "%s: no such node\n", arg);
2756 break;
2757 case XPATH_NODESET:
Daniel Veillarda6825e82001-11-07 13:33:59 +00002758 if (list->nodesetval != NULL) {
2759 if (list->nodesetval->nodeNr == 1) {
2760 ctxt->node = list->nodesetval->nodeTab[0];
Daniel Veillard7a985a12003-07-06 17:57:42 +00002761 if ((ctxt->node != NULL) &&
2762 (ctxt->node->type ==
2763 XML_NAMESPACE_DECL)) {
2764 xmlGenericError(xmlGenericErrorContext,
2765 "cannot cd to namespace\n");
2766 ctxt->node = NULL;
2767 }
Daniel Veillarda6825e82001-11-07 13:33:59 +00002768 } else
2769 xmlGenericError(xmlGenericErrorContext,
2770 "%s is a %d Node Set\n",
2771 arg,
2772 list->nodesetval->nodeNr);
Daniel Veillard78d12092001-10-11 09:12:24 +00002773 } else
2774 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6825e82001-11-07 13:33:59 +00002775 "%s is an empty Node Set\n",
2776 arg);
Daniel Veillard78d12092001-10-11 09:12:24 +00002777 break;
2778 case XPATH_BOOLEAN:
2779 xmlGenericError(xmlGenericErrorContext,
2780 "%s is a Boolean\n", arg);
2781 break;
2782 case XPATH_NUMBER:
2783 xmlGenericError(xmlGenericErrorContext,
2784 "%s is a number\n", arg);
2785 break;
2786 case XPATH_STRING:
2787 xmlGenericError(xmlGenericErrorContext,
2788 "%s is a string\n", arg);
2789 break;
2790 case XPATH_POINT:
2791 xmlGenericError(xmlGenericErrorContext,
2792 "%s is a point\n", arg);
2793 break;
2794 case XPATH_RANGE:
2795 xmlGenericError(xmlGenericErrorContext,
2796 "%s is a range\n", arg);
2797 break;
2798 case XPATH_LOCATIONSET:
2799 xmlGenericError(xmlGenericErrorContext,
2800 "%s is a range\n", arg);
2801 break;
2802 case XPATH_USERS:
2803 xmlGenericError(xmlGenericErrorContext,
2804 "%s is user-defined\n", arg);
2805 break;
2806 case XPATH_XSLT_TREE:
2807 xmlGenericError(xmlGenericErrorContext,
2808 "%s is an XSLT value tree\n",
2809 arg);
2810 break;
2811 }
2812#ifdef LIBXML_XPATH_ENABLED
2813 xmlXPathFreeObject(list);
2814#endif
2815 } else {
2816 xmlGenericError(xmlGenericErrorContext,
2817 "%s: no such node\n", arg);
2818 }
2819 ctxt->pctxt->node = NULL;
2820 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002821#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002822 } else if (!strcmp(command, "cat")) {
2823 if (arg[0] == 0) {
2824 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
2825 } else {
2826 ctxt->pctxt->node = ctxt->node;
2827#ifdef LIBXML_XPATH_ENABLED
2828 ctxt->pctxt->node = ctxt->node;
2829 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2830#else
2831 list = NULL;
2832#endif /* LIBXML_XPATH_ENABLED */
2833 if (list != NULL) {
2834 switch (list->type) {
2835 case XPATH_UNDEFINED:
2836 xmlGenericError(xmlGenericErrorContext,
2837 "%s: no such node\n", arg);
2838 break;
2839 case XPATH_NODESET:{
2840 int indx;
2841
Daniel Veillarda6825e82001-11-07 13:33:59 +00002842 if (list->nodesetval == NULL)
2843 break;
2844
Daniel Veillard78d12092001-10-11 09:12:24 +00002845 for (indx = 0;
2846 indx < list->nodesetval->nodeNr;
2847 indx++) {
2848 if (i > 0)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002849 fprintf(ctxt->output, " -------\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002850 xmlShellCat(ctxt, NULL,
2851 list->nodesetval->
2852 nodeTab[indx], NULL);
2853 }
2854 break;
2855 }
2856 case XPATH_BOOLEAN:
2857 xmlGenericError(xmlGenericErrorContext,
2858 "%s is a Boolean\n", arg);
2859 break;
2860 case XPATH_NUMBER:
2861 xmlGenericError(xmlGenericErrorContext,
2862 "%s is a number\n", arg);
2863 break;
2864 case XPATH_STRING:
2865 xmlGenericError(xmlGenericErrorContext,
2866 "%s is a string\n", arg);
2867 break;
2868 case XPATH_POINT:
2869 xmlGenericError(xmlGenericErrorContext,
2870 "%s is a point\n", arg);
2871 break;
2872 case XPATH_RANGE:
2873 xmlGenericError(xmlGenericErrorContext,
2874 "%s is a range\n", arg);
2875 break;
2876 case XPATH_LOCATIONSET:
2877 xmlGenericError(xmlGenericErrorContext,
2878 "%s is a range\n", arg);
2879 break;
2880 case XPATH_USERS:
2881 xmlGenericError(xmlGenericErrorContext,
2882 "%s is user-defined\n", arg);
2883 break;
2884 case XPATH_XSLT_TREE:
2885 xmlGenericError(xmlGenericErrorContext,
2886 "%s is an XSLT value tree\n",
2887 arg);
2888 break;
2889 }
2890#ifdef LIBXML_XPATH_ENABLED
2891 xmlXPathFreeObject(list);
2892#endif
2893 } else {
2894 xmlGenericError(xmlGenericErrorContext,
2895 "%s: no such node\n", arg);
2896 }
2897 ctxt->pctxt->node = NULL;
2898 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002899#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002900 } else {
2901 xmlGenericError(xmlGenericErrorContext,
2902 "Unknown command %s\n", command);
2903 }
2904 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00002905 }
2906#ifdef LIBXML_XPATH_ENABLED
2907 xmlXPathFreeContext(ctxt->pctxt);
2908#endif /* LIBXML_XPATH_ENABLED */
2909 if (ctxt->loaded) {
2910 xmlFreeDoc(ctxt->doc);
2911 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00002912 if (ctxt->filename != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002913 xmlFree(ctxt->filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002914 xmlFree(ctxt);
2915 if (cmdline != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002916 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00002917}
2918
2919#endif /* LIBXML_DEBUG_ENABLED */