blob: 08364e39e0be5d37c290f30ea71230484546d549 [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 Veillard76821142004-10-09 20:39:04 +000047 int nsNr; /* the number of inherited namespaces */
48 int nsMax; /* the size of the arrays */
49 xmlNsPtr *nsTab; /* the array of namespace nodes */
Daniel Veillard22cdb842004-10-04 14:09:17 +000050};
51
52static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
53
54static void
55xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
56{
57 int i;
58
59 ctxt->depth = 0;
Daniel Veillard76821142004-10-09 20:39:04 +000060 ctxt->nsNr = 0;
61 ctxt->nsMax = 0;
62 ctxt->nsTab = NULL;
Daniel Veillard22cdb842004-10-04 14:09:17 +000063 ctxt->check = 0;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +000064 ctxt->errors = 0;
Daniel Veillard22cdb842004-10-04 14:09:17 +000065 ctxt->output = stdout;
66 for (i = 0; i < 100; i++)
67 ctxt->shift[i] = ' ';
68 ctxt->shift[100] = 0;
69}
70
71static void
Daniel Veillard76821142004-10-09 20:39:04 +000072xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt)
73{
74 if (ctxt->nsTab != NULL)
75 xmlFree(ctxt->nsTab);
76}
77
78/**
79 * xmlNsCheckPush:
80 * @ctxt: an XML parser context
81 * @ns: the namespace node
82 *
83 * Pushes a new namespace on top of the ns stack
84 *
85 * Returns -1 in case of error, and the index in the stack otherwise.
86 */
87static int
88xmlNsCheckPush(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
89{
90 if (ns == NULL)
91 return(ctxt->nsNr);
92
93 if ((ctxt->nsMax == 0) || (ctxt->nsTab == NULL)) {
94 ctxt->nsMax = 10;
95 ctxt->nsNr = 0;
96 ctxt->nsTab = (xmlNsPtr *)
97 xmlMalloc(ctxt->nsMax * sizeof(ctxt->nsTab[0]));
98 if (ctxt->nsTab == NULL) {
99 xmlErrMemory(NULL, NULL);
100 ctxt->nsMax = 0;
101 return (-1);
102 }
103 } else if (ctxt->nsNr >= ctxt->nsMax) {
104 ctxt->nsMax *= 2;
105 ctxt->nsTab = (xmlNsPtr *)
106 xmlRealloc((char *) ctxt->nsTab,
107 ctxt->nsMax * sizeof(ctxt->nsTab[0]));
108 if (ctxt->nsTab == NULL) {
109 xmlErrMemory(NULL, NULL);
110 ctxt->nsMax /= 2;
111 return (-1);
112 }
113 }
114 ctxt->nsTab[ctxt->nsNr++] = ns;
115 return (ctxt->nsNr);
116}
117/**
118 * xmlNsCheckPop:
119 * @ctxt: an XML parser context
120 * @nr: the number to pop
121 *
122 * Pops the top @nr parser prefix/namespace from the ns stack
123 *
124 * Returns the number of namespaces removed
125 */
126static int
127xmlNsCheckPop(xmlDebugCtxtPtr ctxt, int nr)
128{
129 int i;
130
131 if (ctxt->nsTab == NULL) return(0);
132 if (ctxt->nsNr < nr) {
133 xmlGenericError(xmlGenericErrorContext, "Pbm popping %d NS\n", nr);
134 nr = ctxt->nsNr;
135 }
136 if (ctxt->nsNr <= 0)
137 return (0);
138
139 for (i = 0;i < nr;i++) {
140 ctxt->nsNr--;
141 ctxt->nsTab[ctxt->nsNr] = NULL;
142 }
143 return(nr);
144}
145static void
Daniel Veillard22cdb842004-10-04 14:09:17 +0000146xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
147{
148 if (ctxt->check)
149 return;
150 if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
151 if (ctxt->depth < 50)
152 fprintf(ctxt->output, &ctxt->shift[100 - 2 * ctxt->depth]);
153 else
154 fprintf(ctxt->output, ctxt->shift);
155 }
156}
157
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000158/**
159 * xmlDebugErr:
160 * @ctxt: a debug context
161 * @error: the error code
162 *
163 * Handle a debug error.
164 */
165static void
166xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
167{
168 ctxt->errors++;
169 __xmlRaiseError(NULL, NULL, NULL,
170 NULL, ctxt->node, XML_FROM_CHECK,
171 error, XML_ERR_ERROR, NULL, 0,
172 NULL, NULL, NULL, 0, 0,
173 msg);
174}
175static void
176xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra)
177{
178 ctxt->errors++;
179 __xmlRaiseError(NULL, NULL, NULL,
180 NULL, ctxt->node, XML_FROM_CHECK,
181 error, XML_ERR_ERROR, NULL, 0,
182 NULL, NULL, NULL, 0, 0,
183 msg, extra);
184}
185static void
186xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, char *extra)
187{
188 ctxt->errors++;
189 __xmlRaiseError(NULL, NULL, NULL,
190 NULL, ctxt->node, XML_FROM_CHECK,
191 error, XML_ERR_ERROR, NULL, 0,
192 NULL, NULL, NULL, 0, 0,
193 msg, extra);
194}
195
196static void
197xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
198 if (node->parent == NULL)
199 xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
200 "Node has no parent\n");
201 if (node->doc == NULL)
202 xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
203 "Node has no doc\n");
204 if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
205 (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
206 xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
207 "Node doc differs from parent's one\n");
208 if (node->prev == NULL) {
209 if (node->type == XML_ATTRIBUTE_NODE) {
210 if ((node->parent != NULL) &&
211 (node != (xmlNodePtr) node->parent->properties))
212 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
213 "Attr has no prev and not first of attr list\n");
214
215 } else if ((node->parent != NULL) && (node->parent->children != node))
216 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
217 "Node has no prev and not first of parent list\n");
218 } else {
219 if (node->prev->next != node)
220 xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
221 "Node prev->next : back link wrong\n");
222 }
223 if (node->next == NULL) {
224 if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
225 (node->parent->last != node))
226 xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
227 "Node has no next and not last of parent list\n");
228 } else {
229 if (node->next->prev != node)
230 xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
231 "Node next->prev : forward link wrong\n");
232 }
233}
234
Daniel Veillard22cdb842004-10-04 14:09:17 +0000235static void
236xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
237{
238 int i;
239
240 if (ctxt->check)
241 return;
242 /* TODO: check UTF8 content of the string */
243 if (str == NULL) {
244 fprintf(ctxt->output, "(NULL)");
245 return;
246 }
247 for (i = 0; i < 40; i++)
248 if (str[i] == 0)
249 return;
250 else if (IS_BLANK_CH(str[i]))
251 fputc(' ', ctxt->output);
252 else if (str[i] >= 0x80)
253 fprintf(ctxt->output, "#%X", str[i]);
254 else
255 fputc(str[i], ctxt->output);
256 fprintf(ctxt->output, "...");
257}
258
259static void
260xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
261{
262 xmlCtxtDumpSpaces(ctxt);
263
264 if (dtd == NULL) {
265 if (!ctxt->check)
266 fprintf(ctxt->output, "DTD node is NULL\n");
267 return;
268 }
269
270 if (dtd->type != XML_DTD_NODE) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000271 xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
272 "Node is not a DTD");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000273 return;
274 }
275 if (!ctxt->check) {
276 if (dtd->name != NULL)
277 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
278 else
279 fprintf(ctxt->output, "DTD");
280 if (dtd->ExternalID != NULL)
281 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
282 if (dtd->SystemID != NULL)
283 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
284 fprintf(ctxt->output, "\n");
285 }
286 /*
287 * Do a bit of checking
288 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000289 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000290}
291
292static void
293xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
294{
295 xmlCtxtDumpSpaces(ctxt);
296
297 if (attr == NULL) {
298 if (!ctxt->check)
299 fprintf(ctxt->output, "Attribute declaration is NULL\n");
300 return;
301 }
302 if (attr->type != XML_ATTRIBUTE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000303 xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
304 "Node is not an attribute declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000305 return;
306 }
307 if (attr->name != NULL) {
308 if (!ctxt->check)
309 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
310 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000311 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
312 "Node attribute declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000313 if (attr->elem != NULL) {
314 if (!ctxt->check)
315 fprintf(ctxt->output, " for %s", (char *) attr->elem);
316 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000317 xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
318 "Node attribute declaration has no element name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000319 if (!ctxt->check) {
320 switch (attr->atype) {
321 case XML_ATTRIBUTE_CDATA:
322 fprintf(ctxt->output, " CDATA");
323 break;
324 case XML_ATTRIBUTE_ID:
325 fprintf(ctxt->output, " ID");
326 break;
327 case XML_ATTRIBUTE_IDREF:
328 fprintf(ctxt->output, " IDREF");
329 break;
330 case XML_ATTRIBUTE_IDREFS:
331 fprintf(ctxt->output, " IDREFS");
332 break;
333 case XML_ATTRIBUTE_ENTITY:
334 fprintf(ctxt->output, " ENTITY");
335 break;
336 case XML_ATTRIBUTE_ENTITIES:
337 fprintf(ctxt->output, " ENTITIES");
338 break;
339 case XML_ATTRIBUTE_NMTOKEN:
340 fprintf(ctxt->output, " NMTOKEN");
341 break;
342 case XML_ATTRIBUTE_NMTOKENS:
343 fprintf(ctxt->output, " NMTOKENS");
344 break;
345 case XML_ATTRIBUTE_ENUMERATION:
346 fprintf(ctxt->output, " ENUMERATION");
347 break;
348 case XML_ATTRIBUTE_NOTATION:
349 fprintf(ctxt->output, " NOTATION ");
350 break;
351 }
352 if (attr->tree != NULL) {
353 int indx;
354 xmlEnumerationPtr cur = attr->tree;
355
356 for (indx = 0; indx < 5; indx++) {
357 if (indx != 0)
358 fprintf(ctxt->output, "|%s", (char *) cur->name);
359 else
360 fprintf(ctxt->output, " (%s", (char *) cur->name);
361 cur = cur->next;
362 if (cur == NULL)
363 break;
364 }
365 if (cur == NULL)
366 fprintf(ctxt->output, ")");
367 else
368 fprintf(ctxt->output, "...)");
369 }
370 switch (attr->def) {
371 case XML_ATTRIBUTE_NONE:
372 break;
373 case XML_ATTRIBUTE_REQUIRED:
374 fprintf(ctxt->output, " REQUIRED");
375 break;
376 case XML_ATTRIBUTE_IMPLIED:
377 fprintf(ctxt->output, " IMPLIED");
378 break;
379 case XML_ATTRIBUTE_FIXED:
380 fprintf(ctxt->output, " FIXED");
381 break;
382 }
383 if (attr->defaultValue != NULL) {
384 fprintf(ctxt->output, "\"");
385 xmlCtxtDumpString(ctxt, attr->defaultValue);
386 fprintf(ctxt->output, "\"");
387 }
388 fprintf(ctxt->output, "\n");
389 }
390
391 /*
392 * Do a bit of checking
393 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000394 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000395}
396
397static void
398xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
399{
400 xmlCtxtDumpSpaces(ctxt);
401
402 if (elem == NULL) {
403 if (!ctxt->check)
404 fprintf(ctxt->output, "Element declaration is NULL\n");
405 return;
406 }
407 if (elem->type != XML_ELEMENT_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000408 xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
409 "Node is not an element declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000410 return;
411 }
412 if (elem->name != NULL) {
413 if (!ctxt->check) {
414 fprintf(ctxt->output, "ELEMDECL(");
415 xmlCtxtDumpString(ctxt, elem->name);
416 fprintf(ctxt->output, ")");
417 }
418 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000419 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
420 "Element declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000421 if (!ctxt->check) {
422 switch (elem->etype) {
423 case XML_ELEMENT_TYPE_UNDEFINED:
424 fprintf(ctxt->output, ", UNDEFINED");
425 break;
426 case XML_ELEMENT_TYPE_EMPTY:
427 fprintf(ctxt->output, ", EMPTY");
428 break;
429 case XML_ELEMENT_TYPE_ANY:
430 fprintf(ctxt->output, ", ANY");
431 break;
432 case XML_ELEMENT_TYPE_MIXED:
433 fprintf(ctxt->output, ", MIXED ");
434 break;
435 case XML_ELEMENT_TYPE_ELEMENT:
436 fprintf(ctxt->output, ", MIXED ");
437 break;
438 }
439 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
440 char buf[5001];
441
442 buf[0] = 0;
443 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
444 buf[5000] = 0;
445 fprintf(ctxt->output, "%s", buf);
446 }
447 fprintf(ctxt->output, "\n");
448 }
449
450 /*
451 * Do a bit of checking
452 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000453 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000454}
455
456static void
457xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
458{
459 xmlCtxtDumpSpaces(ctxt);
460
461 if (ent == NULL) {
462 if (!ctxt->check)
463 fprintf(ctxt->output, "Entity declaration is NULL\n");
464 return;
465 }
466 if (ent->type != XML_ENTITY_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000467 xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
468 "Node is not an entity declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000469 return;
470 }
471 if (ent->name != NULL) {
472 if (!ctxt->check) {
473 fprintf(ctxt->output, "ENTITYDECL(");
474 xmlCtxtDumpString(ctxt, ent->name);
475 fprintf(ctxt->output, ")");
476 }
477 } else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000478 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
479 "Entity declaration has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000480 if (!ctxt->check) {
481 switch (ent->etype) {
482 case XML_INTERNAL_GENERAL_ENTITY:
483 fprintf(ctxt->output, ", internal\n");
484 break;
485 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
486 fprintf(ctxt->output, ", external parsed\n");
487 break;
488 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
489 fprintf(ctxt->output, ", unparsed\n");
490 break;
491 case XML_INTERNAL_PARAMETER_ENTITY:
492 fprintf(ctxt->output, ", parameter\n");
493 break;
494 case XML_EXTERNAL_PARAMETER_ENTITY:
495 fprintf(ctxt->output, ", external parameter\n");
496 break;
497 case XML_INTERNAL_PREDEFINED_ENTITY:
498 fprintf(ctxt->output, ", predefined\n");
499 break;
500 }
501 if (ent->ExternalID) {
502 xmlCtxtDumpSpaces(ctxt);
503 fprintf(ctxt->output, " ExternalID=%s\n",
504 (char *) ent->ExternalID);
505 }
506 if (ent->SystemID) {
507 xmlCtxtDumpSpaces(ctxt);
508 fprintf(ctxt->output, " SystemID=%s\n",
509 (char *) ent->SystemID);
510 }
511 if (ent->URI != NULL) {
512 xmlCtxtDumpSpaces(ctxt);
513 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
514 }
515 if (ent->content) {
516 xmlCtxtDumpSpaces(ctxt);
517 fprintf(ctxt->output, " content=");
518 xmlCtxtDumpString(ctxt, ent->content);
519 fprintf(ctxt->output, "\n");
520 }
521 }
522
523 /*
524 * Do a bit of checking
525 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000526 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000527}
528
529static void
530xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
531{
532 xmlCtxtDumpSpaces(ctxt);
533
534 if (ns == NULL) {
535 if (!ctxt->check)
536 fprintf(ctxt->output, "namespace node is NULL\n");
537 return;
538 }
539 if (ns->type != XML_NAMESPACE_DECL) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000540 xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
541 "Node is not a namespace declaration");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000542 return;
543 }
544 if (ns->href == NULL) {
545 if (ns->prefix != NULL)
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000546 xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
547 "Incomplete namespace %s href=NULL\n",
Daniel Veillard22cdb842004-10-04 14:09:17 +0000548 (char *) ns->prefix);
549 else
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000550 xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
551 "Incomplete default namespace href=NULL\n");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000552 } else {
553 if (!ctxt->check) {
554 if (ns->prefix != NULL)
555 fprintf(ctxt->output, "namespace %s href=",
556 (char *) ns->prefix);
557 else
558 fprintf(ctxt->output, "default namespace href=");
559
560 xmlCtxtDumpString(ctxt, ns->href);
561 fprintf(ctxt->output, "\n");
562 }
563 }
564}
565
566static void
567xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
568{
569 while (ns != NULL) {
570 xmlCtxtDumpNamespace(ctxt, ns);
571 ns = ns->next;
572 }
573}
574
575static void
576xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
577{
578 xmlCtxtDumpSpaces(ctxt);
579
580 if (ent == NULL) {
581 if (!ctxt->check)
582 fprintf(ctxt->output, "Entity is NULL\n");
583 return;
584 }
585 if (!ctxt->check) {
586 switch (ent->etype) {
587 case XML_INTERNAL_GENERAL_ENTITY:
588 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
589 break;
590 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
591 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
592 break;
593 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
594 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
595 break;
596 case XML_INTERNAL_PARAMETER_ENTITY:
597 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
598 break;
599 case XML_EXTERNAL_PARAMETER_ENTITY:
600 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
601 break;
602 default:
603 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
604 }
605 fprintf(ctxt->output, "%s\n", ent->name);
606 if (ent->ExternalID) {
607 xmlCtxtDumpSpaces(ctxt);
608 fprintf(ctxt->output, "ExternalID=%s\n",
609 (char *) ent->ExternalID);
610 }
611 if (ent->SystemID) {
612 xmlCtxtDumpSpaces(ctxt);
613 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
614 }
615 if (ent->URI) {
616 xmlCtxtDumpSpaces(ctxt);
617 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
618 }
619 if (ent->content) {
620 xmlCtxtDumpSpaces(ctxt);
621 fprintf(ctxt->output, "content=");
622 xmlCtxtDumpString(ctxt, ent->content);
623 fprintf(ctxt->output, "\n");
624 }
625 }
626}
627
628/**
629 * xmlCtxtDumpAttr:
630 * @output: the FILE * for the output
631 * @attr: the attribute
632 * @depth: the indentation level.
633 *
634 * Dumps debug information for the attribute
635 */
636static void
637xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
638{
639 xmlCtxtDumpSpaces(ctxt);
640
641 if (attr == NULL) {
642 if (!ctxt->check)
643 fprintf(ctxt->output, "Attr is NULL");
644 return;
645 }
646 if (!ctxt->check) {
647 fprintf(ctxt->output, "ATTRIBUTE ");
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000648 xmlCtxtDumpString(ctxt, attr->name);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000649 fprintf(ctxt->output, "\n");
650 if (attr->children != NULL) {
651 ctxt->depth++;
652 xmlCtxtDumpNodeList(ctxt, attr->children);
653 ctxt->depth--;
654 }
655 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000656 if (attr->name == NULL)
657 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
658 "Attribute has no name");
Daniel Veillard22cdb842004-10-04 14:09:17 +0000659
660 /*
661 * Do a bit of checking
662 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000663 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000664}
665
666/**
667 * xmlCtxtDumpAttrList:
668 * @output: the FILE * for the output
669 * @attr: the attribute list
670 * @depth: the indentation level.
671 *
672 * Dumps debug information for the attribute list
673 */
674static void
675xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
676{
677 while (attr != NULL) {
678 xmlCtxtDumpAttr(ctxt, attr);
679 attr = attr->next;
680 }
681}
682
683/**
684 * xmlCtxtDumpOneNode:
685 * @output: the FILE * for the output
686 * @node: the node
687 * @depth: the indentation level.
688 *
689 * Dumps debug information for the element node, it is not recursive
690 */
691static void
692xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
693{
694 if (node == NULL) {
695 if (!ctxt->check) {
696 xmlCtxtDumpSpaces(ctxt);
697 fprintf(ctxt->output, "node is NULL\n");
698 }
699 return;
700 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000701 ctxt->node = node;
702
Daniel Veillard22cdb842004-10-04 14:09:17 +0000703 switch (node->type) {
704 case XML_ELEMENT_NODE:
705 if (!ctxt->check) {
706 xmlCtxtDumpSpaces(ctxt);
707 fprintf(ctxt->output, "ELEMENT ");
708 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
709 xmlCtxtDumpString(ctxt, node->ns->prefix);
710 fprintf(ctxt->output, ":");
711 }
712 xmlCtxtDumpString(ctxt, node->name);
713 fprintf(ctxt->output, "\n");
714 }
715 break;
716 case XML_ATTRIBUTE_NODE:
717 if (!ctxt->check)
718 xmlCtxtDumpSpaces(ctxt);
719 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
720 break;
721 case XML_TEXT_NODE:
722 if (!ctxt->check) {
723 xmlCtxtDumpSpaces(ctxt);
724 if (node->name == (const xmlChar *) xmlStringTextNoenc)
725 fprintf(ctxt->output, "TEXT no enc\n");
726 else
727 fprintf(ctxt->output, "TEXT\n");
728 }
729 break;
730 case XML_CDATA_SECTION_NODE:
731 if (!ctxt->check) {
732 xmlCtxtDumpSpaces(ctxt);
733 fprintf(ctxt->output, "CDATA_SECTION\n");
734 }
735 break;
736 case XML_ENTITY_REF_NODE:
737 if (!ctxt->check) {
738 xmlCtxtDumpSpaces(ctxt);
739 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
740 (char *) node->name);
741 }
742 break;
743 case XML_ENTITY_NODE:
744 if (!ctxt->check) {
745 xmlCtxtDumpSpaces(ctxt);
746 fprintf(ctxt->output, "ENTITY\n");
747 }
748 break;
749 case XML_PI_NODE:
750 if (!ctxt->check) {
751 xmlCtxtDumpSpaces(ctxt);
752 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
753 }
754 break;
755 case XML_COMMENT_NODE:
756 if (!ctxt->check) {
757 xmlCtxtDumpSpaces(ctxt);
758 fprintf(ctxt->output, "COMMENT\n");
759 }
760 break;
761 case XML_DOCUMENT_NODE:
762 case XML_HTML_DOCUMENT_NODE:
763 if (!ctxt->check) {
764 xmlCtxtDumpSpaces(ctxt);
765 }
766 fprintf(ctxt->output, "PBM: DOCUMENT found here\n");
767 break;
768 case XML_DOCUMENT_TYPE_NODE:
769 if (!ctxt->check) {
770 xmlCtxtDumpSpaces(ctxt);
771 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
772 }
773 break;
774 case XML_DOCUMENT_FRAG_NODE:
775 if (!ctxt->check) {
776 xmlCtxtDumpSpaces(ctxt);
777 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
778 }
779 break;
780 case XML_NOTATION_NODE:
781 if (!ctxt->check) {
782 xmlCtxtDumpSpaces(ctxt);
783 fprintf(ctxt->output, "NOTATION\n");
784 }
785 break;
786 case XML_DTD_NODE:
787 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
788 return;
789 case XML_ELEMENT_DECL:
790 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
791 return;
792 case XML_ATTRIBUTE_DECL:
793 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
794 return;
795 case XML_ENTITY_DECL:
796 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
797 return;
798 case XML_NAMESPACE_DECL:
799 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
800 return;
801 case XML_XINCLUDE_START:
802 if (!ctxt->check) {
803 xmlCtxtDumpSpaces(ctxt);
804 fprintf(ctxt->output, "INCLUDE START\n");
805 }
806 return;
807 case XML_XINCLUDE_END:
808 if (!ctxt->check) {
809 xmlCtxtDumpSpaces(ctxt);
810 fprintf(ctxt->output, "INCLUDE END\n");
811 }
812 return;
813 default:
814 if (!ctxt->check)
815 xmlCtxtDumpSpaces(ctxt);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000816 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
817 "Unknown node type %d\n", node->type);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000818 return;
819 }
820 if (node->doc == NULL) {
821 if (!ctxt->check) {
822 xmlCtxtDumpSpaces(ctxt);
823 }
824 fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
825 }
826 ctxt->depth++;
827 if (node->nsDef != NULL)
828 xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
829 if (node->properties != NULL)
830 xmlCtxtDumpAttrList(ctxt, node->properties);
831 if (node->type != XML_ENTITY_REF_NODE) {
832 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
833 if (!ctxt->check) {
834 xmlCtxtDumpSpaces(ctxt);
835 fprintf(ctxt->output, "content=");
836 xmlCtxtDumpString(ctxt, node->content);
837 fprintf(ctxt->output, "\n");
838 }
839 }
840 } else {
841 xmlEntityPtr ent;
842
843 ent = xmlGetDocEntity(node->doc, node->name);
844 if (ent != NULL)
845 xmlCtxtDumpEntity(ctxt, ent);
846 }
847 ctxt->depth--;
848
849 /*
850 * Do a bit of checking
851 */
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000852 xmlCtxtGenericNodeCheck(ctxt, node);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000853}
854
855/**
856 * xmlCtxtDumpNode:
857 * @output: the FILE * for the output
858 * @node: the node
859 * @depth: the indentation level.
860 *
861 * Dumps debug information for the element node, it is recursive
862 */
863static void
864xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
865{
866 if (node == NULL) {
867 if (!ctxt->check) {
868 xmlCtxtDumpSpaces(ctxt);
869 fprintf(ctxt->output, "node is NULL\n");
870 }
871 return;
872 }
873 xmlCtxtDumpOneNode(ctxt, node);
874 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
875 ctxt->depth++;
876 xmlCtxtDumpNodeList(ctxt, node->children);
877 ctxt->depth--;
878 }
879}
880
881/**
882 * xmlCtxtDumpNodeList:
883 * @output: the FILE * for the output
884 * @node: the node list
885 * @depth: the indentation level.
886 *
887 * Dumps debug information for the list of element node, it is recursive
888 */
889static void
890xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
891{
892 while (node != NULL) {
893 xmlCtxtDumpNode(ctxt, node);
894 node = node->next;
895 }
896}
897
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000898static void
899xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
900{
901 if (doc == NULL) {
902 if (!ctxt->check)
903 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
904 return;
905 }
906 ctxt->node = (xmlNodePtr) doc;
907
908 switch (doc->type) {
909 case XML_ELEMENT_NODE:
910 xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
911 "Misplaced ELEMENT node\n");
912 break;
913 case XML_ATTRIBUTE_NODE:
914 xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
915 "Misplaced ATTRIBUTE node\n");
916 break;
917 case XML_TEXT_NODE:
918 xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
919 "Misplaced TEXT node\n");
920 break;
921 case XML_CDATA_SECTION_NODE:
922 xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
923 "Misplaced CDATA node\n");
924 break;
925 case XML_ENTITY_REF_NODE:
926 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
927 "Misplaced ENTITYREF node\n");
928 break;
929 case XML_ENTITY_NODE:
930 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
931 "Misplaced ENTITY node\n");
932 break;
933 case XML_PI_NODE:
934 xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
935 "Misplaced PI node\n");
936 break;
937 case XML_COMMENT_NODE:
938 xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
939 "Misplaced COMMENT node\n");
940 break;
941 case XML_DOCUMENT_NODE:
942 if (!ctxt->check)
943 fprintf(ctxt->output, "DOCUMENT\n");
944 break;
945 case XML_HTML_DOCUMENT_NODE:
946 if (!ctxt->check)
947 fprintf(ctxt->output, "HTML DOCUMENT\n");
948 break;
949 case XML_DOCUMENT_TYPE_NODE:
950 xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
951 "Misplaced DOCTYPE node\n");
952 break;
953 case XML_DOCUMENT_FRAG_NODE:
954 xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
955 "Misplaced FRAGMENT node\n");
956 break;
957 case XML_NOTATION_NODE:
958 xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
959 "Misplaced NOTATION node\n");
960 break;
961 default:
962 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
963 "Unknown node type %d\n", doc->type);
964 }
965}
Daniel Veillard22cdb842004-10-04 14:09:17 +0000966
967/**
968 * xmlCtxtDumpDocumentHead:
969 * @output: the FILE * for the output
970 * @doc: the document
971 *
972 * Dumps debug information cncerning the document, not recursive
973 */
974static void
975xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
976{
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000977 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +0000978 if (!ctxt->check) {
979 if (doc->name != NULL) {
980 fprintf(ctxt->output, "name=");
981 xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
982 fprintf(ctxt->output, "\n");
983 }
984 if (doc->version != NULL) {
985 fprintf(ctxt->output, "version=");
986 xmlCtxtDumpString(ctxt, doc->version);
987 fprintf(ctxt->output, "\n");
988 }
989 if (doc->encoding != NULL) {
990 fprintf(ctxt->output, "encoding=");
991 xmlCtxtDumpString(ctxt, doc->encoding);
992 fprintf(ctxt->output, "\n");
993 }
994 if (doc->URL != NULL) {
995 fprintf(ctxt->output, "URL=");
996 xmlCtxtDumpString(ctxt, doc->URL);
997 fprintf(ctxt->output, "\n");
998 }
999 if (doc->standalone)
1000 fprintf(ctxt->output, "standalone=true\n");
1001 }
1002 if (doc->oldNs != NULL)
1003 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
1004}
1005
1006/**
1007 * xmlCtxtDumpDocument:
1008 * @output: the FILE * for the output
1009 * @doc: the document
1010 *
1011 * Dumps debug information for the document, it's recursive
1012 */
1013static void
1014xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1015{
1016 if (doc == NULL) {
1017 if (!ctxt->check)
1018 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1019 return;
1020 }
1021 xmlCtxtDumpDocumentHead(ctxt, doc);
1022 if (((doc->type == XML_DOCUMENT_NODE) ||
1023 (doc->type == XML_HTML_DOCUMENT_NODE))
1024 && (doc->children != NULL)) {
1025 ctxt->depth++;
1026 xmlCtxtDumpNodeList(ctxt, doc->children);
1027 ctxt->depth--;
1028 }
1029}
1030
1031static void
1032xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt)
1033{
1034 if (cur == NULL) {
1035 if (!ctxt->check)
1036 fprintf(ctxt->output, "Entity is NULL");
1037 return;
1038 }
1039 if (!ctxt->check) {
1040 fprintf(ctxt->output, "%s : ", (char *) cur->name);
1041 switch (cur->etype) {
1042 case XML_INTERNAL_GENERAL_ENTITY:
1043 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1044 break;
1045 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1046 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1047 break;
1048 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1049 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1050 break;
1051 case XML_INTERNAL_PARAMETER_ENTITY:
1052 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1053 break;
1054 case XML_EXTERNAL_PARAMETER_ENTITY:
1055 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1056 break;
1057 default:
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001058 xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1059 "Unknown entity type %d\n", cur->etype);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001060 }
1061 if (cur->ExternalID != NULL)
1062 fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1063 if (cur->SystemID != NULL)
1064 fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1065 if (cur->orig != NULL)
1066 fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1067 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1068 fprintf(ctxt->output, "\n content \"%s\"",
1069 (char *) cur->content);
1070 fprintf(ctxt->output, "\n");
1071 }
1072}
1073
1074/**
1075 * xmlCtxtDumpEntities:
1076 * @output: the FILE * for the output
1077 * @doc: the document
1078 *
1079 * Dumps debug information for all the entities in use by the document
1080 */
1081static void
1082xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1083{
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001084 xmlCtxtDumpDocHead(ctxt, doc);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001085 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1086 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1087 doc->intSubset->entities;
1088
1089 if (!ctxt->check)
1090 fprintf(ctxt->output, "Entities in internal subset\n");
1091 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1092 ctxt);
1093 } else
1094 fprintf(ctxt->output, "No entities in internal subset\n");
1095 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1096 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1097 doc->extSubset->entities;
1098
1099 if (!ctxt->check)
1100 fprintf(ctxt->output, "Entities in external subset\n");
1101 xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback,
1102 ctxt);
1103 } else if (!ctxt->check)
1104 fprintf(ctxt->output, "No entities in external subset\n");
1105}
1106
1107/**
1108 * xmlCtxtDumpDTD:
1109 * @output: the FILE * for the output
1110 * @dtd: the DTD
1111 *
1112 * Dumps debug information for the DTD
1113 */
1114static void
1115xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1116{
1117 if (dtd == NULL) {
1118 if (!ctxt->check)
1119 fprintf(ctxt->output, "DTD is NULL\n");
1120 return;
1121 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001122 xmlCtxtDumpDtdNode(ctxt, dtd);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001123 if (dtd->children == NULL)
1124 fprintf(ctxt->output, " DTD is empty\n");
1125 else {
1126 ctxt->depth++;
1127 xmlCtxtDumpNodeList(ctxt, dtd->children);
1128 ctxt->depth--;
1129 }
1130}
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001131
Daniel Veillard22cdb842004-10-04 14:09:17 +00001132/************************************************************************
1133 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001134 * Public entry points for dump *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001135 * *
1136 ************************************************************************/
1137
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001138/**
1139 * xmlDebugDumpString:
1140 * @output: the FILE * for the output
1141 * @str: the string
1142 *
1143 * Dumps informations about the string, shorten it if necessary
1144 */
1145void
1146xmlDebugDumpString(FILE * output, const xmlChar * str)
1147{
Owen Taylor3473f882001-02-23 17:55:21 +00001148 int i;
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001149
Daniel Veillard7db38712002-02-07 16:39:11 +00001150 if (output == NULL)
1151 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00001152 if (str == NULL) {
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001153 fprintf(output, "(NULL)");
1154 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001155 }
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001156 for (i = 0; i < 40; i++)
1157 if (str[i] == 0)
1158 return;
William M. Brack76e95df2003-10-18 16:20:14 +00001159 else if (IS_BLANK_CH(str[i]))
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001160 fputc(' ', output);
1161 else if (str[i] >= 0x80)
1162 fprintf(output, "#%X", str[i]);
1163 else
1164 fputc(str[i], output);
Owen Taylor3473f882001-02-23 17:55:21 +00001165 fprintf(output, "...");
1166}
1167
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001168/**
1169 * xmlDebugDumpAttr:
1170 * @output: the FILE * for the output
1171 * @attr: the attribute
1172 * @depth: the indentation level.
1173 *
1174 * Dumps debug information for the attribute
1175 */
1176void
1177xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
Daniel Veillard22cdb842004-10-04 14:09:17 +00001178 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001179
Daniel Veillard22cdb842004-10-04 14:09:17 +00001180 xmlCtxtDumpInitCtxt(&ctxt);
1181 ctxt.output = output;
1182 ctxt.depth = depth;
1183 xmlCtxtDumpAttr(&ctxt, attr);
Daniel Veillard76821142004-10-09 20:39:04 +00001184 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard22cdb842004-10-04 14:09:17 +00001185}
Owen Taylor3473f882001-02-23 17:55:21 +00001186
Owen Taylor3473f882001-02-23 17:55:21 +00001187
Daniel Veillard22cdb842004-10-04 14:09:17 +00001188/**
1189 * xmlDebugDumpEntities:
1190 * @output: the FILE * for the output
1191 * @doc: the document
1192 *
1193 * Dumps debug information for all the entities in use by the document
1194 */
1195void
1196xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1197{
1198 xmlDebugCtxt ctxt;
1199
1200 xmlCtxtDumpInitCtxt(&ctxt);
1201 ctxt.output = output;
1202 xmlCtxtDumpEntities(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001203 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001204}
1205
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001206/**
1207 * xmlDebugDumpAttrList:
1208 * @output: the FILE * for the output
1209 * @attr: the attribute list
1210 * @depth: the indentation level.
1211 *
1212 * Dumps debug information for the attribute list
1213 */
1214void
1215xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1216{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001217 xmlDebugCtxt ctxt;
1218
1219 xmlCtxtDumpInitCtxt(&ctxt);
1220 ctxt.output = output;
1221 ctxt.depth = depth;
1222 xmlCtxtDumpAttrList(&ctxt, attr);
Daniel Veillard76821142004-10-09 20:39:04 +00001223 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001224}
1225
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001226/**
1227 * xmlDebugDumpOneNode:
1228 * @output: the FILE * for the output
1229 * @node: the node
1230 * @depth: the indentation level.
1231 *
1232 * Dumps debug information for the element node, it is not recursive
1233 */
1234void
1235xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1236{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001237 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001238
Daniel Veillard22cdb842004-10-04 14:09:17 +00001239 xmlCtxtDumpInitCtxt(&ctxt);
1240 ctxt.output = output;
1241 ctxt.depth = depth;
1242 xmlCtxtDumpOneNode(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001243 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001244}
1245
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001246/**
1247 * xmlDebugDumpNode:
1248 * @output: the FILE * for the output
1249 * @node: the node
1250 * @depth: the indentation level.
1251 *
1252 * Dumps debug information for the element node, it is recursive
1253 */
1254void
1255xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1256{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001257 xmlDebugCtxt ctxt;
1258
Daniel Veillard7db38712002-02-07 16:39:11 +00001259 if (output == NULL)
1260 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001261 xmlCtxtDumpInitCtxt(&ctxt);
1262 ctxt.output = output;
1263 ctxt.depth = depth;
1264 xmlCtxtDumpNode(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001265 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001266}
1267
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001268/**
1269 * xmlDebugDumpNodeList:
1270 * @output: the FILE * for the output
1271 * @node: the node list
1272 * @depth: the indentation level.
1273 *
1274 * Dumps debug information for the list of element node, it is recursive
1275 */
1276void
1277xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1278{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001279 xmlDebugCtxt ctxt;
1280
Daniel Veillard7db38712002-02-07 16:39:11 +00001281 if (output == NULL)
1282 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001283 xmlCtxtDumpInitCtxt(&ctxt);
1284 ctxt.output = output;
1285 ctxt.depth = depth;
1286 xmlCtxtDumpNodeList(&ctxt, node);
Daniel Veillard76821142004-10-09 20:39:04 +00001287 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001288}
1289
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001290/**
1291 * xmlDebugDumpDocumentHead:
1292 * @output: the FILE * for the output
1293 * @doc: the document
1294 *
1295 * Dumps debug information cncerning the document, not recursive
1296 */
1297void
1298xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1299{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001300 xmlDebugCtxt ctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00001301
Daniel Veillard22cdb842004-10-04 14:09:17 +00001302 if (output == NULL)
1303 output = stdout;
1304 xmlCtxtDumpInitCtxt(&ctxt);
1305 ctxt.output = output;
1306 xmlCtxtDumpDocumentHead(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001307 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001308}
1309
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001310/**
1311 * xmlDebugDumpDocument:
1312 * @output: the FILE * for the output
1313 * @doc: the document
1314 *
1315 * Dumps debug information for the document, it's recursive
1316 */
1317void
1318xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1319{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001320 xmlDebugCtxt ctxt;
1321
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001322 if (output == NULL)
Daniel Veillard22cdb842004-10-04 14:09:17 +00001323 output = stdout;
1324 xmlCtxtDumpInitCtxt(&ctxt);
1325 ctxt.output = output;
1326 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001327 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001328}
Owen Taylor3473f882001-02-23 17:55:21 +00001329
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001330/**
1331 * xmlDebugDumpDTD:
1332 * @output: the FILE * for the output
1333 * @dtd: the DTD
1334 *
1335 * Dumps debug information for the DTD
1336 */
1337void
1338xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1339{
Daniel Veillard22cdb842004-10-04 14:09:17 +00001340 xmlDebugCtxt ctxt;
1341
Daniel Veillard7db38712002-02-07 16:39:11 +00001342 if (output == NULL)
1343 output = stdout;
Daniel Veillard22cdb842004-10-04 14:09:17 +00001344 xmlCtxtDumpInitCtxt(&ctxt);
1345 ctxt.output = output;
1346 xmlCtxtDumpDTD(&ctxt, dtd);
Daniel Veillard76821142004-10-09 20:39:04 +00001347 xmlCtxtDumpCleanCtxt(&ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00001348}
1349
Daniel Veillard22cdb842004-10-04 14:09:17 +00001350/************************************************************************
1351 * *
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001352 * Public entry points for checkings *
1353 * *
1354 ************************************************************************/
1355
1356/**
1357 * xmlDebugCheckDocument:
1358 * @output: the FILE * for the output
1359 * @doc: the document
1360 *
1361 * Check the document for potential content problems, and output
1362 * the errors to @output
1363 *
1364 * Returns the number of errors found
1365 */
1366int
1367xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1368{
1369 xmlDebugCtxt ctxt;
1370
1371 if (output == NULL)
1372 output = stdout;
1373 xmlCtxtDumpInitCtxt(&ctxt);
1374 ctxt.output = output;
1375 ctxt.check = 1;
1376 xmlCtxtDumpDocument(&ctxt, doc);
Daniel Veillard76821142004-10-09 20:39:04 +00001377 xmlCtxtDumpCleanCtxt(&ctxt);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001378 return(ctxt.errors);
1379}
1380
1381/************************************************************************
1382 * *
Daniel Veillard22cdb842004-10-04 14:09:17 +00001383 * Helpers for Shell *
1384 * *
1385 ************************************************************************/
Owen Taylor3473f882001-02-23 17:55:21 +00001386
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001387/**
1388 * xmlLsCountNode:
1389 * @node: the node to count
1390 *
1391 * Count the children of @node.
1392 *
1393 * Returns the number of children of @node.
1394 */
1395int
1396xmlLsCountNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001397 int ret = 0;
1398 xmlNodePtr list = NULL;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001399
1400 if (node == NULL)
1401 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001402
1403 switch (node->type) {
1404 case XML_ELEMENT_NODE:
1405 list = node->children;
1406 break;
1407 case XML_DOCUMENT_NODE:
1408 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00001409#ifdef LIBXML_DOCB_ENABLED
1410 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00001411#endif
1412 list = ((xmlDocPtr) node)->children;
1413 break;
1414 case XML_ATTRIBUTE_NODE:
1415 list = ((xmlAttrPtr) node)->children;
1416 break;
1417 case XML_TEXT_NODE:
1418 case XML_CDATA_SECTION_NODE:
1419 case XML_PI_NODE:
1420 case XML_COMMENT_NODE:
1421 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001422 ret = xmlStrlen(node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001423 }
1424 break;
1425 case XML_ENTITY_REF_NODE:
1426 case XML_DOCUMENT_TYPE_NODE:
1427 case XML_ENTITY_NODE:
1428 case XML_DOCUMENT_FRAG_NODE:
1429 case XML_NOTATION_NODE:
1430 case XML_DTD_NODE:
1431 case XML_ELEMENT_DECL:
1432 case XML_ATTRIBUTE_DECL:
1433 case XML_ENTITY_DECL:
1434 case XML_NAMESPACE_DECL:
1435 case XML_XINCLUDE_START:
1436 case XML_XINCLUDE_END:
1437 ret = 1;
1438 break;
1439 }
1440 for (;list != NULL;ret++)
1441 list = list->next;
1442 return(ret);
1443}
1444
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001445/**
1446 * xmlLsOneNode:
1447 * @output: the FILE * for the output
1448 * @node: the node to dump
1449 *
1450 * Dump to @output the type and name of @node.
1451 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001452void
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001453xmlLsOneNode(FILE *output, xmlNodePtr node) {
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001454 if (node == NULL) {
1455 fprintf(output, "NULL\n");
1456 return;
1457 }
Owen Taylor3473f882001-02-23 17:55:21 +00001458 switch (node->type) {
1459 case XML_ELEMENT_NODE:
1460 fprintf(output, "-");
1461 break;
1462 case XML_ATTRIBUTE_NODE:
1463 fprintf(output, "a");
1464 break;
1465 case XML_TEXT_NODE:
1466 fprintf(output, "t");
1467 break;
1468 case XML_CDATA_SECTION_NODE:
Daniel Veillard75be0132002-03-13 10:03:35 +00001469 fprintf(output, "C");
Owen Taylor3473f882001-02-23 17:55:21 +00001470 break;
1471 case XML_ENTITY_REF_NODE:
1472 fprintf(output, "e");
1473 break;
1474 case XML_ENTITY_NODE:
1475 fprintf(output, "E");
1476 break;
1477 case XML_PI_NODE:
1478 fprintf(output, "p");
1479 break;
1480 case XML_COMMENT_NODE:
1481 fprintf(output, "c");
1482 break;
1483 case XML_DOCUMENT_NODE:
1484 fprintf(output, "d");
1485 break;
1486 case XML_HTML_DOCUMENT_NODE:
1487 fprintf(output, "h");
1488 break;
1489 case XML_DOCUMENT_TYPE_NODE:
1490 fprintf(output, "T");
1491 break;
1492 case XML_DOCUMENT_FRAG_NODE:
1493 fprintf(output, "F");
1494 break;
1495 case XML_NOTATION_NODE:
1496 fprintf(output, "N");
1497 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001498 case XML_NAMESPACE_DECL:
1499 fprintf(output, "n");
1500 break;
Owen Taylor3473f882001-02-23 17:55:21 +00001501 default:
1502 fprintf(output, "?");
1503 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00001504 if (node->type != XML_NAMESPACE_DECL) {
1505 if (node->properties != NULL)
1506 fprintf(output, "a");
1507 else
1508 fprintf(output, "-");
1509 if (node->nsDef != NULL)
1510 fprintf(output, "n");
1511 else
1512 fprintf(output, "-");
1513 }
Owen Taylor3473f882001-02-23 17:55:21 +00001514
1515 fprintf(output, " %8d ", xmlLsCountNode(node));
1516
1517 switch (node->type) {
1518 case XML_ELEMENT_NODE:
1519 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001520 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001521 break;
1522 case XML_ATTRIBUTE_NODE:
1523 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001524 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001525 break;
1526 case XML_TEXT_NODE:
1527 if (node->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001528 xmlDebugDumpString(output, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001529 }
1530 break;
1531 case XML_CDATA_SECTION_NODE:
1532 break;
1533 case XML_ENTITY_REF_NODE:
1534 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001535 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 break;
1537 case XML_ENTITY_NODE:
1538 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001539 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001540 break;
1541 case XML_PI_NODE:
1542 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001543 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001544 break;
1545 case XML_COMMENT_NODE:
1546 break;
1547 case XML_DOCUMENT_NODE:
1548 break;
1549 case XML_HTML_DOCUMENT_NODE:
1550 break;
1551 case XML_DOCUMENT_TYPE_NODE:
1552 break;
1553 case XML_DOCUMENT_FRAG_NODE:
1554 break;
1555 case XML_NOTATION_NODE:
1556 break;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001557 case XML_NAMESPACE_DECL: {
1558 xmlNsPtr ns = (xmlNsPtr) node;
1559
1560 if (ns->prefix == NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00001561 fprintf(output, "default -> %s", (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001562 else
William M. Brack13dfa872004-09-18 04:52:08 +00001563 fprintf(output, "%s -> %s", (char *)ns->prefix,
1564 (char *)ns->href);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001565 break;
1566 }
Owen Taylor3473f882001-02-23 17:55:21 +00001567 default:
1568 if (node->name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001569 fprintf(output, "%s", (const char *) node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001570 }
1571 fprintf(output, "\n");
1572}
1573
Daniel Veillard78d12092001-10-11 09:12:24 +00001574/**
1575 * xmlBoolToText:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001576 * @boolval: a bool to turn into text
Daniel Veillard78d12092001-10-11 09:12:24 +00001577 *
1578 * Convenient way to turn bool into text
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001579 *
1580 * Returns a pointer to either "True" or "False"
1581 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001582const char *
Daniel Veillardebd38c52001-11-01 08:38:12 +00001583xmlBoolToText(int boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001584{
Daniel Veillardebd38c52001-11-01 08:38:12 +00001585 if (boolval)
Daniel Veillard78d12092001-10-11 09:12:24 +00001586 return("True");
1587 else
1588 return("False");
1589}
1590
Owen Taylor3473f882001-02-23 17:55:21 +00001591/****************************************************************
1592 * *
1593 * The XML shell related functions *
1594 * *
1595 ****************************************************************/
1596
Daniel Veillard78d12092001-10-11 09:12:24 +00001597
1598
Owen Taylor3473f882001-02-23 17:55:21 +00001599/*
1600 * TODO: Improvement/cleanups for the XML shell
1601 * - allow to shell out an editor on a subpart
1602 * - cleanup function registrations (with help) and calling
1603 * - provide registration routines
1604 */
1605
1606/**
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001607 * xmlShellPrintXPathError:
Daniel Veillard78d12092001-10-11 09:12:24 +00001608 * @errorType: valid xpath error id
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001609 * @arg: the argument that cause xpath to fail
Daniel Veillard78d12092001-10-11 09:12:24 +00001610 *
1611 * Print the xpath error to libxml default error channel
1612 */
1613void
1614xmlShellPrintXPathError(int errorType, const char *arg)
1615{
1616 const char *default_arg = "Result";
1617
1618 if (!arg)
1619 arg = default_arg;
1620
1621 switch (errorType) {
1622 case XPATH_UNDEFINED:
1623 xmlGenericError(xmlGenericErrorContext,
1624 "%s: no such node\n", arg);
1625 break;
1626
1627 case XPATH_BOOLEAN:
1628 xmlGenericError(xmlGenericErrorContext,
1629 "%s is a Boolean\n", arg);
1630 break;
1631 case XPATH_NUMBER:
1632 xmlGenericError(xmlGenericErrorContext,
1633 "%s is a number\n", arg);
1634 break;
1635 case XPATH_STRING:
1636 xmlGenericError(xmlGenericErrorContext,
1637 "%s is a string\n", arg);
1638 break;
1639 case XPATH_POINT:
1640 xmlGenericError(xmlGenericErrorContext,
1641 "%s is a point\n", arg);
1642 break;
1643 case XPATH_RANGE:
1644 xmlGenericError(xmlGenericErrorContext,
1645 "%s is a range\n", arg);
1646 break;
1647 case XPATH_LOCATIONSET:
1648 xmlGenericError(xmlGenericErrorContext,
1649 "%s is a range\n", arg);
1650 break;
1651 case XPATH_USERS:
1652 xmlGenericError(xmlGenericErrorContext,
1653 "%s is user-defined\n", arg);
1654 break;
1655 case XPATH_XSLT_TREE:
1656 xmlGenericError(xmlGenericErrorContext,
1657 "%s is an XSLT value tree\n", arg);
1658 break;
1659 }
1660 xmlGenericError(xmlGenericErrorContext,
1661 "Try casting the result string function (xpath builtin)\n",
1662 arg);
1663}
1664
1665
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001666#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001667/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001668 * xmlShellPrintNodeCtxt:
1669 * @ctxt : a non-null shell context
1670 * @node : a non-null node to print to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001671 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001672 * Print node to the output FILE
1673 */
1674static void
1675xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node)
1676{
Daniel Veillard01992e02002-10-09 10:20:30 +00001677 FILE *fp;
1678
1679 if (!node)
Daniel Veillard321be0c2002-10-08 21:26:42 +00001680 return;
Daniel Veillard01992e02002-10-09 10:20:30 +00001681 if (ctxt == NULL)
1682 fp = stdout;
1683 else
1684 fp = ctxt->output;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001685
1686 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001687 xmlDocDump(fp, (xmlDocPtr) node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001688 else if (node->type == XML_ATTRIBUTE_NODE)
Daniel Veillard01992e02002-10-09 10:20:30 +00001689 xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001690 else
Daniel Veillard01992e02002-10-09 10:20:30 +00001691 xmlElemDump(fp, node->doc, node);
Daniel Veillard321be0c2002-10-08 21:26:42 +00001692
Daniel Veillard01992e02002-10-09 10:20:30 +00001693 fprintf(fp, "\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00001694}
1695
1696/**
1697 * xmlShellPrintNode:
1698 * @node : a non-null node to print to the output FILE
1699 *
1700 * Print node to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001701 */
1702void
1703xmlShellPrintNode(xmlNodePtr node)
1704{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001705 xmlShellPrintNodeCtxt(NULL, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001706}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001707#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001708
Daniel Veillard78d12092001-10-11 09:12:24 +00001709/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001710 * xmlShellPrintXPathResultCtxt:
1711 * @ctxt: a valid shell context
Daniel Veillard9d06d302002-01-22 18:15:52 +00001712 * @list: a valid result generated by an xpath evaluation
Daniel Veillard78d12092001-10-11 09:12:24 +00001713 *
Daniel Veillard321be0c2002-10-08 21:26:42 +00001714 * Prints result to the output FILE
Daniel Veillard78d12092001-10-11 09:12:24 +00001715 */
Daniel Veillard321be0c2002-10-08 21:26:42 +00001716static void
1717xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list)
Daniel Veillard78d12092001-10-11 09:12:24 +00001718{
Daniel Veillard321be0c2002-10-08 21:26:42 +00001719 if (!ctxt)
1720 return;
Daniel Veillard78d12092001-10-11 09:12:24 +00001721
1722 if (list != NULL) {
1723 switch (list->type) {
1724 case XPATH_NODESET:{
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001725#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00001726 int indx;
1727
1728 if (list->nodesetval) {
1729 for (indx = 0; indx < list->nodesetval->nodeNr;
1730 indx++) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001731 xmlShellPrintNodeCtxt(ctxt,
1732 list->nodesetval->nodeTab[indx]);
Daniel Veillard78d12092001-10-11 09:12:24 +00001733 }
1734 } else {
1735 xmlGenericError(xmlGenericErrorContext,
1736 "Empty node set\n");
1737 }
1738 break;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001739#else
1740 xmlGenericError(xmlGenericErrorContext,
1741 "Node set\n");
1742#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00001743 }
1744 case XPATH_BOOLEAN:
1745 xmlGenericError(xmlGenericErrorContext,
1746 "Is a Boolean:%s\n",
1747 xmlBoolToText(list->boolval));
1748 break;
1749 case XPATH_NUMBER:
1750 xmlGenericError(xmlGenericErrorContext,
1751 "Is a number:%0g\n", list->floatval);
1752 break;
1753 case XPATH_STRING:
1754 xmlGenericError(xmlGenericErrorContext,
1755 "Is a string:%s\n", list->stringval);
1756 break;
1757
1758 default:
1759 xmlShellPrintXPathError(list->type, NULL);
1760 }
1761 }
1762}
1763
1764/**
Daniel Veillard321be0c2002-10-08 21:26:42 +00001765 * xmlShellPrintXPathResult:
1766 * @list: a valid result generated by an xpath evaluation
1767 *
1768 * Prints result to the output FILE
1769 */
1770void
1771xmlShellPrintXPathResult(xmlXPathObjectPtr list)
1772{
1773 xmlShellPrintXPathResultCtxt(NULL, list);
1774}
1775
1776/**
Owen Taylor3473f882001-02-23 17:55:21 +00001777 * xmlShellList:
1778 * @ctxt: the shell context
1779 * @arg: unused
1780 * @node: a node
1781 * @node2: unused
1782 *
1783 * Implements the XML shell function "ls"
1784 * Does an Unix like listing of the given node (like a directory)
1785 *
1786 * Returns 0
1787 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001788int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001789xmlShellList(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001790 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1791 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1792{
Owen Taylor3473f882001-02-23 17:55:21 +00001793 xmlNodePtr cur;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001794 if (!ctxt)
1795 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001796 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001797 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001798 return (0);
1799 }
Owen Taylor3473f882001-02-23 17:55:21 +00001800 if ((node->type == XML_DOCUMENT_NODE) ||
1801 (node->type == XML_HTML_DOCUMENT_NODE)) {
1802 cur = ((xmlDocPtr) node)->children;
Daniel Veillarde6a55192002-01-14 17:11:53 +00001803 } else if (node->type == XML_NAMESPACE_DECL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001804 xmlLsOneNode(ctxt->output, node);
Daniel Veillarde6a55192002-01-14 17:11:53 +00001805 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001806 } else if (node->children != NULL) {
1807 cur = node->children;
1808 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001809 xmlLsOneNode(ctxt->output, node);
Daniel Veillard78d12092001-10-11 09:12:24 +00001810 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001811 }
1812 while (cur != NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001813 xmlLsOneNode(ctxt->output, cur);
Daniel Veillard78d12092001-10-11 09:12:24 +00001814 cur = cur->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001815 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001816 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001817}
1818
1819/**
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001820 * xmlShellBase:
1821 * @ctxt: the shell context
1822 * @arg: unused
1823 * @node: a node
1824 * @node2: unused
1825 *
1826 * Implements the XML shell function "base"
1827 * dumps the current XML base of the node
1828 *
1829 * Returns 0
1830 */
Daniel Veillard78d12092001-10-11 09:12:24 +00001831int
Daniel Veillard321be0c2002-10-08 21:26:42 +00001832xmlShellBase(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00001833 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1834 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1835{
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001836 xmlChar *base;
Daniel Veillard321be0c2002-10-08 21:26:42 +00001837 if (!ctxt)
1838 return 0;
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001839 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001840 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00001841 return (0);
1842 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001843
1844 base = xmlNodeGetBase(node->doc, node);
1845
1846 if (base == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001847 fprintf(ctxt->output, " No base found !!!\n");
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001848 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00001849 fprintf(ctxt->output, "%s\n", base);
Daniel Veillard78d12092001-10-11 09:12:24 +00001850 xmlFree(base);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001851 }
Daniel Veillard78d12092001-10-11 09:12:24 +00001852 return (0);
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001853}
1854
Daniel Veillardb34321c2004-03-04 17:09:47 +00001855#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb8c9be92001-07-09 16:01:19 +00001856/**
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001857 * xmlShellSetBase:
1858 * @ctxt: the shell context
1859 * @arg: the new base
1860 * @node: a node
1861 * @node2: unused
1862 *
1863 * Implements the XML shell function "setbase"
1864 * change the current XML base of the node
1865 *
1866 * Returns 0
1867 */
1868static int
1869xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1870 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
1871 xmlNodePtr node2 ATTRIBUTE_UNUSED)
1872{
1873 xmlNodeSetBase(node, (xmlChar*) arg);
1874 return (0);
1875}
Daniel Veillard2156d432004-03-04 15:59:36 +00001876#endif
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001877
Daniel Veillardbbaa9972004-06-16 14:08:33 +00001878#ifdef LIBXML_XPATH_ENABLED
1879/**
1880 * xmlShellRegisterNamespace:
1881 * @ctxt: the shell context
1882 * @arg: a string in prefix=nsuri format
1883 * @node: unused
1884 * @node2: unused
1885 *
1886 * Implements the XML shell function "setns"
1887 * register/unregister a prefix=namespace pair
1888 * on the XPath context
1889 *
1890 * Returns 0 on success and a negative value otherwise.
1891 */
1892static int
1893xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg,
1894 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1895{
1896 xmlChar* nsListDup;
1897 xmlChar* prefix;
1898 xmlChar* href;
1899 xmlChar* next;
1900
1901 nsListDup = xmlStrdup((xmlChar *) arg);
1902 next = nsListDup;
1903 while(next != NULL) {
1904 /* skip spaces */
1905 /*while((*next) == ' ') next++;*/
1906 if((*next) == '\0') break;
1907
1908 /* find prefix */
1909 prefix = next;
1910 next = (xmlChar*)xmlStrchr(next, '=');
1911 if(next == NULL) {
1912 fprintf(ctxt->output, "setns: prefix=[nsuri] required\n");
1913 xmlFree(nsListDup);
1914 return(-1);
1915 }
1916 *(next++) = '\0';
1917
1918 /* find href */
1919 href = next;
1920 next = (xmlChar*)xmlStrchr(next, ' ');
1921 if(next != NULL) {
1922 *(next++) = '\0';
1923 }
1924
1925 /* do register namespace */
1926 if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) {
1927 fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
1928 xmlFree(nsListDup);
1929 return(-1);
1930 }
1931 }
1932
1933 xmlFree(nsListDup);
1934 return(0);
1935}
1936#endif
1937
Daniel Veillardcfa0d812002-01-17 08:46:58 +00001938/**
Daniel Veillard1e208222002-10-22 14:25:25 +00001939 * xmlShellGrep:
1940 * @ctxt: the shell context
1941 * @arg: the string or regular expression to find
1942 * @node: a node
1943 * @node2: unused
1944 *
1945 * Implements the XML shell function "grep"
1946 * dumps informations about the node (namespace, attributes, content).
1947 *
1948 * Returns 0
1949 */
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001950static int
Daniel Veillard1e208222002-10-22 14:25:25 +00001951xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
1952 char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
1953{
1954 if (!ctxt)
1955 return (0);
1956 if (node == NULL)
1957 return (0);
1958 if (arg == NULL)
1959 return (0);
1960#ifdef LIBXML_REGEXP_ENABLED
1961 if ((xmlStrchr((xmlChar *) arg, '?')) ||
1962 (xmlStrchr((xmlChar *) arg, '*')) ||
1963 (xmlStrchr((xmlChar *) arg, '.')) ||
1964 (xmlStrchr((xmlChar *) arg, '['))) {
1965 }
1966#endif
1967 while (node != NULL) {
1968 if (node->type == XML_COMMENT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001969 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00001970
1971 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node));
1972 xmlShellList(ctxt, NULL, node, NULL);
1973 }
1974 } else if (node->type == XML_TEXT_NODE) {
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001975 if (xmlStrstr(node->content, (xmlChar *) arg)) {
Daniel Veillard1e208222002-10-22 14:25:25 +00001976
1977 fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent));
Daniel Veillarde645e8c2002-10-22 17:35:37 +00001978 xmlShellList(ctxt, NULL, node->parent, NULL);
Daniel Veillard1e208222002-10-22 14:25:25 +00001979 }
1980 }
1981
1982 /*
1983 * Browse the full subtree, deep first
1984 */
1985
1986 if ((node->type == XML_DOCUMENT_NODE) ||
1987 (node->type == XML_HTML_DOCUMENT_NODE)) {
1988 node = ((xmlDocPtr) node)->children;
1989 } else if ((node->children != NULL)
1990 && (node->type != XML_ENTITY_REF_NODE)) {
1991 /* deep first */
1992 node = node->children;
1993 } else if (node->next != NULL) {
1994 /* then siblings */
1995 node = node->next;
1996 } else {
1997 /* go up to parents->next if needed */
1998 while (node != NULL) {
1999 if (node->parent != NULL) {
2000 node = node->parent;
2001 }
2002 if (node->next != NULL) {
2003 node = node->next;
2004 break;
2005 }
2006 if (node->parent == NULL) {
2007 node = NULL;
2008 break;
2009 }
2010 }
2011 }
2012 }
2013 return (0);
2014}
2015
2016/**
Owen Taylor3473f882001-02-23 17:55:21 +00002017 * xmlShellDir:
2018 * @ctxt: the shell context
2019 * @arg: unused
2020 * @node: a node
2021 * @node2: unused
2022 *
2023 * Implements the XML shell function "dir"
2024 * dumps informations about the node (namespace, attributes, content).
2025 *
2026 * Returns 0
2027 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002028int
2029xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2030 char *arg ATTRIBUTE_UNUSED, xmlNodePtr node,
2031 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2032{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002033 if (!ctxt)
2034 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002035 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002036 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002037 return (0);
2038 }
Owen Taylor3473f882001-02-23 17:55:21 +00002039 if ((node->type == XML_DOCUMENT_NODE) ||
2040 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002041 xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node);
Owen Taylor3473f882001-02-23 17:55:21 +00002042 } else if (node->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002043 xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002044 } else {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002045 xmlDebugDumpOneNode(ctxt->output, node, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00002046 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002047 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002048}
2049
Daniel Veillard29b17482004-08-16 00:39:03 +00002050/**
2051 * xmlShellSetContent:
2052 * @ctxt: the shell context
2053 * @value: the content as a string
2054 * @node: a node
2055 * @node2: unused
2056 *
2057 * Implements the XML shell function "dir"
2058 * dumps informations about the node (namespace, attributes, content).
2059 *
2060 * Returns 0
2061 */
2062static int
2063xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED,
2064 char *value, xmlNodePtr node,
2065 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2066{
2067 xmlNodePtr results;
2068 xmlParserErrors ret;
2069
2070 if (!ctxt)
2071 return (0);
2072 if (node == NULL) {
2073 fprintf(ctxt->output, "NULL\n");
2074 return (0);
2075 }
2076 if (value == NULL) {
2077 fprintf(ctxt->output, "NULL\n");
2078 return (0);
2079 }
2080
2081 ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results);
2082 if (ret == XML_ERR_OK) {
2083 if (node->children != NULL) {
2084 xmlFreeNodeList(node->children);
2085 node->children = NULL;
2086 node->last = NULL;
2087 }
2088 xmlAddChildList(node, results);
2089 } else {
2090 fprintf(ctxt->output, "failed to parse content\n");
2091 }
2092 return (0);
2093}
2094
Daniel Veillard522bc602004-02-21 11:53:09 +00002095#ifdef LIBXML_SCHEMAS_ENABLED
2096/**
2097 * xmlShellRNGValidate:
2098 * @ctxt: the shell context
2099 * @schemas: the path to the Relax-NG schemas
2100 * @node: a node
2101 * @node2: unused
2102 *
2103 * Implements the XML shell function "relaxng"
2104 * validating the instance against a Relax-NG schemas
2105 *
2106 * Returns 0
2107 */
2108static int
2109xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas,
2110 xmlNodePtr node ATTRIBUTE_UNUSED,
2111 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2112{
2113 xmlRelaxNGPtr relaxngschemas;
2114 xmlRelaxNGParserCtxtPtr ctxt;
2115 xmlRelaxNGValidCtxtPtr vctxt;
2116 int ret;
2117
2118 ctxt = xmlRelaxNGNewParserCtxt(schemas);
2119 xmlRelaxNGSetParserErrors(ctxt,
2120 (xmlRelaxNGValidityErrorFunc) fprintf,
2121 (xmlRelaxNGValidityWarningFunc) fprintf,
2122 stderr);
2123 relaxngschemas = xmlRelaxNGParse(ctxt);
2124 xmlRelaxNGFreeParserCtxt(ctxt);
2125 if (relaxngschemas == NULL) {
2126 xmlGenericError(xmlGenericErrorContext,
2127 "Relax-NG schema %s failed to compile\n", schemas);
2128 return(-1);
2129 }
2130 vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2131 xmlRelaxNGSetValidErrors(vctxt,
2132 (xmlRelaxNGValidityErrorFunc) fprintf,
2133 (xmlRelaxNGValidityWarningFunc) fprintf,
2134 stderr);
2135 ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc);
2136 if (ret == 0) {
2137 fprintf(stderr, "%s validates\n", sctxt->filename);
2138 } else if (ret > 0) {
2139 fprintf(stderr, "%s fails to validate\n", sctxt->filename);
2140 } else {
2141 fprintf(stderr, "%s validation generated an internal error\n",
2142 sctxt->filename);
2143 }
2144 xmlRelaxNGFreeValidCtxt(vctxt);
2145 if (relaxngschemas != NULL)
2146 xmlRelaxNGFree(relaxngschemas);
2147 return(0);
2148}
2149#endif
2150
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002151#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002152/**
2153 * xmlShellCat:
2154 * @ctxt: the shell context
2155 * @arg: unused
2156 * @node: a node
2157 * @node2: unused
2158 *
2159 * Implements the XML shell function "cat"
2160 * dumps the serialization node content (XML or HTML).
2161 *
2162 * Returns 0
2163 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002164int
2165xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED,
2166 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2167{
Daniel Veillard321be0c2002-10-08 21:26:42 +00002168 if (!ctxt)
2169 return (0);
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002170 if (node == NULL) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002171 fprintf(ctxt->output, "NULL\n");
Daniel Veillard5e926fa2002-01-22 21:44:25 +00002172 return (0);
2173 }
Owen Taylor3473f882001-02-23 17:55:21 +00002174 if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
2175#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002176 if (node->type == XML_HTML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002177 htmlDocDump(ctxt->output, (htmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002178 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002179 htmlNodeDumpFile(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002180#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002181 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002182 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002183 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002184 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002185#endif /* LIBXML_HTML_ENABLED */
2186 } else {
Daniel Veillard78d12092001-10-11 09:12:24 +00002187 if (node->type == XML_DOCUMENT_NODE)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002188 xmlDocDump(ctxt->output, (xmlDocPtr) node);
Daniel Veillard78d12092001-10-11 09:12:24 +00002189 else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002190 xmlElemDump(ctxt->output, ctxt->doc, node);
Owen Taylor3473f882001-02-23 17:55:21 +00002191 }
Daniel Veillard321be0c2002-10-08 21:26:42 +00002192 fprintf(ctxt->output, "\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002193 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002194}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002195#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002196
2197/**
2198 * xmlShellLoad:
2199 * @ctxt: the shell context
2200 * @filename: the file name
2201 * @node: unused
2202 * @node2: unused
2203 *
2204 * Implements the XML shell function "load"
2205 * loads a new document specified by the filename
2206 *
2207 * Returns 0 or -1 if loading failed
2208 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002209int
2210xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename,
2211 xmlNodePtr node ATTRIBUTE_UNUSED,
2212 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2213{
Owen Taylor3473f882001-02-23 17:55:21 +00002214 xmlDocPtr doc;
2215 int html = 0;
2216
2217 if (ctxt->doc != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002218 html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00002219
2220 if (html) {
2221#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002222 doc = htmlParseFile(filename, NULL);
2223#else
Daniel Veillard321be0c2002-10-08 21:26:42 +00002224 fprintf(ctxt->output, "HTML support not compiled in\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002225 doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002226#endif /* LIBXML_HTML_ENABLED */
2227 } else {
Daniel Veillardebe25d42004-03-25 09:35:49 +00002228 doc = xmlReadFile(filename,NULL,0);
Owen Taylor3473f882001-02-23 17:55:21 +00002229 }
2230 if (doc != NULL) {
2231 if (ctxt->loaded == 1) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002232 xmlFreeDoc(ctxt->doc);
2233 }
2234 ctxt->loaded = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002235#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002236 xmlXPathFreeContext(ctxt->pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002237#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002238 xmlFree(ctxt->filename);
2239 ctxt->doc = doc;
2240 ctxt->node = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002241#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002242 ctxt->pctxt = xmlXPathNewContext(doc);
Owen Taylor3473f882001-02-23 17:55:21 +00002243#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard85095e22003-04-23 13:56:44 +00002244 ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename);
Owen Taylor3473f882001-02-23 17:55:21 +00002245 } else
Daniel Veillard78d12092001-10-11 09:12:24 +00002246 return (-1);
2247 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002248}
2249
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002250#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002251/**
2252 * xmlShellWrite:
2253 * @ctxt: the shell context
2254 * @filename: the file name
2255 * @node: a node in the tree
2256 * @node2: unused
2257 *
2258 * Implements the XML shell function "write"
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002259 * Write the current node to the filename, it saves the serialization
Owen Taylor3473f882001-02-23 17:55:21 +00002260 * of the subtree under the @node specified
2261 *
2262 * Returns 0 or -1 in case of error
2263 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002264int
Owen Taylor3473f882001-02-23 17:55:21 +00002265xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
Daniel Veillard78d12092001-10-11 09:12:24 +00002266 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2267{
Owen Taylor3473f882001-02-23 17:55:21 +00002268 if (node == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002269 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002270 if ((filename == NULL) || (filename[0] == 0)) {
2271 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002272 "Write command requires a filename argument\n");
2273 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002274 }
2275#ifdef W_OK
2276 if (access((char *) filename, W_OK)) {
2277 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002278 "Cannot write to %s\n", filename);
2279 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002280 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002281#endif
2282 switch (node->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002283 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002284 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2285 xmlGenericError(xmlGenericErrorContext,
2286 "Failed to write to %s\n", filename);
2287 return (-1);
2288 }
2289 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002290 case XML_HTML_DOCUMENT_NODE:
2291#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002292 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2293 xmlGenericError(xmlGenericErrorContext,
2294 "Failed to write to %s\n", filename);
2295 return (-1);
2296 }
Owen Taylor3473f882001-02-23 17:55:21 +00002297#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002298 if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
2299 xmlGenericError(xmlGenericErrorContext,
2300 "Failed to write to %s\n", filename);
2301 return (-1);
2302 }
Owen Taylor3473f882001-02-23 17:55:21 +00002303#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002304 break;
2305 default:{
2306 FILE *f;
Owen Taylor3473f882001-02-23 17:55:21 +00002307
Daniel Veillard78d12092001-10-11 09:12:24 +00002308 f = fopen((char *) filename, "w");
2309 if (f == NULL) {
2310 xmlGenericError(xmlGenericErrorContext,
2311 "Failed to write to %s\n", filename);
2312 return (-1);
2313 }
2314 xmlElemDump(f, ctxt->doc, node);
2315 fclose(f);
2316 }
Owen Taylor3473f882001-02-23 17:55:21 +00002317 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002318 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002319}
2320
2321/**
2322 * xmlShellSave:
2323 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002324 * @filename: the file name (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002325 * @node: unused
2326 * @node2: unused
2327 *
2328 * Implements the XML shell function "save"
2329 * Write the current document to the filename, or it's original name
2330 *
2331 * Returns 0 or -1 in case of error
2332 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002333int
2334xmlShellSave(xmlShellCtxtPtr ctxt, char *filename,
2335 xmlNodePtr node ATTRIBUTE_UNUSED,
2336 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2337{
Owen Taylor3473f882001-02-23 17:55:21 +00002338 if (ctxt->doc == NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00002339 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 if ((filename == NULL) || (filename[0] == 0))
2341 filename = ctxt->filename;
2342#ifdef W_OK
2343 if (access((char *) filename, W_OK)) {
2344 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard78d12092001-10-11 09:12:24 +00002345 "Cannot save to %s\n", filename);
2346 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002347 }
2348#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002349 switch (ctxt->doc->type) {
Owen Taylor3473f882001-02-23 17:55:21 +00002350 case XML_DOCUMENT_NODE:
Daniel Veillard78d12092001-10-11 09:12:24 +00002351 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2352 xmlGenericError(xmlGenericErrorContext,
2353 "Failed to save to %s\n", filename);
2354 }
2355 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002356 case XML_HTML_DOCUMENT_NODE:
2357#ifdef LIBXML_HTML_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002358 if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
2359 xmlGenericError(xmlGenericErrorContext,
2360 "Failed to save to %s\n", filename);
2361 }
Owen Taylor3473f882001-02-23 17:55:21 +00002362#else
Daniel Veillard78d12092001-10-11 09:12:24 +00002363 if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
2364 xmlGenericError(xmlGenericErrorContext,
2365 "Failed to save to %s\n", filename);
2366 }
Owen Taylor3473f882001-02-23 17:55:21 +00002367#endif /* LIBXML_HTML_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002368 break;
2369 default:
2370 xmlGenericError(xmlGenericErrorContext,
2371 "To save to subparts of a document use the 'write' command\n");
2372 return (-1);
2373
Owen Taylor3473f882001-02-23 17:55:21 +00002374 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002375 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002376}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002377#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002378
Daniel Veillardf54cd532004-02-25 11:52:31 +00002379#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002380/**
2381 * xmlShellValidate:
2382 * @ctxt: the shell context
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002383 * @dtd: the DTD URI (optional)
Owen Taylor3473f882001-02-23 17:55:21 +00002384 * @node: unused
2385 * @node2: unused
2386 *
2387 * Implements the XML shell function "validate"
2388 * Validate the document, if a DTD path is provided, then the validation
2389 * is done against the given DTD.
2390 *
2391 * Returns 0 or -1 in case of error
2392 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002393int
2394xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
2395 xmlNodePtr node ATTRIBUTE_UNUSED,
2396 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2397{
Owen Taylor3473f882001-02-23 17:55:21 +00002398 xmlValidCtxt vctxt;
2399 int res = -1;
2400
2401 vctxt.userData = stderr;
2402 vctxt.error = (xmlValidityErrorFunc) fprintf;
2403 vctxt.warning = (xmlValidityWarningFunc) fprintf;
2404
2405 if ((dtd == NULL) || (dtd[0] == 0)) {
2406 res = xmlValidateDocument(&vctxt, ctxt->doc);
2407 } else {
2408 xmlDtdPtr subset;
2409
Daniel Veillard78d12092001-10-11 09:12:24 +00002410 subset = xmlParseDTD(NULL, (xmlChar *) dtd);
2411 if (subset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002412 res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
2413
Daniel Veillard78d12092001-10-11 09:12:24 +00002414 xmlFreeDtd(subset);
2415 }
Owen Taylor3473f882001-02-23 17:55:21 +00002416 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002417 return (res);
Owen Taylor3473f882001-02-23 17:55:21 +00002418}
Daniel Veillardf54cd532004-02-25 11:52:31 +00002419#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002420
2421/**
2422 * xmlShellDu:
2423 * @ctxt: the shell context
2424 * @arg: unused
2425 * @tree: a node defining a subtree
2426 * @node2: unused
2427 *
2428 * Implements the XML shell function "du"
2429 * show the structure of the subtree under node @tree
2430 * If @tree is null, the command works on the current node.
2431 *
2432 * Returns 0 or -1 in case of error
2433 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002434int
Daniel Veillard321be0c2002-10-08 21:26:42 +00002435xmlShellDu(xmlShellCtxtPtr ctxt,
Daniel Veillard78d12092001-10-11 09:12:24 +00002436 char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree,
2437 xmlNodePtr node2 ATTRIBUTE_UNUSED)
2438{
Owen Taylor3473f882001-02-23 17:55:21 +00002439 xmlNodePtr node;
Daniel Veillard78d12092001-10-11 09:12:24 +00002440 int indent = 0, i;
Owen Taylor3473f882001-02-23 17:55:21 +00002441
Daniel Veillard321be0c2002-10-08 21:26:42 +00002442 if (!ctxt)
2443 return (-1);
2444
Daniel Veillard78d12092001-10-11 09:12:24 +00002445 if (tree == NULL)
2446 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002447 node = tree;
2448 while (node != NULL) {
2449 if ((node->type == XML_DOCUMENT_NODE) ||
2450 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002451 fprintf(ctxt->output, "/\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002452 } else if (node->type == XML_ELEMENT_NODE) {
2453 for (i = 0; i < indent; i++)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002454 fprintf(ctxt->output, " ");
2455 fprintf(ctxt->output, "%s\n", node->name);
Daniel Veillard78d12092001-10-11 09:12:24 +00002456 } else {
2457 }
Owen Taylor3473f882001-02-23 17:55:21 +00002458
Daniel Veillard78d12092001-10-11 09:12:24 +00002459 /*
2460 * Browse the full subtree, deep first
2461 */
Owen Taylor3473f882001-02-23 17:55:21 +00002462
2463 if ((node->type == XML_DOCUMENT_NODE) ||
2464 (node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002465 node = ((xmlDocPtr) node)->children;
2466 } else if ((node->children != NULL)
2467 && (node->type != XML_ENTITY_REF_NODE)) {
2468 /* deep first */
2469 node = node->children;
2470 indent++;
2471 } else if ((node != tree) && (node->next != NULL)) {
2472 /* then siblings */
2473 node = node->next;
2474 } else if (node != tree) {
2475 /* go up to parents->next if needed */
2476 while (node != tree) {
2477 if (node->parent != NULL) {
2478 node = node->parent;
2479 indent--;
2480 }
2481 if ((node != tree) && (node->next != NULL)) {
2482 node = node->next;
2483 break;
2484 }
2485 if (node->parent == NULL) {
2486 node = NULL;
2487 break;
2488 }
2489 if (node == tree) {
2490 node = NULL;
2491 break;
2492 }
2493 }
2494 /* exit condition */
2495 if (node == tree)
2496 node = NULL;
2497 } else
2498 node = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002499 }
Daniel Veillard78d12092001-10-11 09:12:24 +00002500 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002501}
2502
2503/**
2504 * xmlShellPwd:
2505 * @ctxt: the shell context
2506 * @buffer: the output buffer
Daniel Veillard9d06d302002-01-22 18:15:52 +00002507 * @node: a node
Owen Taylor3473f882001-02-23 17:55:21 +00002508 * @node2: unused
2509 *
2510 * Implements the XML shell function "pwd"
2511 * Show the full path from the root to the node, if needed building
2512 * thumblers when similar elements exists at a given ancestor level.
2513 * The output is compatible with XPath commands.
2514 *
2515 * Returns 0 or -1 in case of error
2516 */
Daniel Veillard78d12092001-10-11 09:12:24 +00002517int
2518xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer,
2519 xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED)
2520{
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002521 xmlChar *path;
Owen Taylor3473f882001-02-23 17:55:21 +00002522
Daniel Veillard78d12092001-10-11 09:12:24 +00002523 if (node == NULL)
2524 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002525
Daniel Veillardc6e013a2001-11-10 10:08:57 +00002526 path = xmlGetNodePath(node);
2527 if (path == NULL)
2528 return (-1);
2529
2530 /*
2531 * This test prevents buffer overflow, because this routine
2532 * is only called by xmlShell, in which the second argument is
2533 * 500 chars long.
2534 * It is a dirty hack before a cleaner solution is found.
2535 * Documentation should mention that the second argument must
2536 * be at least 500 chars long, and could be stripped if too long.
2537 */
2538 snprintf(buffer, 499, "%s", path);
2539 buffer[499] = '0';
2540 xmlFree(path);
2541
Daniel Veillard78d12092001-10-11 09:12:24 +00002542 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00002543}
2544
2545/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002546 * xmlShell:
Owen Taylor3473f882001-02-23 17:55:21 +00002547 * @doc: the initial document
2548 * @filename: the output buffer
2549 * @input: the line reading function
Daniel Veillard321be0c2002-10-08 21:26:42 +00002550 * @output: the output FILE*, defaults to stdout if NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002551 *
2552 * Implements the XML shell
2553 * This allow to load, validate, view, modify and save a document
2554 * using a environment similar to a UNIX commandline.
2555 */
2556void
2557xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
Daniel Veillard78d12092001-10-11 09:12:24 +00002558 FILE * output)
2559{
Owen Taylor3473f882001-02-23 17:55:21 +00002560 char prompt[500] = "/ > ";
2561 char *cmdline = NULL, *cur;
2562 int nbargs;
2563 char command[100];
2564 char arg[400];
2565 int i;
2566 xmlShellCtxtPtr ctxt;
2567 xmlXPathObjectPtr list;
2568
2569 if (doc == NULL)
2570 return;
2571 if (filename == NULL)
2572 return;
2573 if (input == NULL)
2574 return;
2575 if (output == NULL)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002576 output = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00002577 ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
Daniel Veillard78d12092001-10-11 09:12:24 +00002578 if (ctxt == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002579 return;
2580 ctxt->loaded = 0;
2581 ctxt->doc = doc;
2582 ctxt->input = input;
2583 ctxt->output = output;
2584 ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
Daniel Veillard78d12092001-10-11 09:12:24 +00002585 ctxt->node = (xmlNodePtr) ctxt->doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002586
2587#ifdef LIBXML_XPATH_ENABLED
2588 ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
2589 if (ctxt->pctxt == NULL) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002590 xmlFree(ctxt);
2591 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002592 }
2593#endif /* LIBXML_XPATH_ENABLED */
2594 while (1) {
2595 if (ctxt->node == (xmlNodePtr) ctxt->doc)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002596 snprintf(prompt, sizeof(prompt), "%s > ", "/");
Daniel Veillard7a985a12003-07-06 17:57:42 +00002597 else if ((ctxt->node != NULL) && (ctxt->node->name))
Daniel Veillard78d12092001-10-11 09:12:24 +00002598 snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002599 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002600 snprintf(prompt, sizeof(prompt), "? > ");
Owen Taylor3473f882001-02-23 17:55:21 +00002601 prompt[sizeof(prompt) - 1] = 0;
2602
Daniel Veillard78d12092001-10-11 09:12:24 +00002603 /*
2604 * Get a new command line
2605 */
Owen Taylor3473f882001-02-23 17:55:21 +00002606 cmdline = ctxt->input(prompt);
Daniel Veillard78d12092001-10-11 09:12:24 +00002607 if (cmdline == NULL)
2608 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002609
Daniel Veillard78d12092001-10-11 09:12:24 +00002610 /*
2611 * Parse the command itself
2612 */
2613 cur = cmdline;
2614 nbargs = 0;
2615 while ((*cur == ' ') || (*cur == '\t'))
2616 cur++;
2617 i = 0;
2618 while ((*cur != ' ') && (*cur != '\t') &&
2619 (*cur != '\n') && (*cur != '\r')) {
2620 if (*cur == 0)
2621 break;
2622 command[i++] = *cur++;
2623 }
2624 command[i] = 0;
2625 if (i == 0)
2626 continue;
2627 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002628
Daniel Veillard78d12092001-10-11 09:12:24 +00002629 /*
2630 * Parse the argument
2631 */
2632 while ((*cur == ' ') || (*cur == '\t'))
2633 cur++;
2634 i = 0;
2635 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
2636 if (*cur == 0)
2637 break;
2638 arg[i++] = *cur++;
2639 }
2640 arg[i] = 0;
2641 if (i != 0)
2642 nbargs++;
Owen Taylor3473f882001-02-23 17:55:21 +00002643
Daniel Veillard78d12092001-10-11 09:12:24 +00002644 /*
2645 * start interpreting the command
2646 */
Owen Taylor3473f882001-02-23 17:55:21 +00002647 if (!strcmp(command, "exit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002648 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002649 if (!strcmp(command, "quit"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002650 break;
Owen Taylor3473f882001-02-23 17:55:21 +00002651 if (!strcmp(command, "bye"))
Daniel Veillard78d12092001-10-11 09:12:24 +00002652 break;
Daniel Veillard5004f422001-11-08 13:53:05 +00002653 if (!strcmp(command, "help")) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002654 fprintf(ctxt->output, "\tbase display XML base of the node\n");
2655 fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n");
2656 fprintf(ctxt->output, "\tbye leave shell\n");
2657 fprintf(ctxt->output, "\tcat [node] display node or current node\n");
2658 fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n");
2659 fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n");
2660 fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n");
2661 fprintf(ctxt->output, "\texit leave shell\n");
2662 fprintf(ctxt->output, "\thelp display this help\n");
2663 fprintf(ctxt->output, "\tfree display memory usage\n");
2664 fprintf(ctxt->output, "\tload [name] load a new document with name\n");
2665 fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n");
Daniel Veillardc14c3892004-08-16 12:34:50 +00002666 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 +00002667#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002668 fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n");
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002669 fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n");
2670 fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n");
Daniel Veillard2070c482002-01-22 22:12:19 +00002671#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard321be0c2002-10-08 21:26:42 +00002672 fprintf(ctxt->output, "\tpwd display current working directory\n");
2673 fprintf(ctxt->output, "\tquit leave shell\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002674#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard321be0c2002-10-08 21:26:42 +00002675 fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n");
Daniel Veillard321be0c2002-10-08 21:26:42 +00002676 fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n");
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002677#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf54cd532004-02-25 11:52:31 +00002678#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002679 fprintf(ctxt->output, "\tvalidate check the document for errors\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002680#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard522bc602004-02-21 11:53:09 +00002681#ifdef LIBXML_SCHEMAS_ENABLED
2682 fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n");
2683#endif
Daniel Veillard1e208222002-10-22 14:25:25 +00002684 fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n");
Daniel Veillardf54cd532004-02-25 11:52:31 +00002685#ifdef LIBXML_VALID_ENABLED
Daniel Veillard5004f422001-11-08 13:53:05 +00002686 } else if (!strcmp(command, "validate")) {
Daniel Veillard78d12092001-10-11 09:12:24 +00002687 xmlShellValidate(ctxt, arg, NULL, NULL);
Daniel Veillardf54cd532004-02-25 11:52:31 +00002688#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002689 } else if (!strcmp(command, "load")) {
2690 xmlShellLoad(ctxt, arg, NULL, NULL);
Daniel Veillard522bc602004-02-21 11:53:09 +00002691#ifdef LIBXML_SCHEMAS_ENABLED
2692 } else if (!strcmp(command, "relaxng")) {
2693 xmlShellRNGValidate(ctxt, arg, NULL, NULL);
2694#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002695#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002696 } else if (!strcmp(command, "save")) {
2697 xmlShellSave(ctxt, arg, NULL, NULL);
2698 } else if (!strcmp(command, "write")) {
2699 xmlShellWrite(ctxt, arg, NULL, NULL);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002700#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard1e208222002-10-22 14:25:25 +00002701 } else if (!strcmp(command, "grep")) {
2702 xmlShellGrep(ctxt, arg, ctxt->node, NULL);
Daniel Veillard78d12092001-10-11 09:12:24 +00002703 } else if (!strcmp(command, "free")) {
2704 if (arg[0] == 0) {
Daniel Veillard321be0c2002-10-08 21:26:42 +00002705 xmlMemShow(ctxt->output, 0);
Daniel Veillard78d12092001-10-11 09:12:24 +00002706 } else {
2707 int len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002708
Daniel Veillard78d12092001-10-11 09:12:24 +00002709 sscanf(arg, "%d", &len);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002710 xmlMemShow(ctxt->output, len);
Daniel Veillard78d12092001-10-11 09:12:24 +00002711 }
2712 } else if (!strcmp(command, "pwd")) {
2713 char dir[500];
Owen Taylor3473f882001-02-23 17:55:21 +00002714
Daniel Veillard78d12092001-10-11 09:12:24 +00002715 if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
Daniel Veillard321be0c2002-10-08 21:26:42 +00002716 fprintf(ctxt->output, "%s\n", dir);
Daniel Veillard78d12092001-10-11 09:12:24 +00002717 } else if (!strcmp(command, "du")) {
2718 xmlShellDu(ctxt, NULL, ctxt->node, NULL);
2719 } else if (!strcmp(command, "base")) {
2720 xmlShellBase(ctxt, NULL, ctxt->node, NULL);
Daniel Veillard29b17482004-08-16 00:39:03 +00002721 } else if (!strcmp(command, "set")) {
2722 xmlShellSetContent(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2070c482002-01-22 22:12:19 +00002723#ifdef LIBXML_XPATH_ENABLED
Daniel Veillardbbaa9972004-06-16 14:08:33 +00002724 } else if (!strcmp(command, "setns")) {
2725 if (arg[0] == 0) {
2726 xmlGenericError(xmlGenericErrorContext,
2727 "setns: prefix=[nsuri] required\n");
2728 } else {
2729 xmlShellRegisterNamespace(ctxt, arg, NULL, NULL);
2730 }
Daniel Veillard2070c482002-01-22 22:12:19 +00002731 } else if (!strcmp(command, "xpath")) {
2732 if (arg[0] == 0) {
2733 xmlGenericError(xmlGenericErrorContext,
2734 "xpath: expression required\n");
2735 } else {
2736 ctxt->pctxt->node = ctxt->node;
2737 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
Daniel Veillard321be0c2002-10-08 21:26:42 +00002738 xmlXPathDebugDumpObject(ctxt->output, list, 0);
Daniel Veillard2070c482002-01-22 22:12:19 +00002739 xmlXPathFreeObject(list);
2740 }
2741#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard2156d432004-03-04 15:59:36 +00002742#ifdef LIBXML_TREE_ENABLED
Daniel Veillardcfa0d812002-01-17 08:46:58 +00002743 } else if (!strcmp(command, "setbase")) {
2744 xmlShellSetBase(ctxt, arg, ctxt->node, NULL);
Daniel Veillard2156d432004-03-04 15:59:36 +00002745#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002746 } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) {
2747 int dir = (!strcmp(command, "dir"));
2748
2749 if (arg[0] == 0) {
2750 if (dir)
2751 xmlShellDir(ctxt, NULL, ctxt->node, NULL);
2752 else
2753 xmlShellList(ctxt, NULL, ctxt->node, NULL);
2754 } else {
2755 ctxt->pctxt->node = ctxt->node;
Daniel Veillard61d80a22001-04-27 17:13:01 +00002756#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002757 ctxt->pctxt->node = ctxt->node;
2758 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2759#else
2760 list = NULL;
2761#endif /* LIBXML_XPATH_ENABLED */
2762 if (list != NULL) {
2763 switch (list->type) {
2764 case XPATH_UNDEFINED:
2765 xmlGenericError(xmlGenericErrorContext,
2766 "%s: no such node\n", arg);
2767 break;
2768 case XPATH_NODESET:{
2769 int indx;
2770
Daniel Veillarda6825e82001-11-07 13:33:59 +00002771 if (list->nodesetval == NULL)
2772 break;
2773
Daniel Veillard78d12092001-10-11 09:12:24 +00002774 for (indx = 0;
2775 indx < list->nodesetval->nodeNr;
2776 indx++) {
2777 if (dir)
2778 xmlShellDir(ctxt, NULL,
2779 list->nodesetval->
2780 nodeTab[indx], NULL);
2781 else
2782 xmlShellList(ctxt, NULL,
2783 list->nodesetval->
2784 nodeTab[indx], NULL);
2785 }
2786 break;
2787 }
2788 case XPATH_BOOLEAN:
2789 xmlGenericError(xmlGenericErrorContext,
2790 "%s is a Boolean\n", arg);
2791 break;
2792 case XPATH_NUMBER:
2793 xmlGenericError(xmlGenericErrorContext,
2794 "%s is a number\n", arg);
2795 break;
2796 case XPATH_STRING:
2797 xmlGenericError(xmlGenericErrorContext,
2798 "%s is a string\n", arg);
2799 break;
2800 case XPATH_POINT:
2801 xmlGenericError(xmlGenericErrorContext,
2802 "%s is a point\n", arg);
2803 break;
2804 case XPATH_RANGE:
2805 xmlGenericError(xmlGenericErrorContext,
2806 "%s is a range\n", arg);
2807 break;
2808 case XPATH_LOCATIONSET:
2809 xmlGenericError(xmlGenericErrorContext,
2810 "%s is a range\n", arg);
2811 break;
2812 case XPATH_USERS:
2813 xmlGenericError(xmlGenericErrorContext,
2814 "%s is user-defined\n", arg);
2815 break;
2816 case XPATH_XSLT_TREE:
2817 xmlGenericError(xmlGenericErrorContext,
2818 "%s is an XSLT value tree\n",
2819 arg);
2820 break;
2821 }
2822#ifdef LIBXML_XPATH_ENABLED
2823 xmlXPathFreeObject(list);
Daniel Veillard61d80a22001-04-27 17:13:01 +00002824#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00002825 } else {
2826 xmlGenericError(xmlGenericErrorContext,
2827 "%s: no such node\n", arg);
2828 }
2829 ctxt->pctxt->node = NULL;
2830 }
2831 } else if (!strcmp(command, "cd")) {
2832 if (arg[0] == 0) {
2833 ctxt->node = (xmlNodePtr) ctxt->doc;
2834 } else {
2835#ifdef LIBXML_XPATH_ENABLED
2836 ctxt->pctxt->node = ctxt->node;
2837 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2838#else
2839 list = NULL;
2840#endif /* LIBXML_XPATH_ENABLED */
2841 if (list != NULL) {
2842 switch (list->type) {
2843 case XPATH_UNDEFINED:
2844 xmlGenericError(xmlGenericErrorContext,
2845 "%s: no such node\n", arg);
2846 break;
2847 case XPATH_NODESET:
Daniel Veillarda6825e82001-11-07 13:33:59 +00002848 if (list->nodesetval != NULL) {
2849 if (list->nodesetval->nodeNr == 1) {
2850 ctxt->node = list->nodesetval->nodeTab[0];
Daniel Veillard7a985a12003-07-06 17:57:42 +00002851 if ((ctxt->node != NULL) &&
2852 (ctxt->node->type ==
2853 XML_NAMESPACE_DECL)) {
2854 xmlGenericError(xmlGenericErrorContext,
2855 "cannot cd to namespace\n");
2856 ctxt->node = NULL;
2857 }
Daniel Veillarda6825e82001-11-07 13:33:59 +00002858 } else
2859 xmlGenericError(xmlGenericErrorContext,
2860 "%s is a %d Node Set\n",
2861 arg,
2862 list->nodesetval->nodeNr);
Daniel Veillard78d12092001-10-11 09:12:24 +00002863 } else
2864 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6825e82001-11-07 13:33:59 +00002865 "%s is an empty Node Set\n",
2866 arg);
Daniel Veillard78d12092001-10-11 09:12:24 +00002867 break;
2868 case XPATH_BOOLEAN:
2869 xmlGenericError(xmlGenericErrorContext,
2870 "%s is a Boolean\n", arg);
2871 break;
2872 case XPATH_NUMBER:
2873 xmlGenericError(xmlGenericErrorContext,
2874 "%s is a number\n", arg);
2875 break;
2876 case XPATH_STRING:
2877 xmlGenericError(xmlGenericErrorContext,
2878 "%s is a string\n", arg);
2879 break;
2880 case XPATH_POINT:
2881 xmlGenericError(xmlGenericErrorContext,
2882 "%s is a point\n", arg);
2883 break;
2884 case XPATH_RANGE:
2885 xmlGenericError(xmlGenericErrorContext,
2886 "%s is a range\n", arg);
2887 break;
2888 case XPATH_LOCATIONSET:
2889 xmlGenericError(xmlGenericErrorContext,
2890 "%s is a range\n", arg);
2891 break;
2892 case XPATH_USERS:
2893 xmlGenericError(xmlGenericErrorContext,
2894 "%s is user-defined\n", arg);
2895 break;
2896 case XPATH_XSLT_TREE:
2897 xmlGenericError(xmlGenericErrorContext,
2898 "%s is an XSLT value tree\n",
2899 arg);
2900 break;
2901 }
2902#ifdef LIBXML_XPATH_ENABLED
2903 xmlXPathFreeObject(list);
2904#endif
2905 } else {
2906 xmlGenericError(xmlGenericErrorContext,
2907 "%s: no such node\n", arg);
2908 }
2909 ctxt->pctxt->node = NULL;
2910 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002911#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard78d12092001-10-11 09:12:24 +00002912 } else if (!strcmp(command, "cat")) {
2913 if (arg[0] == 0) {
2914 xmlShellCat(ctxt, NULL, ctxt->node, NULL);
2915 } else {
2916 ctxt->pctxt->node = ctxt->node;
2917#ifdef LIBXML_XPATH_ENABLED
2918 ctxt->pctxt->node = ctxt->node;
2919 list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
2920#else
2921 list = NULL;
2922#endif /* LIBXML_XPATH_ENABLED */
2923 if (list != NULL) {
2924 switch (list->type) {
2925 case XPATH_UNDEFINED:
2926 xmlGenericError(xmlGenericErrorContext,
2927 "%s: no such node\n", arg);
2928 break;
2929 case XPATH_NODESET:{
2930 int indx;
2931
Daniel Veillarda6825e82001-11-07 13:33:59 +00002932 if (list->nodesetval == NULL)
2933 break;
2934
Daniel Veillard78d12092001-10-11 09:12:24 +00002935 for (indx = 0;
2936 indx < list->nodesetval->nodeNr;
2937 indx++) {
2938 if (i > 0)
Daniel Veillard321be0c2002-10-08 21:26:42 +00002939 fprintf(ctxt->output, " -------\n");
Daniel Veillard78d12092001-10-11 09:12:24 +00002940 xmlShellCat(ctxt, NULL,
2941 list->nodesetval->
2942 nodeTab[indx], NULL);
2943 }
2944 break;
2945 }
2946 case XPATH_BOOLEAN:
2947 xmlGenericError(xmlGenericErrorContext,
2948 "%s is a Boolean\n", arg);
2949 break;
2950 case XPATH_NUMBER:
2951 xmlGenericError(xmlGenericErrorContext,
2952 "%s is a number\n", arg);
2953 break;
2954 case XPATH_STRING:
2955 xmlGenericError(xmlGenericErrorContext,
2956 "%s is a string\n", arg);
2957 break;
2958 case XPATH_POINT:
2959 xmlGenericError(xmlGenericErrorContext,
2960 "%s is a point\n", arg);
2961 break;
2962 case XPATH_RANGE:
2963 xmlGenericError(xmlGenericErrorContext,
2964 "%s is a range\n", arg);
2965 break;
2966 case XPATH_LOCATIONSET:
2967 xmlGenericError(xmlGenericErrorContext,
2968 "%s is a range\n", arg);
2969 break;
2970 case XPATH_USERS:
2971 xmlGenericError(xmlGenericErrorContext,
2972 "%s is user-defined\n", arg);
2973 break;
2974 case XPATH_XSLT_TREE:
2975 xmlGenericError(xmlGenericErrorContext,
2976 "%s is an XSLT value tree\n",
2977 arg);
2978 break;
2979 }
2980#ifdef LIBXML_XPATH_ENABLED
2981 xmlXPathFreeObject(list);
2982#endif
2983 } else {
2984 xmlGenericError(xmlGenericErrorContext,
2985 "%s: no such node\n", arg);
2986 }
2987 ctxt->pctxt->node = NULL;
2988 }
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002989#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard78d12092001-10-11 09:12:24 +00002990 } else {
2991 xmlGenericError(xmlGenericErrorContext,
2992 "Unknown command %s\n", command);
2993 }
2994 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00002995 }
2996#ifdef LIBXML_XPATH_ENABLED
2997 xmlXPathFreeContext(ctxt->pctxt);
2998#endif /* LIBXML_XPATH_ENABLED */
2999 if (ctxt->loaded) {
3000 xmlFreeDoc(ctxt->doc);
3001 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003002 if (ctxt->filename != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00003003 xmlFree(ctxt->filename);
Owen Taylor3473f882001-02-23 17:55:21 +00003004 xmlFree(ctxt);
3005 if (cmdline != NULL)
Daniel Veillard78d12092001-10-11 09:12:24 +00003006 free(cmdline); /* not xmlFree here ! */
Owen Taylor3473f882001-02-23 17:55:21 +00003007}
3008
3009#endif /* LIBXML_DEBUG_ENABLED */