1 /*
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 *
7 * Daniel Veillard <daniel@veillard.com>
8 */
9
10 #define IN_LIBXML
11 #include "libxml.h"
12 #ifdef LIBXML_DEBUG_ENABLED
13
14 #include <string.h>
15 #include <stdlib.h>
16
17 #include <libxml/debugXML.h>
18 #include <libxml/xmlmemory.h>
19 #include <libxml/tree.h>
20 #include <libxml/parser.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/HTMLtree.h>
23 #include <libxml/HTMLparser.h>
24 #include <libxml/xmlerror.h>
25
26 #include "private/error.h"
27 #include "private/parser.h"
28
29 #define DUMP_TEXT_TYPE 1
30
31 typedef struct _xmlDebugCtxt xmlDebugCtxt;
32 typedef xmlDebugCtxt *xmlDebugCtxtPtr;
33 struct _xmlDebugCtxt {
34 FILE *output; /* the output file */
35 char shift[101]; /* used for indenting */
36 int depth; /* current depth */
37 xmlDocPtr doc; /* current document */
38 xmlNodePtr node; /* current node */
39 xmlDictPtr dict; /* the doc dictionary */
40 int check; /* do just checkings */
41 int errors; /* number of errors found */
42 int nodict; /* if the document has no dictionary */
43 int options; /* options */
44 };
45
46 static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
47
48 static void
xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)49 xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
50 {
51 int i;
52
53 ctxt->depth = 0;
54 ctxt->check = 0;
55 ctxt->errors = 0;
56 ctxt->output = stdout;
57 ctxt->doc = NULL;
58 ctxt->node = NULL;
59 ctxt->dict = NULL;
60 ctxt->nodict = 0;
61 ctxt->options = 0;
62 for (i = 0; i < 100; i++)
63 ctxt->shift[i] = ' ';
64 ctxt->shift[100] = 0;
65 }
66
67 static void
xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)68 xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)
69 {
70 /* remove the ATTRIBUTE_UNUSED when this is added */
71 }
72
73 /**
74 * xmlNsCheckScope:
75 * @node: the node
76 * @ns: the namespace node
77 *
78 * Check that a given namespace is in scope on a node.
79 *
80 * Returns 1 if in scope, -1 in case of argument error,
81 * -2 if the namespace is not in scope, and -3 if not on
82 * an ancestor node.
83 */
84 static int
xmlNsCheckScope(xmlNodePtr node,xmlNsPtr ns)85 xmlNsCheckScope(xmlNodePtr node, xmlNsPtr ns)
86 {
87 xmlNsPtr cur;
88
89 if ((node == NULL) || (ns == NULL))
90 return(-1);
91
92 if ((node->type != XML_ELEMENT_NODE) &&
93 (node->type != XML_ATTRIBUTE_NODE) &&
94 (node->type != XML_DOCUMENT_NODE) &&
95 (node->type != XML_TEXT_NODE) &&
96 (node->type != XML_HTML_DOCUMENT_NODE) &&
97 (node->type != XML_XINCLUDE_START))
98 return(-2);
99
100 while ((node != NULL) &&
101 ((node->type == XML_ELEMENT_NODE) ||
102 (node->type == XML_ATTRIBUTE_NODE) ||
103 (node->type == XML_TEXT_NODE) ||
104 (node->type == XML_XINCLUDE_START))) {
105 if ((node->type == XML_ELEMENT_NODE) ||
106 (node->type == XML_XINCLUDE_START)) {
107 cur = node->nsDef;
108 while (cur != NULL) {
109 if (cur == ns)
110 return(1);
111 if (xmlStrEqual(cur->prefix, ns->prefix))
112 return(-2);
113 cur = cur->next;
114 }
115 }
116 node = node->parent;
117 }
118 /* the xml namespace may be declared on the document node */
119 if ((node != NULL) &&
120 ((node->type == XML_DOCUMENT_NODE) ||
121 (node->type == XML_HTML_DOCUMENT_NODE))) {
122 xmlNsPtr oldNs = ((xmlDocPtr) node)->oldNs;
123 if (oldNs == ns)
124 return(1);
125 }
126 return(-3);
127 }
128
129 static void
xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)130 xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
131 {
132 if (ctxt->check)
133 return;
134 if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
135 if (ctxt->depth < 50)
136 fprintf(ctxt->output, "%s", &ctxt->shift[100 - 2 * ctxt->depth]);
137 else
138 fprintf(ctxt->output, "%s", ctxt->shift);
139 }
140 }
141
142 /**
143 * xmlDebugErr:
144 * @ctxt: a debug context
145 * @error: the error code
146 *
147 * Handle a debug error.
148 */
149 static void
xmlDebugErr(xmlDebugCtxtPtr ctxt,int error,const char * msg)150 xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
151 {
152 ctxt->errors++;
153 fprintf(ctxt->output, "ERROR %d: %s", error, msg);
154 }
155 static void LIBXML_ATTR_FORMAT(3,0)
xmlDebugErr2(xmlDebugCtxtPtr ctxt,int error,const char * msg,int extra)156 xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra)
157 {
158 ctxt->errors++;
159 fprintf(ctxt->output, "ERROR %d: ", error);
160 fprintf(ctxt->output, msg, extra);
161 }
162 static void LIBXML_ATTR_FORMAT(3,0)
xmlDebugErr3(xmlDebugCtxtPtr ctxt,int error,const char * msg,const char * extra)163 xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, const char *extra)
164 {
165 ctxt->errors++;
166 fprintf(ctxt->output, "ERROR %d: ", error);
167 fprintf(ctxt->output, msg, extra);
168 }
169
170 /**
171 * xmlCtxtNsCheckScope:
172 * @ctxt: the debugging context
173 * @node: the node
174 * @ns: the namespace node
175 *
176 * Report if a given namespace is is not in scope.
177 */
178 static void
xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt,xmlNodePtr node,xmlNsPtr ns)179 xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt, xmlNodePtr node, xmlNsPtr ns)
180 {
181 int ret;
182
183 ret = xmlNsCheckScope(node, ns);
184 if (ret == -2) {
185 if (ns->prefix == NULL)
186 xmlDebugErr(ctxt, XML_CHECK_NS_SCOPE,
187 "Reference to default namespace not in scope\n");
188 else
189 xmlDebugErr3(ctxt, XML_CHECK_NS_SCOPE,
190 "Reference to namespace '%s' not in scope\n",
191 (char *) ns->prefix);
192 }
193 if (ret == -3) {
194 if (ns->prefix == NULL)
195 xmlDebugErr(ctxt, XML_CHECK_NS_ANCESTOR,
196 "Reference to default namespace not on ancestor\n");
197 else
198 xmlDebugErr3(ctxt, XML_CHECK_NS_ANCESTOR,
199 "Reference to namespace '%s' not on ancestor\n",
200 (char *) ns->prefix);
201 }
202 }
203
204 /**
205 * xmlCtxtCheckString:
206 * @ctxt: the debug context
207 * @str: the string
208 *
209 * Do debugging on the string, currently it just checks the UTF-8 content
210 */
211 static void
xmlCtxtCheckString(xmlDebugCtxtPtr ctxt,const xmlChar * str)212 xmlCtxtCheckString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
213 {
214 if (str == NULL) return;
215 if (ctxt->check) {
216 if (!xmlCheckUTF8(str)) {
217 xmlDebugErr3(ctxt, XML_CHECK_NOT_UTF8,
218 "String is not UTF-8 %s", (const char *) str);
219 }
220 }
221 }
222
223 /**
224 * xmlCtxtCheckName:
225 * @ctxt: the debug context
226 * @name: the name
227 *
228 * Do debugging on the name, for example the dictionary status and
229 * conformance to the Name production.
230 */
231 static void
xmlCtxtCheckName(xmlDebugCtxtPtr ctxt,const xmlChar * name)232 xmlCtxtCheckName(xmlDebugCtxtPtr ctxt, const xmlChar * name)
233 {
234 if (ctxt->check) {
235 if (name == NULL) {
236 xmlDebugErr(ctxt, XML_CHECK_NO_NAME, "Name is NULL");
237 return;
238 }
239 if (xmlValidateName(name, 0)) {
240 xmlDebugErr3(ctxt, XML_CHECK_NOT_NCNAME,
241 "Name is not an NCName '%s'", (const char *) name);
242 }
243 if ((ctxt->dict != NULL) &&
244 (!xmlDictOwns(ctxt->dict, name)) &&
245 ((ctxt->doc == NULL) ||
246 ((ctxt->doc->parseFlags & (XML_PARSE_SAX1 | XML_PARSE_NODICT)) == 0))) {
247 xmlDebugErr3(ctxt, XML_CHECK_OUTSIDE_DICT,
248 "Name is not from the document dictionary '%s'",
249 (const char *) name);
250 }
251 }
252 }
253
254 static void
xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt,xmlNodePtr node)255 xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
256 xmlDocPtr doc;
257 xmlDictPtr dict;
258
259 doc = node->doc;
260
261 if (node->parent == NULL)
262 xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
263 "Node has no parent\n");
264 if (node->doc == NULL) {
265 xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
266 "Node has no doc\n");
267 dict = NULL;
268 } else {
269 dict = doc->dict;
270 if ((dict == NULL) && (ctxt->nodict == 0)) {
271 ctxt->nodict = 1;
272 }
273 if (ctxt->doc == NULL)
274 ctxt->doc = doc;
275
276 if (ctxt->dict == NULL) {
277 ctxt->dict = dict;
278 }
279 }
280 if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
281 (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
282 xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
283 "Node doc differs from parent's one\n");
284 if (node->prev == NULL) {
285 if (node->type == XML_ATTRIBUTE_NODE) {
286 if ((node->parent != NULL) &&
287 (node != (xmlNodePtr) node->parent->properties))
288 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
289 "Attr has no prev and not first of attr list\n");
290
291 } else if ((node->parent != NULL) && (node->parent->children != node))
292 xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
293 "Node has no prev and not first of parent list\n");
294 } else {
295 if (node->prev->next != node)
296 xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
297 "Node prev->next : back link wrong\n");
298 }
299 if (node->next == NULL) {
300 if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
301 (node->parent->last != node) &&
302 (node->parent->type == XML_ELEMENT_NODE))
303 xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
304 "Node has no next and not last of parent list\n");
305 } else {
306 if (node->next->prev != node)
307 xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
308 "Node next->prev : forward link wrong\n");
309 if (node->next->parent != node->parent)
310 xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT,
311 "Node next->prev : forward link wrong\n");
312 }
313 if (node->type == XML_ELEMENT_NODE) {
314 xmlNsPtr ns;
315
316 ns = node->nsDef;
317 while (ns != NULL) {
318 xmlCtxtNsCheckScope(ctxt, node, ns);
319 ns = ns->next;
320 }
321 if (node->ns != NULL)
322 xmlCtxtNsCheckScope(ctxt, node, node->ns);
323 } else if (node->type == XML_ATTRIBUTE_NODE) {
324 if (node->ns != NULL)
325 xmlCtxtNsCheckScope(ctxt, node, node->ns);
326 }
327
328 if ((node->type != XML_ELEMENT_NODE) &&
329 (node->type != XML_ATTRIBUTE_NODE) &&
330 (node->type != XML_ELEMENT_DECL) &&
331 (node->type != XML_ATTRIBUTE_DECL) &&
332 (node->type != XML_DTD_NODE) &&
333 (node->type != XML_HTML_DOCUMENT_NODE) &&
334 (node->type != XML_DOCUMENT_NODE)) {
335 if (node->content != NULL)
336 xmlCtxtCheckString(ctxt, (const xmlChar *) node->content);
337 }
338 switch (node->type) {
339 case XML_ELEMENT_NODE:
340 case XML_ATTRIBUTE_NODE:
341 xmlCtxtCheckName(ctxt, node->name);
342 break;
343 case XML_TEXT_NODE:
344 if ((node->name == xmlStringText) ||
345 (node->name == xmlStringTextNoenc))
346 break;
347 /* some case of entity substitution can lead to this */
348 if ((ctxt->dict != NULL) &&
349 (node->name == xmlDictLookup(ctxt->dict, BAD_CAST "nbktext",
350 7)))
351 break;
352
353 xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
354 "Text node has wrong name '%s'",
355 (const char *) node->name);
356 break;
357 case XML_COMMENT_NODE:
358 if (node->name == xmlStringComment)
359 break;
360 xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
361 "Comment node has wrong name '%s'",
362 (const char *) node->name);
363 break;
364 case XML_PI_NODE:
365 xmlCtxtCheckName(ctxt, node->name);
366 break;
367 case XML_CDATA_SECTION_NODE:
368 if (node->name == NULL)
369 break;
370 xmlDebugErr3(ctxt, XML_CHECK_NAME_NOT_NULL,
371 "CData section has non NULL name '%s'",
372 (const char *) node->name);
373 break;
374 case XML_ENTITY_REF_NODE:
375 case XML_ENTITY_NODE:
376 case XML_DOCUMENT_TYPE_NODE:
377 case XML_DOCUMENT_FRAG_NODE:
378 case XML_NOTATION_NODE:
379 case XML_DTD_NODE:
380 case XML_ELEMENT_DECL:
381 case XML_ATTRIBUTE_DECL:
382 case XML_ENTITY_DECL:
383 case XML_NAMESPACE_DECL:
384 case XML_XINCLUDE_START:
385 case XML_XINCLUDE_END:
386 case XML_DOCUMENT_NODE:
387 case XML_HTML_DOCUMENT_NODE:
388 break;
389 }
390 }
391
392 static void
xmlCtxtDumpString(xmlDebugCtxtPtr ctxt,const xmlChar * str)393 xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
394 {
395 int i;
396
397 if (ctxt->check) {
398 return;
399 }
400 /* TODO: check UTF8 content of the string */
401 if (str == NULL) {
402 fprintf(ctxt->output, "(NULL)");
403 return;
404 }
405 for (i = 0; i < 40; i++)
406 if (str[i] == 0)
407 return;
408 else if (IS_BLANK_CH(str[i]))
409 fputc(' ', ctxt->output);
410 else if (str[i] >= 0x80)
411 fprintf(ctxt->output, "#%X", str[i]);
412 else
413 fputc(str[i], ctxt->output);
414 fprintf(ctxt->output, "...");
415 }
416
417 static void
xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)418 xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
419 {
420 xmlCtxtDumpSpaces(ctxt);
421
422 if (dtd == NULL) {
423 if (!ctxt->check)
424 fprintf(ctxt->output, "DTD node is NULL\n");
425 return;
426 }
427
428 if (dtd->type != XML_DTD_NODE) {
429 xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
430 "Node is not a DTD");
431 return;
432 }
433 if (!ctxt->check) {
434 if (dtd->name != NULL)
435 fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
436 else
437 fprintf(ctxt->output, "DTD");
438 if (dtd->ExternalID != NULL)
439 fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
440 if (dtd->SystemID != NULL)
441 fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
442 fprintf(ctxt->output, "\n");
443 }
444 /*
445 * Do a bit of checking
446 */
447 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
448 }
449
450 static void
xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt,xmlAttributePtr attr)451 xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
452 {
453 xmlCtxtDumpSpaces(ctxt);
454
455 if (attr == NULL) {
456 if (!ctxt->check)
457 fprintf(ctxt->output, "Attribute declaration is NULL\n");
458 return;
459 }
460 if (attr->type != XML_ATTRIBUTE_DECL) {
461 xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
462 "Node is not an attribute declaration");
463 return;
464 }
465 if (attr->name != NULL) {
466 if (!ctxt->check)
467 fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
468 } else
469 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
470 "Node attribute declaration has no name");
471 if (attr->elem != NULL) {
472 if (!ctxt->check)
473 fprintf(ctxt->output, " for %s", (char *) attr->elem);
474 } else
475 xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
476 "Node attribute declaration has no element name");
477 if (!ctxt->check) {
478 switch (attr->atype) {
479 case XML_ATTRIBUTE_CDATA:
480 fprintf(ctxt->output, " CDATA");
481 break;
482 case XML_ATTRIBUTE_ID:
483 fprintf(ctxt->output, " ID");
484 break;
485 case XML_ATTRIBUTE_IDREF:
486 fprintf(ctxt->output, " IDREF");
487 break;
488 case XML_ATTRIBUTE_IDREFS:
489 fprintf(ctxt->output, " IDREFS");
490 break;
491 case XML_ATTRIBUTE_ENTITY:
492 fprintf(ctxt->output, " ENTITY");
493 break;
494 case XML_ATTRIBUTE_ENTITIES:
495 fprintf(ctxt->output, " ENTITIES");
496 break;
497 case XML_ATTRIBUTE_NMTOKEN:
498 fprintf(ctxt->output, " NMTOKEN");
499 break;
500 case XML_ATTRIBUTE_NMTOKENS:
501 fprintf(ctxt->output, " NMTOKENS");
502 break;
503 case XML_ATTRIBUTE_ENUMERATION:
504 fprintf(ctxt->output, " ENUMERATION");
505 break;
506 case XML_ATTRIBUTE_NOTATION:
507 fprintf(ctxt->output, " NOTATION ");
508 break;
509 }
510 if (attr->tree != NULL) {
511 int indx;
512 xmlEnumerationPtr cur = attr->tree;
513
514 for (indx = 0; indx < 5; indx++) {
515 if (indx != 0)
516 fprintf(ctxt->output, "|%s", (char *) cur->name);
517 else
518 fprintf(ctxt->output, " (%s", (char *) cur->name);
519 cur = cur->next;
520 if (cur == NULL)
521 break;
522 }
523 if (cur == NULL)
524 fprintf(ctxt->output, ")");
525 else
526 fprintf(ctxt->output, "...)");
527 }
528 switch (attr->def) {
529 case XML_ATTRIBUTE_NONE:
530 break;
531 case XML_ATTRIBUTE_REQUIRED:
532 fprintf(ctxt->output, " REQUIRED");
533 break;
534 case XML_ATTRIBUTE_IMPLIED:
535 fprintf(ctxt->output, " IMPLIED");
536 break;
537 case XML_ATTRIBUTE_FIXED:
538 fprintf(ctxt->output, " FIXED");
539 break;
540 }
541 if (attr->defaultValue != NULL) {
542 fprintf(ctxt->output, "\"");
543 xmlCtxtDumpString(ctxt, attr->defaultValue);
544 fprintf(ctxt->output, "\"");
545 }
546 fprintf(ctxt->output, "\n");
547 }
548
549 /*
550 * Do a bit of checking
551 */
552 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
553 }
554
555 static void
xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt,xmlElementPtr elem)556 xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
557 {
558 xmlCtxtDumpSpaces(ctxt);
559
560 if (elem == NULL) {
561 if (!ctxt->check)
562 fprintf(ctxt->output, "Element declaration is NULL\n");
563 return;
564 }
565 if (elem->type != XML_ELEMENT_DECL) {
566 xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
567 "Node is not an element declaration");
568 return;
569 }
570 if (elem->name != NULL) {
571 if (!ctxt->check) {
572 fprintf(ctxt->output, "ELEMDECL(");
573 xmlCtxtDumpString(ctxt, elem->name);
574 fprintf(ctxt->output, ")");
575 }
576 } else
577 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
578 "Element declaration has no name");
579 if (!ctxt->check) {
580 switch (elem->etype) {
581 case XML_ELEMENT_TYPE_UNDEFINED:
582 fprintf(ctxt->output, ", UNDEFINED");
583 break;
584 case XML_ELEMENT_TYPE_EMPTY:
585 fprintf(ctxt->output, ", EMPTY");
586 break;
587 case XML_ELEMENT_TYPE_ANY:
588 fprintf(ctxt->output, ", ANY");
589 break;
590 case XML_ELEMENT_TYPE_MIXED:
591 fprintf(ctxt->output, ", MIXED ");
592 break;
593 case XML_ELEMENT_TYPE_ELEMENT:
594 fprintf(ctxt->output, ", MIXED ");
595 break;
596 }
597 if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
598 char buf[5001];
599
600 buf[0] = 0;
601 xmlSnprintfElementContent(buf, 5000, elem->content, 1);
602 buf[5000] = 0;
603 fprintf(ctxt->output, "%s", buf);
604 }
605 fprintf(ctxt->output, "\n");
606 }
607
608 /*
609 * Do a bit of checking
610 */
611 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
612 }
613
614 static void
xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)615 xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
616 {
617 xmlCtxtDumpSpaces(ctxt);
618
619 if (ent == NULL) {
620 if (!ctxt->check)
621 fprintf(ctxt->output, "Entity declaration is NULL\n");
622 return;
623 }
624 if (ent->type != XML_ENTITY_DECL) {
625 xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
626 "Node is not an entity declaration");
627 return;
628 }
629 if (ent->name != NULL) {
630 if (!ctxt->check) {
631 fprintf(ctxt->output, "ENTITYDECL(");
632 xmlCtxtDumpString(ctxt, ent->name);
633 fprintf(ctxt->output, ")");
634 }
635 } else
636 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
637 "Entity declaration has no name");
638 if (!ctxt->check) {
639 switch (ent->etype) {
640 case XML_INTERNAL_GENERAL_ENTITY:
641 fprintf(ctxt->output, ", internal\n");
642 break;
643 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
644 fprintf(ctxt->output, ", external parsed\n");
645 break;
646 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
647 fprintf(ctxt->output, ", unparsed\n");
648 break;
649 case XML_INTERNAL_PARAMETER_ENTITY:
650 fprintf(ctxt->output, ", parameter\n");
651 break;
652 case XML_EXTERNAL_PARAMETER_ENTITY:
653 fprintf(ctxt->output, ", external parameter\n");
654 break;
655 case XML_INTERNAL_PREDEFINED_ENTITY:
656 fprintf(ctxt->output, ", predefined\n");
657 break;
658 }
659 if (ent->ExternalID) {
660 xmlCtxtDumpSpaces(ctxt);
661 fprintf(ctxt->output, " ExternalID=%s\n",
662 (char *) ent->ExternalID);
663 }
664 if (ent->SystemID) {
665 xmlCtxtDumpSpaces(ctxt);
666 fprintf(ctxt->output, " SystemID=%s\n",
667 (char *) ent->SystemID);
668 }
669 if (ent->URI != NULL) {
670 xmlCtxtDumpSpaces(ctxt);
671 fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
672 }
673 if (ent->content) {
674 xmlCtxtDumpSpaces(ctxt);
675 fprintf(ctxt->output, " content=");
676 xmlCtxtDumpString(ctxt, ent->content);
677 fprintf(ctxt->output, "\n");
678 }
679 }
680
681 /*
682 * Do a bit of checking
683 */
684 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
685 }
686
687 static void
xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)688 xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
689 {
690 xmlCtxtDumpSpaces(ctxt);
691
692 if (ns == NULL) {
693 if (!ctxt->check)
694 fprintf(ctxt->output, "namespace node is NULL\n");
695 return;
696 }
697 if (ns->type != XML_NAMESPACE_DECL) {
698 xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
699 "Node is not a namespace declaration");
700 return;
701 }
702 if (ns->href == NULL) {
703 if (ns->prefix != NULL)
704 xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
705 "Incomplete namespace %s href=NULL\n",
706 (char *) ns->prefix);
707 else
708 xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
709 "Incomplete default namespace href=NULL\n");
710 } else {
711 if (!ctxt->check) {
712 if (ns->prefix != NULL)
713 fprintf(ctxt->output, "namespace %s href=",
714 (char *) ns->prefix);
715 else
716 fprintf(ctxt->output, "default namespace href=");
717
718 xmlCtxtDumpString(ctxt, ns->href);
719 fprintf(ctxt->output, "\n");
720 }
721 }
722 }
723
724 static void
xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)725 xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
726 {
727 while (ns != NULL) {
728 xmlCtxtDumpNamespace(ctxt, ns);
729 ns = ns->next;
730 }
731 }
732
733 static void
xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)734 xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
735 {
736 xmlCtxtDumpSpaces(ctxt);
737
738 if (ent == NULL) {
739 if (!ctxt->check)
740 fprintf(ctxt->output, "Entity is NULL\n");
741 return;
742 }
743 if (!ctxt->check) {
744 switch (ent->etype) {
745 case XML_INTERNAL_GENERAL_ENTITY:
746 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
747 break;
748 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
749 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
750 break;
751 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
752 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
753 break;
754 case XML_INTERNAL_PARAMETER_ENTITY:
755 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
756 break;
757 case XML_EXTERNAL_PARAMETER_ENTITY:
758 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
759 break;
760 default:
761 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
762 }
763 fprintf(ctxt->output, "%s\n", ent->name);
764 if (ent->ExternalID) {
765 xmlCtxtDumpSpaces(ctxt);
766 fprintf(ctxt->output, "ExternalID=%s\n",
767 (char *) ent->ExternalID);
768 }
769 if (ent->SystemID) {
770 xmlCtxtDumpSpaces(ctxt);
771 fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
772 }
773 if (ent->URI) {
774 xmlCtxtDumpSpaces(ctxt);
775 fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
776 }
777 if (ent->content) {
778 xmlCtxtDumpSpaces(ctxt);
779 fprintf(ctxt->output, "content=");
780 xmlCtxtDumpString(ctxt, ent->content);
781 fprintf(ctxt->output, "\n");
782 }
783 }
784 }
785
786 /**
787 * xmlCtxtDumpAttr:
788 * @output: the FILE * for the output
789 * @attr: the attribute
790 * @depth: the indentation level.
791 *
792 * Dumps debug information for the attribute
793 */
794 static void
xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)795 xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
796 {
797 xmlCtxtDumpSpaces(ctxt);
798
799 if (attr == NULL) {
800 if (!ctxt->check)
801 fprintf(ctxt->output, "Attr is NULL");
802 return;
803 }
804 if (!ctxt->check) {
805 fprintf(ctxt->output, "ATTRIBUTE ");
806 xmlCtxtDumpString(ctxt, attr->name);
807 fprintf(ctxt->output, "\n");
808 if (attr->children != NULL) {
809 ctxt->depth++;
810 xmlCtxtDumpNodeList(ctxt, attr->children);
811 ctxt->depth--;
812 }
813 }
814 if (attr->name == NULL)
815 xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
816 "Attribute has no name");
817
818 /*
819 * Do a bit of checking
820 */
821 xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
822 }
823
824 /**
825 * xmlCtxtDumpAttrList:
826 * @output: the FILE * for the output
827 * @attr: the attribute list
828 * @depth: the indentation level.
829 *
830 * Dumps debug information for the attribute list
831 */
832 static void
xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)833 xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
834 {
835 while (attr != NULL) {
836 xmlCtxtDumpAttr(ctxt, attr);
837 attr = attr->next;
838 }
839 }
840
841 /**
842 * xmlCtxtDumpOneNode:
843 * @output: the FILE * for the output
844 * @node: the node
845 * @depth: the indentation level.
846 *
847 * Dumps debug information for the element node, it is not recursive
848 */
849 static void
xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)850 xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
851 {
852 if (node == NULL) {
853 if (!ctxt->check) {
854 xmlCtxtDumpSpaces(ctxt);
855 fprintf(ctxt->output, "node is NULL\n");
856 }
857 return;
858 }
859 ctxt->node = node;
860
861 switch (node->type) {
862 case XML_ELEMENT_NODE:
863 if (!ctxt->check) {
864 xmlCtxtDumpSpaces(ctxt);
865 fprintf(ctxt->output, "ELEMENT ");
866 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
867 xmlCtxtDumpString(ctxt, node->ns->prefix);
868 fprintf(ctxt->output, ":");
869 }
870 xmlCtxtDumpString(ctxt, node->name);
871 fprintf(ctxt->output, "\n");
872 }
873 break;
874 case XML_ATTRIBUTE_NODE:
875 if (!ctxt->check)
876 xmlCtxtDumpSpaces(ctxt);
877 fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
878 xmlCtxtGenericNodeCheck(ctxt, node);
879 return;
880 case XML_TEXT_NODE:
881 if (!ctxt->check) {
882 xmlCtxtDumpSpaces(ctxt);
883 if (node->name == (const xmlChar *) xmlStringTextNoenc)
884 fprintf(ctxt->output, "TEXT no enc");
885 else
886 fprintf(ctxt->output, "TEXT");
887 if (ctxt->options & DUMP_TEXT_TYPE) {
888 if (node->content == (xmlChar *) &(node->properties))
889 fprintf(ctxt->output, " compact\n");
890 else if (xmlDictOwns(ctxt->dict, node->content) == 1)
891 fprintf(ctxt->output, " interned\n");
892 else
893 fprintf(ctxt->output, "\n");
894 } else
895 fprintf(ctxt->output, "\n");
896 }
897 break;
898 case XML_CDATA_SECTION_NODE:
899 if (!ctxt->check) {
900 xmlCtxtDumpSpaces(ctxt);
901 fprintf(ctxt->output, "CDATA_SECTION\n");
902 }
903 break;
904 case XML_ENTITY_REF_NODE:
905 if (!ctxt->check) {
906 xmlCtxtDumpSpaces(ctxt);
907 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
908 (char *) node->name);
909 }
910 break;
911 case XML_ENTITY_NODE:
912 if (!ctxt->check) {
913 xmlCtxtDumpSpaces(ctxt);
914 fprintf(ctxt->output, "ENTITY\n");
915 }
916 break;
917 case XML_PI_NODE:
918 if (!ctxt->check) {
919 xmlCtxtDumpSpaces(ctxt);
920 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
921 }
922 break;
923 case XML_COMMENT_NODE:
924 if (!ctxt->check) {
925 xmlCtxtDumpSpaces(ctxt);
926 fprintf(ctxt->output, "COMMENT\n");
927 }
928 break;
929 case XML_DOCUMENT_NODE:
930 case XML_HTML_DOCUMENT_NODE:
931 if (!ctxt->check) {
932 xmlCtxtDumpSpaces(ctxt);
933 }
934 fprintf(ctxt->output, "Error, DOCUMENT found here\n");
935 xmlCtxtGenericNodeCheck(ctxt, node);
936 return;
937 case XML_DOCUMENT_TYPE_NODE:
938 if (!ctxt->check) {
939 xmlCtxtDumpSpaces(ctxt);
940 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
941 }
942 break;
943 case XML_DOCUMENT_FRAG_NODE:
944 if (!ctxt->check) {
945 xmlCtxtDumpSpaces(ctxt);
946 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
947 }
948 break;
949 case XML_NOTATION_NODE:
950 if (!ctxt->check) {
951 xmlCtxtDumpSpaces(ctxt);
952 fprintf(ctxt->output, "NOTATION\n");
953 }
954 break;
955 case XML_DTD_NODE:
956 xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
957 return;
958 case XML_ELEMENT_DECL:
959 xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
960 return;
961 case XML_ATTRIBUTE_DECL:
962 xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
963 return;
964 case XML_ENTITY_DECL:
965 xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
966 return;
967 case XML_NAMESPACE_DECL:
968 xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
969 return;
970 case XML_XINCLUDE_START:
971 if (!ctxt->check) {
972 xmlCtxtDumpSpaces(ctxt);
973 fprintf(ctxt->output, "INCLUDE START\n");
974 }
975 return;
976 case XML_XINCLUDE_END:
977 if (!ctxt->check) {
978 xmlCtxtDumpSpaces(ctxt);
979 fprintf(ctxt->output, "INCLUDE END\n");
980 }
981 return;
982 default:
983 if (!ctxt->check)
984 xmlCtxtDumpSpaces(ctxt);
985 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
986 "Unknown node type %d\n", node->type);
987 return;
988 }
989 if (node->doc == NULL) {
990 if (!ctxt->check) {
991 xmlCtxtDumpSpaces(ctxt);
992 }
993 fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
994 }
995 ctxt->depth++;
996 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
997 xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
998 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
999 xmlCtxtDumpAttrList(ctxt, node->properties);
1000 if (node->type != XML_ENTITY_REF_NODE) {
1001 if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
1002 if (!ctxt->check) {
1003 xmlCtxtDumpSpaces(ctxt);
1004 fprintf(ctxt->output, "content=");
1005 xmlCtxtDumpString(ctxt, node->content);
1006 fprintf(ctxt->output, "\n");
1007 }
1008 }
1009 } else {
1010 xmlEntityPtr ent;
1011
1012 ent = xmlGetDocEntity(node->doc, node->name);
1013 if (ent != NULL)
1014 xmlCtxtDumpEntity(ctxt, ent);
1015 }
1016 ctxt->depth--;
1017
1018 /*
1019 * Do a bit of checking
1020 */
1021 xmlCtxtGenericNodeCheck(ctxt, node);
1022 }
1023
1024 /**
1025 * xmlCtxtDumpNode:
1026 * @output: the FILE * for the output
1027 * @node: the node
1028 * @depth: the indentation level.
1029 *
1030 * Dumps debug information for the element node, it is recursive
1031 */
1032 static void
xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1033 xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1034 {
1035 if (node == NULL) {
1036 if (!ctxt->check) {
1037 xmlCtxtDumpSpaces(ctxt);
1038 fprintf(ctxt->output, "node is NULL\n");
1039 }
1040 return;
1041 }
1042 xmlCtxtDumpOneNode(ctxt, node);
1043 if ((node->type != XML_NAMESPACE_DECL) &&
1044 (node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1045 ctxt->depth++;
1046 xmlCtxtDumpNodeList(ctxt, node->children);
1047 ctxt->depth--;
1048 }
1049 }
1050
1051 /**
1052 * xmlCtxtDumpNodeList:
1053 * @output: the FILE * for the output
1054 * @node: the node list
1055 * @depth: the indentation level.
1056 *
1057 * Dumps debug information for the list of element node, it is recursive
1058 */
1059 static void
xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1060 xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1061 {
1062 while (node != NULL) {
1063 xmlCtxtDumpNode(ctxt, node);
1064 node = node->next;
1065 }
1066 }
1067
1068 static void
xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1069 xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1070 {
1071 if (doc == NULL) {
1072 if (!ctxt->check)
1073 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1074 return;
1075 }
1076 ctxt->node = (xmlNodePtr) doc;
1077
1078 switch (doc->type) {
1079 case XML_ELEMENT_NODE:
1080 xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
1081 "Misplaced ELEMENT node\n");
1082 break;
1083 case XML_ATTRIBUTE_NODE:
1084 xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
1085 "Misplaced ATTRIBUTE node\n");
1086 break;
1087 case XML_TEXT_NODE:
1088 xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
1089 "Misplaced TEXT node\n");
1090 break;
1091 case XML_CDATA_SECTION_NODE:
1092 xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
1093 "Misplaced CDATA node\n");
1094 break;
1095 case XML_ENTITY_REF_NODE:
1096 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
1097 "Misplaced ENTITYREF node\n");
1098 break;
1099 case XML_ENTITY_NODE:
1100 xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
1101 "Misplaced ENTITY node\n");
1102 break;
1103 case XML_PI_NODE:
1104 xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
1105 "Misplaced PI node\n");
1106 break;
1107 case XML_COMMENT_NODE:
1108 xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
1109 "Misplaced COMMENT node\n");
1110 break;
1111 case XML_DOCUMENT_NODE:
1112 if (!ctxt->check)
1113 fprintf(ctxt->output, "DOCUMENT\n");
1114 break;
1115 case XML_HTML_DOCUMENT_NODE:
1116 if (!ctxt->check)
1117 fprintf(ctxt->output, "HTML DOCUMENT\n");
1118 break;
1119 case XML_DOCUMENT_TYPE_NODE:
1120 xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
1121 "Misplaced DOCTYPE node\n");
1122 break;
1123 case XML_DOCUMENT_FRAG_NODE:
1124 xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
1125 "Misplaced FRAGMENT node\n");
1126 break;
1127 case XML_NOTATION_NODE:
1128 xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
1129 "Misplaced NOTATION node\n");
1130 break;
1131 default:
1132 xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
1133 "Unknown node type %d\n", doc->type);
1134 }
1135 }
1136
1137 /**
1138 * xmlCtxtDumpDocumentHead:
1139 * @output: the FILE * for the output
1140 * @doc: the document
1141 *
1142 * Dumps debug information concerning the document, not recursive
1143 */
1144 static void
xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1145 xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1146 {
1147 if (doc == NULL) return;
1148 xmlCtxtDumpDocHead(ctxt, doc);
1149 if (!ctxt->check) {
1150 if (doc->name != NULL) {
1151 fprintf(ctxt->output, "name=");
1152 xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
1153 fprintf(ctxt->output, "\n");
1154 }
1155 if (doc->version != NULL) {
1156 fprintf(ctxt->output, "version=");
1157 xmlCtxtDumpString(ctxt, doc->version);
1158 fprintf(ctxt->output, "\n");
1159 }
1160 if (doc->encoding != NULL) {
1161 fprintf(ctxt->output, "encoding=");
1162 xmlCtxtDumpString(ctxt, doc->encoding);
1163 fprintf(ctxt->output, "\n");
1164 }
1165 if (doc->URL != NULL) {
1166 fprintf(ctxt->output, "URL=");
1167 xmlCtxtDumpString(ctxt, doc->URL);
1168 fprintf(ctxt->output, "\n");
1169 }
1170 if (doc->standalone)
1171 fprintf(ctxt->output, "standalone=true\n");
1172 }
1173 if (doc->oldNs != NULL)
1174 xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
1175 }
1176
1177 /**
1178 * xmlCtxtDumpDocument:
1179 * @output: the FILE * for the output
1180 * @doc: the document
1181 *
1182 * Dumps debug information for the document, it's recursive
1183 */
1184 static void
xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1185 xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1186 {
1187 if (doc == NULL) {
1188 if (!ctxt->check)
1189 fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1190 return;
1191 }
1192 xmlCtxtDumpDocumentHead(ctxt, doc);
1193 if (((doc->type == XML_DOCUMENT_NODE) ||
1194 (doc->type == XML_HTML_DOCUMENT_NODE))
1195 && (doc->children != NULL)) {
1196 ctxt->depth++;
1197 xmlCtxtDumpNodeList(ctxt, doc->children);
1198 ctxt->depth--;
1199 }
1200 }
1201
1202 static void
xmlCtxtDumpEntityCallback(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)1203 xmlCtxtDumpEntityCallback(void *payload, void *data,
1204 const xmlChar *name ATTRIBUTE_UNUSED)
1205 {
1206 xmlEntityPtr cur = (xmlEntityPtr) payload;
1207 xmlDebugCtxtPtr ctxt = (xmlDebugCtxtPtr) data;
1208 if (cur == NULL) {
1209 if (!ctxt->check)
1210 fprintf(ctxt->output, "Entity is NULL");
1211 return;
1212 }
1213 if (!ctxt->check) {
1214 fprintf(ctxt->output, "%s : ", (char *) cur->name);
1215 switch (cur->etype) {
1216 case XML_INTERNAL_GENERAL_ENTITY:
1217 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1218 break;
1219 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1220 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1221 break;
1222 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1223 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1224 break;
1225 case XML_INTERNAL_PARAMETER_ENTITY:
1226 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1227 break;
1228 case XML_EXTERNAL_PARAMETER_ENTITY:
1229 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1230 break;
1231 default:
1232 xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1233 "Unknown entity type %d\n", cur->etype);
1234 }
1235 if (cur->ExternalID != NULL)
1236 fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1237 if (cur->SystemID != NULL)
1238 fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1239 if (cur->orig != NULL)
1240 fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1241 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1242 fprintf(ctxt->output, "\n content \"%s\"",
1243 (char *) cur->content);
1244 fprintf(ctxt->output, "\n");
1245 }
1246 }
1247
1248 /**
1249 * xmlCtxtDumpEntities:
1250 * @output: the FILE * for the output
1251 * @doc: the document
1252 *
1253 * Dumps debug information for all the entities in use by the document
1254 */
1255 static void
xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1256 xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1257 {
1258 if (doc == NULL) return;
1259 xmlCtxtDumpDocHead(ctxt, doc);
1260 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1261 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1262 doc->intSubset->entities;
1263
1264 if (!ctxt->check)
1265 fprintf(ctxt->output, "Entities in internal subset\n");
1266 xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1267 } else
1268 fprintf(ctxt->output, "No entities in internal subset\n");
1269 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1270 xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1271 doc->extSubset->entities;
1272
1273 if (!ctxt->check)
1274 fprintf(ctxt->output, "Entities in external subset\n");
1275 xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1276 } else if (!ctxt->check)
1277 fprintf(ctxt->output, "No entities in external subset\n");
1278 }
1279
1280 /**
1281 * xmlCtxtDumpDTD:
1282 * @output: the FILE * for the output
1283 * @dtd: the DTD
1284 *
1285 * Dumps debug information for the DTD
1286 */
1287 static void
xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)1288 xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1289 {
1290 if (dtd == NULL) {
1291 if (!ctxt->check)
1292 fprintf(ctxt->output, "DTD is NULL\n");
1293 return;
1294 }
1295 xmlCtxtDumpDtdNode(ctxt, dtd);
1296 if (dtd->children == NULL)
1297 fprintf(ctxt->output, " DTD is empty\n");
1298 else {
1299 ctxt->depth++;
1300 xmlCtxtDumpNodeList(ctxt, dtd->children);
1301 ctxt->depth--;
1302 }
1303 }
1304
1305 /************************************************************************
1306 * *
1307 * Public entry points for dump *
1308 * *
1309 ************************************************************************/
1310
1311 /**
1312 * xmlDebugDumpString:
1313 * @output: the FILE * for the output
1314 * @str: the string
1315 *
1316 * Dumps information about the string, shorten it if necessary
1317 */
1318 void
xmlDebugDumpString(FILE * output,const xmlChar * str)1319 xmlDebugDumpString(FILE * output, const xmlChar * str)
1320 {
1321 int i;
1322
1323 if (output == NULL)
1324 output = stdout;
1325 if (str == NULL) {
1326 fprintf(output, "(NULL)");
1327 return;
1328 }
1329 for (i = 0; i < 40; i++)
1330 if (str[i] == 0)
1331 return;
1332 else if (IS_BLANK_CH(str[i]))
1333 fputc(' ', output);
1334 else if (str[i] >= 0x80)
1335 fprintf(output, "#%X", str[i]);
1336 else
1337 fputc(str[i], output);
1338 fprintf(output, "...");
1339 }
1340
1341 /**
1342 * xmlDebugDumpAttr:
1343 * @output: the FILE * for the output
1344 * @attr: the attribute
1345 * @depth: the indentation level.
1346 *
1347 * Dumps debug information for the attribute
1348 */
1349 void
xmlDebugDumpAttr(FILE * output,xmlAttrPtr attr,int depth)1350 xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
1351 xmlDebugCtxt ctxt;
1352
1353 if (output == NULL) return;
1354 xmlCtxtDumpInitCtxt(&ctxt);
1355 ctxt.output = output;
1356 ctxt.depth = depth;
1357 xmlCtxtDumpAttr(&ctxt, attr);
1358 xmlCtxtDumpCleanCtxt(&ctxt);
1359 }
1360
1361
1362 /**
1363 * xmlDebugDumpEntities:
1364 * @output: the FILE * for the output
1365 * @doc: the document
1366 *
1367 * Dumps debug information for all the entities in use by the document
1368 */
1369 void
xmlDebugDumpEntities(FILE * output,xmlDocPtr doc)1370 xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1371 {
1372 xmlDebugCtxt ctxt;
1373
1374 if (output == NULL) return;
1375 xmlCtxtDumpInitCtxt(&ctxt);
1376 ctxt.output = output;
1377 xmlCtxtDumpEntities(&ctxt, doc);
1378 xmlCtxtDumpCleanCtxt(&ctxt);
1379 }
1380
1381 /**
1382 * xmlDebugDumpAttrList:
1383 * @output: the FILE * for the output
1384 * @attr: the attribute list
1385 * @depth: the indentation level.
1386 *
1387 * Dumps debug information for the attribute list
1388 */
1389 void
xmlDebugDumpAttrList(FILE * output,xmlAttrPtr attr,int depth)1390 xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1391 {
1392 xmlDebugCtxt ctxt;
1393
1394 if (output == NULL) return;
1395 xmlCtxtDumpInitCtxt(&ctxt);
1396 ctxt.output = output;
1397 ctxt.depth = depth;
1398 xmlCtxtDumpAttrList(&ctxt, attr);
1399 xmlCtxtDumpCleanCtxt(&ctxt);
1400 }
1401
1402 /**
1403 * xmlDebugDumpOneNode:
1404 * @output: the FILE * for the output
1405 * @node: the node
1406 * @depth: the indentation level.
1407 *
1408 * Dumps debug information for the element node, it is not recursive
1409 */
1410 void
xmlDebugDumpOneNode(FILE * output,xmlNodePtr node,int depth)1411 xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1412 {
1413 xmlDebugCtxt ctxt;
1414
1415 if (output == NULL) return;
1416 xmlCtxtDumpInitCtxt(&ctxt);
1417 ctxt.output = output;
1418 ctxt.depth = depth;
1419 xmlCtxtDumpOneNode(&ctxt, node);
1420 xmlCtxtDumpCleanCtxt(&ctxt);
1421 }
1422
1423 /**
1424 * xmlDebugDumpNode:
1425 * @output: the FILE * for the output
1426 * @node: the node
1427 * @depth: the indentation level.
1428 *
1429 * Dumps debug information for the element node, it is recursive
1430 */
1431 void
xmlDebugDumpNode(FILE * output,xmlNodePtr node,int depth)1432 xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1433 {
1434 xmlDebugCtxt ctxt;
1435
1436 if (output == NULL)
1437 output = stdout;
1438 xmlCtxtDumpInitCtxt(&ctxt);
1439 ctxt.output = output;
1440 ctxt.depth = depth;
1441 xmlCtxtDumpNode(&ctxt, node);
1442 xmlCtxtDumpCleanCtxt(&ctxt);
1443 }
1444
1445 /**
1446 * xmlDebugDumpNodeList:
1447 * @output: the FILE * for the output
1448 * @node: the node list
1449 * @depth: the indentation level.
1450 *
1451 * Dumps debug information for the list of element node, it is recursive
1452 */
1453 void
xmlDebugDumpNodeList(FILE * output,xmlNodePtr node,int depth)1454 xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1455 {
1456 xmlDebugCtxt ctxt;
1457
1458 if (output == NULL)
1459 output = stdout;
1460 xmlCtxtDumpInitCtxt(&ctxt);
1461 ctxt.output = output;
1462 ctxt.depth = depth;
1463 xmlCtxtDumpNodeList(&ctxt, node);
1464 xmlCtxtDumpCleanCtxt(&ctxt);
1465 }
1466
1467 /**
1468 * xmlDebugDumpDocumentHead:
1469 * @output: the FILE * for the output
1470 * @doc: the document
1471 *
1472 * Dumps debug information concerning the document, not recursive
1473 */
1474 void
xmlDebugDumpDocumentHead(FILE * output,xmlDocPtr doc)1475 xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1476 {
1477 xmlDebugCtxt ctxt;
1478
1479 if (output == NULL)
1480 output = stdout;
1481 xmlCtxtDumpInitCtxt(&ctxt);
1482 ctxt.options |= DUMP_TEXT_TYPE;
1483 ctxt.output = output;
1484 xmlCtxtDumpDocumentHead(&ctxt, doc);
1485 xmlCtxtDumpCleanCtxt(&ctxt);
1486 }
1487
1488 /**
1489 * xmlDebugDumpDocument:
1490 * @output: the FILE * for the output
1491 * @doc: the document
1492 *
1493 * Dumps debug information for the document, it's recursive
1494 */
1495 void
xmlDebugDumpDocument(FILE * output,xmlDocPtr doc)1496 xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1497 {
1498 xmlDebugCtxt ctxt;
1499
1500 if (output == NULL)
1501 output = stdout;
1502 xmlCtxtDumpInitCtxt(&ctxt);
1503 ctxt.options |= DUMP_TEXT_TYPE;
1504 ctxt.output = output;
1505 xmlCtxtDumpDocument(&ctxt, doc);
1506 xmlCtxtDumpCleanCtxt(&ctxt);
1507 }
1508
1509 /**
1510 * xmlDebugDumpDTD:
1511 * @output: the FILE * for the output
1512 * @dtd: the DTD
1513 *
1514 * Dumps debug information for the DTD
1515 */
1516 void
xmlDebugDumpDTD(FILE * output,xmlDtdPtr dtd)1517 xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1518 {
1519 xmlDebugCtxt ctxt;
1520
1521 if (output == NULL)
1522 output = stdout;
1523 xmlCtxtDumpInitCtxt(&ctxt);
1524 ctxt.options |= DUMP_TEXT_TYPE;
1525 ctxt.output = output;
1526 xmlCtxtDumpDTD(&ctxt, dtd);
1527 xmlCtxtDumpCleanCtxt(&ctxt);
1528 }
1529
1530 /************************************************************************
1531 * *
1532 * Public entry points for checkings *
1533 * *
1534 ************************************************************************/
1535
1536 /**
1537 * xmlDebugCheckDocument:
1538 * @output: the FILE * for the output
1539 * @doc: the document
1540 *
1541 * Check the document for potential content problems, and output
1542 * the errors to @output
1543 *
1544 * Returns the number of errors found
1545 */
1546 int
xmlDebugCheckDocument(FILE * output,xmlDocPtr doc)1547 xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1548 {
1549 xmlDebugCtxt ctxt;
1550
1551 if (output == NULL)
1552 output = stdout;
1553 xmlCtxtDumpInitCtxt(&ctxt);
1554 ctxt.output = output;
1555 ctxt.check = 1;
1556 xmlCtxtDumpDocument(&ctxt, doc);
1557 xmlCtxtDumpCleanCtxt(&ctxt);
1558 return(ctxt.errors);
1559 }
1560
1561 #endif /* LIBXML_DEBUG_ENABLED */
1562