• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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