• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * error.c: module displaying/handling XML parser errors
3  *
4  * See Copyright for the status of this software.
5  *
6  * Daniel Veillard <daniel@veillard.com>
7  */
8 
9 #define IN_LIBXML
10 #include "libxml.h"
11 
12 #include <string.h>
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #include <libxml/parser.h>
16 #include <libxml/xmlerror.h>
17 #include <libxml/xmlmemory.h>
18 
19 #include "private/error.h"
20 #include "private/globals.h"
21 #include "private/string.h"
22 
23 /**
24  * xmlIsCatastrophicError:
25  * @level:  error level
26  * @code:  error code
27  *
28  * Returns true if an error is catastrophic.
29  */
30 int
xmlIsCatastrophicError(int level,int code)31 xmlIsCatastrophicError(int level, int code) {
32     int fatal = 0;
33 
34     if (level != XML_ERR_FATAL)
35         return(0);
36 
37     switch (code) {
38         case XML_ERR_NO_MEMORY:
39         /* case XML_ERR_RESOURCE_LIMIT: */
40         case XML_ERR_SYSTEM:
41         case XML_ERR_ARGUMENT:
42         case XML_ERR_INTERNAL_ERROR:
43             fatal = 1;
44             break;
45         default:
46             if ((code >= 1500) && (code <= 1599))
47                 fatal = 1;
48             break;
49     }
50 
51     return(fatal);
52 }
53 
54 /************************************************************************
55  *									*
56  *			Error struct					*
57  *									*
58  ************************************************************************/
59 
60 static int
xmlVSetError(xmlError * err,void * ctxt,xmlNodePtr node,int domain,int code,xmlErrorLevel level,const char * file,int line,const char * str1,const char * str2,const char * str3,int int1,int col,const char * fmt,va_list ap)61 xmlVSetError(xmlError *err,
62              void *ctxt, xmlNodePtr node,
63              int domain, int code, xmlErrorLevel level,
64              const char *file, int line,
65              const char *str1, const char *str2, const char *str3,
66              int int1, int col,
67              const char *fmt, va_list ap)
68 {
69     char *message = NULL;
70     char *fileCopy = NULL;
71     char *str1Copy = NULL;
72     char *str2Copy = NULL;
73     char *str3Copy = NULL;
74 
75     if (code == XML_ERR_OK) {
76         xmlResetError(err);
77         return(0);
78     }
79 
80     /*
81      * Formatting the message
82      */
83     if (fmt == NULL) {
84         message = xmlMemStrdup("No error message provided");
85     } else {
86         xmlChar *tmp;
87         int res;
88 
89         res = xmlStrVASPrintf(&tmp, MAX_ERR_MSG_SIZE, fmt, ap);
90         if (res < 0)
91             goto err_memory;
92         message = (char *) tmp;
93     }
94     if (message == NULL)
95         goto err_memory;
96 
97     if (file != NULL) {
98         fileCopy = (char *) xmlStrdup((const xmlChar *) file);
99         if (fileCopy == NULL)
100             goto err_memory;
101     }
102     if (str1 != NULL) {
103         str1Copy = (char *) xmlStrdup((const xmlChar *) str1);
104         if (str1Copy == NULL)
105             goto err_memory;
106     }
107     if (str2 != NULL) {
108         str2Copy = (char *) xmlStrdup((const xmlChar *) str2);
109         if (str2Copy == NULL)
110             goto err_memory;
111     }
112     if (str3 != NULL) {
113         str3Copy = (char *) xmlStrdup((const xmlChar *) str3);
114         if (str3Copy == NULL)
115             goto err_memory;
116     }
117 
118     xmlResetError(err);
119 
120     err->domain = domain;
121     err->code = code;
122     err->message = message;
123     err->level = level;
124     err->file = fileCopy;
125     err->line = line;
126     err->str1 = str1Copy;
127     err->str2 = str2Copy;
128     err->str3 = str3Copy;
129     err->int1 = int1;
130     err->int2 = col;
131     err->node = node;
132     err->ctxt = ctxt;
133 
134     return(0);
135 
136 err_memory:
137     xmlFree(message);
138     xmlFree(fileCopy);
139     xmlFree(str1Copy);
140     xmlFree(str2Copy);
141     xmlFree(str3Copy);
142     return(-1);
143 }
144 
145 static int LIBXML_ATTR_FORMAT(14,15)
xmlSetError(xmlError * err,void * ctxt,xmlNodePtr node,int domain,int code,xmlErrorLevel level,const char * file,int line,const char * str1,const char * str2,const char * str3,int int1,int col,const char * fmt,...)146 xmlSetError(xmlError *err,
147             void *ctxt, xmlNodePtr node,
148             int domain, int code, xmlErrorLevel level,
149             const char *file, int line,
150             const char *str1, const char *str2, const char *str3,
151             int int1, int col,
152             const char *fmt, ...)
153 {
154     va_list ap;
155     int res;
156 
157     va_start(ap, fmt);
158     res = xmlVSetError(err, ctxt, node, domain, code, level, file, line,
159                        str1, str2, str3, int1, col, fmt, ap);
160     va_end(ap);
161 
162     return(res);
163 }
164 
165 static int
xmlVUpdateError(xmlError * err,void * ctxt,xmlNodePtr node,int domain,int code,xmlErrorLevel level,const char * file,int line,const char * str1,const char * str2,const char * str3,int int1,int col,const char * fmt,va_list ap)166 xmlVUpdateError(xmlError *err,
167                 void *ctxt, xmlNodePtr node,
168                 int domain, int code, xmlErrorLevel level,
169                 const char *file, int line,
170                 const char *str1, const char *str2, const char *str3,
171                 int int1, int col,
172                 const char *fmt, va_list ap)
173 {
174     int res;
175 
176     /*
177      * Find first element parent.
178      */
179     if (node != NULL) {
180         int i;
181 
182         for (i = 0; i < 10; i++) {
183             if ((node->type == XML_ELEMENT_NODE) ||
184                 (node->parent == NULL))
185                 break;
186             node = node->parent;
187         }
188     }
189 
190     /*
191      * Get file and line from node.
192      */
193     if (node != NULL) {
194         if ((file == NULL) && (node->doc != NULL))
195             file = (const char *) node->doc->URL;
196 
197         if (line == 0) {
198             if (node->type == XML_ELEMENT_NODE)
199                 line = node->line;
200             if ((line == 0) || (line == 65535))
201                 line = xmlGetLineNo(node);
202         }
203     }
204 
205     res = xmlVSetError(err, ctxt, node, domain, code, level, file, line,
206                        str1, str2, str3, int1, col, fmt, ap);
207 
208     return(res);
209 }
210 
211 /************************************************************************
212  *									*
213  *			Handling of out of context errors		*
214  *									*
215  ************************************************************************/
216 
217 /**
218  * xmlGenericErrorDefaultFunc:
219  * @ctx:  an error context
220  * @msg:  the message to display/transmit
221  * @...:  extra parameters for the message display
222  *
223  * Default handler for out of context error messages.
224  */
225 void
xmlGenericErrorDefaultFunc(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)226 xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
227     va_list args;
228 
229     if (xmlGenericErrorContext == NULL)
230 	xmlGenericErrorContext = (void *) stderr;
231 
232     va_start(args, msg);
233     vfprintf((FILE *)xmlGenericErrorContext, msg, args);
234     va_end(args);
235 }
236 
237 /**
238  * initGenericErrorDefaultFunc:
239  * @handler:  the handler
240  *
241  * DEPRECATED: Use xmlSetGenericErrorFunc.
242  *
243  * Set or reset (if NULL) the default handler for generic errors
244  * to the builtin error function.
245  */
246 void
initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)247 initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)
248 {
249     if (handler == NULL)
250         xmlGenericError = xmlGenericErrorDefaultFunc;
251     else
252         xmlGenericError = (*handler);
253 }
254 
255 /**
256  * xmlSetGenericErrorFunc:
257  * @ctx:  the new error handling context
258  * @handler:  the new handler function
259  *
260  * DEPRECATED: See xmlSetStructuredErrorFunc for alternatives.
261  *
262  * Set the global "generic" handler and context for error messages.
263  * The generic error handler will only receive fragments of error
264  * messages which should be concatenated or printed to a stream.
265  *
266  * If handler is NULL, use the built-in default handler which prints
267  * to stderr.
268  *
269  * Since this is a global setting, it's a good idea to reset the
270  * error handler to its default value after collecting the errors
271  * you're interested in.
272  *
273  * For multi-threaded applications, this must be set separately for
274  * each thread.
275  */
276 void
xmlSetGenericErrorFunc(void * ctx,xmlGenericErrorFunc handler)277 xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
278     xmlGenericErrorContext = ctx;
279     if (handler != NULL)
280 	xmlGenericError = handler;
281     else
282 	xmlGenericError = xmlGenericErrorDefaultFunc;
283 }
284 
285 /**
286  * xmlSetStructuredErrorFunc:
287  * @ctx:  the new error handling context
288  * @handler:  the new handler function
289  *
290  * DEPRECATED: Use a per-context error handler.
291  *
292  * It's recommended to use the per-context error handlers instead:
293  *
294  * - xmlCtxtSetErrorHandler (since 2.13.0)
295  * - xmlTextReaderSetStructuredErrorHandler
296  * - xmlXPathSetErrorHandler (since 2.13.0)
297  * - xmlXIncludeSetErrorHandler (since 2.13.0)
298  * - xmlSchemaSetParserStructuredErrors
299  * - xmlSchemaSetValidStructuredErrors
300  * - xmlRelaxNGSetParserStructuredErrors
301  * - xmlRelaxNGSetValidStructuredErrors
302  *
303  * Set the global "structured" handler and context for error messages.
304  * If handler is NULL, the error handler is deactivated.
305  *
306  * The structured error handler takes precedence over "generic"
307  * handlers, even per-context generic handlers.
308  *
309  * Since this is a global setting, it's a good idea to deactivate the
310  * error handler after collecting the errors you're interested in.
311  *
312  * For multi-threaded applications, this must be set separately for
313  * each thread.
314  */
315 void
xmlSetStructuredErrorFunc(void * ctx,xmlStructuredErrorFunc handler)316 xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
317     xmlStructuredErrorContext = ctx;
318     xmlStructuredError = handler;
319 }
320 
321 /************************************************************************
322  *									*
323  *			Handling of parsing errors			*
324  *									*
325  ************************************************************************/
326 
327 /**
328  * xmlParserPrintFileInfo:
329  * @input:  an xmlParserInputPtr input
330  *
331  * DEPRECATED: Use xmlFormatError.
332  *
333  * Displays the associated file and line information for the current input
334  */
335 
336 void
xmlParserPrintFileInfo(xmlParserInputPtr input)337 xmlParserPrintFileInfo(xmlParserInputPtr input) {
338     if (input != NULL) {
339 	if (input->filename)
340 	    xmlGenericError(xmlGenericErrorContext,
341 		    "%s:%d: ", input->filename,
342 		    input->line);
343 	else
344 	    xmlGenericError(xmlGenericErrorContext,
345 		    "Entity: line %d: ", input->line);
346     }
347 }
348 
349 /**
350  * xmlParserPrintFileContextInternal:
351  * @input:  an xmlParserInputPtr input
352  *
353  * Displays current context within the input content for error tracking
354  */
355 
356 static void
xmlParserPrintFileContextInternal(xmlParserInputPtr input,xmlGenericErrorFunc channel,void * data)357 xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
358 		xmlGenericErrorFunc channel, void *data ) {
359     const xmlChar *cur, *base, *start;
360     unsigned int n, col;	/* GCC warns if signed, because compared with sizeof() */
361     xmlChar  content[81]; /* space for 80 chars + line terminator */
362     xmlChar *ctnt;
363 
364     if ((input == NULL) || (input->cur == NULL))
365         return;
366 
367     cur = input->cur;
368     base = input->base;
369     /* skip backwards over any end-of-lines */
370     while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
371 	cur--;
372     }
373     n = 0;
374     /* search backwards for beginning-of-line (to max buff size) */
375     while ((n < sizeof(content) - 1) && (cur > base) &&
376 	   (*cur != '\n') && (*cur != '\r')) {
377         cur--;
378         n++;
379     }
380     if ((n > 0) && ((*cur == '\n') || (*cur == '\r'))) {
381         cur++;
382     } else {
383         /* skip over continuation bytes */
384         while ((cur < input->cur) && ((*cur & 0xC0) == 0x80))
385             cur++;
386     }
387     /* calculate the error position in terms of the current position */
388     col = input->cur - cur;
389     /* search forward for end-of-line (to max buff size) */
390     n = 0;
391     start = cur;
392     /* copy selected text to our buffer */
393     while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) {
394         int len = input->end - cur;
395         int c = xmlGetUTF8Char(cur, &len);
396 
397         if ((c < 0) || (n + len > sizeof(content)-1))
398             break;
399         cur += len;
400 	n += len;
401     }
402     memcpy(content, start, n);
403     content[n] = 0;
404     /* print out the selected text */
405     channel(data ,"%s\n", content);
406     /* create blank line with problem pointer */
407     n = 0;
408     ctnt = content;
409     /* (leave buffer space for pointer + line terminator) */
410     while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
411 	if (*(ctnt) != '\t')
412 	    *(ctnt) = ' ';
413 	ctnt++;
414     }
415     *ctnt++ = '^';
416     *ctnt = 0;
417     channel(data ,"%s\n", content);
418 }
419 
420 /**
421  * xmlParserPrintFileContext:
422  * @input:  an xmlParserInputPtr input
423  *
424  * DEPRECATED: Use xmlFormatError.
425  *
426  * Displays current context within the input content for error tracking
427  */
428 void
xmlParserPrintFileContext(xmlParserInputPtr input)429 xmlParserPrintFileContext(xmlParserInputPtr input) {
430    xmlParserPrintFileContextInternal(input, xmlGenericError,
431                                      xmlGenericErrorContext);
432 }
433 
434 /**
435  * xmlFormatError:
436  * @err:  the error
437  * @channel:  callback
438  * @data:  user data for callback
439  *
440  * Report a formatted error to a printf-like callback.
441  *
442  * This can result in a verbose multi-line report including additional
443  * information from the parser context.
444  *
445  * Available since 2.13.0.
446  */
447 void
xmlFormatError(const xmlError * err,xmlGenericErrorFunc channel,void * data)448 xmlFormatError(const xmlError *err, xmlGenericErrorFunc channel, void *data)
449 {
450     const char *message;
451     const char *file;
452     int line;
453     int code;
454     int domain;
455     const xmlChar *name = NULL;
456     xmlNodePtr node;
457     xmlErrorLevel level;
458     xmlParserCtxtPtr ctxt = NULL;
459     xmlParserInputPtr input = NULL;
460     xmlParserInputPtr cur = NULL;
461 
462     if ((err == NULL) || (channel == NULL))
463         return;
464 
465     message = err->message;
466     file = err->file;
467     line = err->line;
468     code = err->code;
469     domain = err->domain;
470     level = err->level;
471     node = err->node;
472 
473     if (code == XML_ERR_OK)
474         return;
475 
476     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
477         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
478 	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
479 	ctxt = err->ctxt;
480     }
481 
482     if ((node != NULL) && (node->type == XML_ELEMENT_NODE) &&
483         (domain != XML_FROM_SCHEMASV))
484         name = node->name;
485 
486     /*
487      * Maintain the compatibility with the legacy error handling
488      */
489     if ((ctxt != NULL) && (ctxt->input != NULL)) {
490         input = ctxt->input;
491         if ((input->filename == NULL) &&
492             (ctxt->inputNr > 1)) {
493             cur = input;
494             input = ctxt->inputTab[ctxt->inputNr - 2];
495         }
496         if (input->filename)
497             channel(data, "%s:%d: ", input->filename, input->line);
498         else if ((line != 0) && (domain == XML_FROM_PARSER))
499             channel(data, "Entity: line %d: ", input->line);
500     } else {
501         if (file != NULL)
502             channel(data, "%s:%d: ", file, line);
503         else if ((line != 0) &&
504 	         ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)||
505 		  (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) ||
506 		  (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV)))
507             channel(data, "Entity: line %d: ", line);
508     }
509     if (name != NULL) {
510         channel(data, "element %s: ", name);
511     }
512     switch (domain) {
513         case XML_FROM_PARSER:
514             channel(data, "parser ");
515             break;
516         case XML_FROM_NAMESPACE:
517             channel(data, "namespace ");
518             break;
519         case XML_FROM_DTD:
520         case XML_FROM_VALID:
521             channel(data, "validity ");
522             break;
523         case XML_FROM_HTML:
524             channel(data, "HTML parser ");
525             break;
526         case XML_FROM_MEMORY:
527             channel(data, "memory ");
528             break;
529         case XML_FROM_OUTPUT:
530             channel(data, "output ");
531             break;
532         case XML_FROM_IO:
533             channel(data, "I/O ");
534             break;
535         case XML_FROM_XINCLUDE:
536             channel(data, "XInclude ");
537             break;
538         case XML_FROM_XPATH:
539             channel(data, "XPath ");
540             break;
541         case XML_FROM_XPOINTER:
542             channel(data, "parser ");
543             break;
544         case XML_FROM_REGEXP:
545             channel(data, "regexp ");
546             break;
547         case XML_FROM_MODULE:
548             channel(data, "module ");
549             break;
550         case XML_FROM_SCHEMASV:
551             channel(data, "Schemas validity ");
552             break;
553         case XML_FROM_SCHEMASP:
554             channel(data, "Schemas parser ");
555             break;
556         case XML_FROM_RELAXNGP:
557             channel(data, "Relax-NG parser ");
558             break;
559         case XML_FROM_RELAXNGV:
560             channel(data, "Relax-NG validity ");
561             break;
562         case XML_FROM_CATALOG:
563             channel(data, "Catalog ");
564             break;
565         case XML_FROM_C14N:
566             channel(data, "C14N ");
567             break;
568         case XML_FROM_XSLT:
569             channel(data, "XSLT ");
570             break;
571         case XML_FROM_I18N:
572             channel(data, "encoding ");
573             break;
574         case XML_FROM_SCHEMATRONV:
575             channel(data, "schematron ");
576             break;
577         case XML_FROM_BUFFER:
578             channel(data, "internal buffer ");
579             break;
580         case XML_FROM_URI:
581             channel(data, "URI ");
582             break;
583         default:
584             break;
585     }
586     switch (level) {
587         case XML_ERR_NONE:
588             channel(data, ": ");
589             break;
590         case XML_ERR_WARNING:
591             channel(data, "warning : ");
592             break;
593         case XML_ERR_ERROR:
594             channel(data, "error : ");
595             break;
596         case XML_ERR_FATAL:
597             channel(data, "error : ");
598             break;
599     }
600     if (message != NULL) {
601         int len;
602 	len = xmlStrlen((const xmlChar *) message);
603 	if ((len > 0) && (message[len - 1] != '\n'))
604 	    channel(data, "%s\n", message);
605 	else
606 	    channel(data, "%s", message);
607     } else {
608         channel(data, "%s\n", "No error message provided");
609     }
610 
611     if (ctxt != NULL) {
612         if ((input != NULL) &&
613             ((input->buf == NULL) || (input->buf->encoder == NULL)) &&
614             (code == XML_ERR_INVALID_ENCODING) &&
615             (input->cur < input->end)) {
616             int i;
617 
618             channel(data, "Bytes:");
619             for (i = 0; i < 4; i++) {
620                 if (input->cur + i >= input->end)
621                     break;
622                 channel(data, " 0x%02X", input->cur[i]);
623             }
624             channel(data, "\n");
625         }
626 
627         xmlParserPrintFileContextInternal(input, channel, data);
628 
629         if (cur != NULL) {
630             if (cur->filename)
631                 channel(data, "%s:%d: \n", cur->filename, cur->line);
632             else if ((line != 0) && (domain == XML_FROM_PARSER))
633                 channel(data, "Entity: line %d: \n", cur->line);
634             xmlParserPrintFileContextInternal(cur, channel, data);
635         }
636     }
637     if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
638         (err->int1 < 100) &&
639 	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
640 	xmlChar buf[150];
641 	int i;
642 
643 	channel(data, "%s\n", err->str1);
644 	for (i=0;i < err->int1;i++)
645 	     buf[i] = ' ';
646 	buf[i++] = '^';
647 	buf[i] = 0;
648 	channel(data, "%s\n", buf);
649     }
650 }
651 
652 /**
653  * xmlRaiseMemoryError:
654  * @schannel: the structured callback channel
655  * @channel: the old callback channel
656  * @data: the callback data
657  * @domain: the domain for the error
658  * @error: optional error struct to be filled
659  *
660  * Update the global and optional error structure, then forward the
661  * error to an error handler.
662  *
663  * This function doesn't make memory allocations which are likely
664  * to fail after an OOM error.
665  */
666 void
xmlRaiseMemoryError(xmlStructuredErrorFunc schannel,xmlGenericErrorFunc channel,void * data,int domain,xmlError * error)667 xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel,
668                     void *data, int domain, xmlError *error)
669 {
670     xmlError *lastError = xmlGetLastErrorInternal();
671 
672     xmlResetLastError();
673     lastError->domain = domain;
674     lastError->code = XML_ERR_NO_MEMORY;
675     lastError->level = XML_ERR_FATAL;
676 
677     if (error != NULL) {
678         xmlResetError(error);
679         error->domain = domain;
680         error->code = XML_ERR_NO_MEMORY;
681         error->level = XML_ERR_FATAL;
682     }
683 
684     if (schannel != NULL) {
685         schannel(data, lastError);
686     } else if (xmlStructuredError != NULL) {
687         xmlStructuredError(xmlStructuredErrorContext, lastError);
688     } else if (channel != NULL) {
689         channel(data, "libxml2: out of memory\n");
690     }
691 }
692 
693 /**
694  * xmlVRaiseError:
695  * @schannel: the structured callback channel
696  * @channel: the old callback channel
697  * @data: the callback data
698  * @ctx: the parser context or NULL
699  * @node: the current node or NULL
700  * @domain: the domain for the error
701  * @code: the code for the error
702  * @level: the xmlErrorLevel for the error
703  * @file: the file source of the error (or NULL)
704  * @line: the line of the error or 0 if N/A
705  * @str1: extra string info
706  * @str2: extra string info
707  * @str3: extra string info
708  * @int1: extra int info
709  * @col: column number of the error or 0 if N/A
710  * @msg:  the message to display/transmit
711  * @ap:  extra parameters for the message display
712  *
713  * Update the appropriate global or contextual error structure,
714  * then forward the error message down the parser or generic
715  * error callback handler
716  *
717  * Returns 0 on success, -1 if a memory allocation failed.
718  */
719 int
xmlVRaiseError(xmlStructuredErrorFunc schannel,xmlGenericErrorFunc channel,void * data,void * ctx,xmlNode * node,int domain,int code,xmlErrorLevel level,const char * file,int line,const char * str1,const char * str2,const char * str3,int int1,int col,const char * msg,va_list ap)720 xmlVRaiseError(xmlStructuredErrorFunc schannel,
721                xmlGenericErrorFunc channel, void *data, void *ctx,
722                xmlNode *node, int domain, int code, xmlErrorLevel level,
723                const char *file, int line, const char *str1,
724                const char *str2, const char *str3, int int1, int col,
725                const char *msg, va_list ap)
726 {
727     xmlParserCtxtPtr ctxt = NULL;
728     /* xmlLastError is a macro retrieving the per-thread global. */
729     xmlErrorPtr lastError = xmlGetLastErrorInternal();
730     xmlErrorPtr to = lastError;
731 
732     if (code == XML_ERR_OK)
733         return(0);
734 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
735     if (code == XML_ERR_INTERNAL_ERROR)
736         xmlAbort("Unexpected error: %d\n", code);
737 #endif
738     if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
739         return(0);
740 
741     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
742         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
743 	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
744 	ctxt = (xmlParserCtxtPtr) ctx;
745 
746         if (ctxt != NULL)
747             to = &ctxt->lastError;
748     }
749 
750     if (xmlVUpdateError(to, ctxt, node, domain, code, level, file, line,
751                         str1, str2, str3, int1, col, msg, ap))
752         return(-1);
753 
754     if (to != lastError) {
755         if (xmlCopyError(to, lastError) < 0)
756             return(-1);
757     }
758 
759     if (schannel != NULL) {
760 	schannel(data, to);
761     } else if (xmlStructuredError != NULL) {
762         xmlStructuredError(xmlStructuredErrorContext, to);
763     } else if (channel != NULL) {
764         /* Don't invoke legacy error handlers */
765         if ((channel == xmlGenericErrorDefaultFunc) ||
766             (channel == xmlParserError) ||
767             (channel == xmlParserWarning) ||
768             (channel == xmlParserValidityError) ||
769             (channel == xmlParserValidityWarning))
770             xmlFormatError(to, xmlGenericError, xmlGenericErrorContext);
771         else
772 	    channel(data, "%s", to->message);
773     }
774 
775     return(0);
776 }
777 
778 /**
779  * xmlRaiseError:
780  * @schannel: the structured callback channel
781  * @channel: the old callback channel
782  * @data: the callback data
783  * @ctx: the parser context or NULL
784  * @node: the node or NULL
785  * @domain: the domain for the error
786  * @code: the code for the error
787  * @level: the xmlErrorLevel for the error
788  * @file: the file source of the error (or NULL)
789  * @line: the line of the error or 0 if N/A
790  * @str1: extra string info
791  * @str2: extra string info
792  * @str3: extra string info
793  * @int1: extra int info
794  * @col: column number of the error or 0 if N/A
795  * @msg:  the message to display/transmit
796  * @...:  extra parameters for the message display
797  *
798  * Update the appropriate global or contextual error structure,
799  * then forward the error message down the parser or generic
800  * error callback handler
801  *
802  * Returns 0 on success, -1 if a memory allocation failed.
803  */
804 int
xmlRaiseError(xmlStructuredErrorFunc schannel,xmlGenericErrorFunc channel,void * data,void * ctx,xmlNode * node,int domain,int code,xmlErrorLevel level,const char * file,int line,const char * str1,const char * str2,const char * str3,int int1,int col,const char * msg,...)805 xmlRaiseError(xmlStructuredErrorFunc schannel,
806               xmlGenericErrorFunc channel, void *data, void *ctx,
807               xmlNode *node, int domain, int code, xmlErrorLevel level,
808               const char *file, int line, const char *str1,
809               const char *str2, const char *str3, int int1, int col,
810               const char *msg, ...)
811 {
812     va_list ap;
813     int res;
814 
815     va_start(ap, msg);
816     res = xmlVRaiseError(schannel, channel, data, ctx, node, domain, code,
817                          level, file, line, str1, str2, str3, int1, col, msg,
818                          ap);
819     va_end(ap);
820 
821     return(res);
822 }
823 
824 static void
xmlVFormatLegacyError(void * ctx,const char * level,const char * fmt,va_list ap)825 xmlVFormatLegacyError(void *ctx, const char *level,
826                       const char *fmt, va_list ap) {
827     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
828     xmlParserInputPtr input = NULL;
829     xmlParserInputPtr cur = NULL;
830     xmlChar *str = NULL;
831 
832     if (ctxt != NULL) {
833 	input = ctxt->input;
834 	if ((input != NULL) && (input->filename == NULL) &&
835 	    (ctxt->inputNr > 1)) {
836 	    cur = input;
837 	    input = ctxt->inputTab[ctxt->inputNr - 2];
838 	}
839 	xmlParserPrintFileInfo(input);
840     }
841 
842     xmlGenericError(xmlGenericErrorContext, "%s: ", level);
843 
844     xmlStrVASPrintf(&str, MAX_ERR_MSG_SIZE, fmt, ap);
845     if (str != NULL) {
846         xmlGenericError(xmlGenericErrorContext, "%s", (char *) str);
847 	xmlFree(str);
848     }
849 
850     if (ctxt != NULL) {
851 	xmlParserPrintFileContext(input);
852 	if (cur != NULL) {
853 	    xmlParserPrintFileInfo(cur);
854 	    xmlGenericError(xmlGenericErrorContext, "\n");
855 	    xmlParserPrintFileContext(cur);
856 	}
857     }
858 }
859 
860 /**
861  * xmlParserError:
862  * @ctx:  an XML parser context
863  * @msg:  the message to display/transmit
864  * @...:  extra parameters for the message display
865  *
866  * Display and format an error messages, gives file, line, position and
867  * extra parameters.
868  */
869 void
xmlParserError(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)870 xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
871 {
872     va_list ap;
873 
874     va_start(ap, msg);
875     xmlVFormatLegacyError(ctx, "error", msg, ap);
876     va_end(ap);
877 }
878 
879 /**
880  * xmlParserWarning:
881  * @ctx:  an XML parser context
882  * @msg:  the message to display/transmit
883  * @...:  extra parameters for the message display
884  *
885  * Display and format a warning messages, gives file, line, position and
886  * extra parameters.
887  */
888 void
xmlParserWarning(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)889 xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
890 {
891     va_list ap;
892 
893     va_start(ap, msg);
894     xmlVFormatLegacyError(ctx, "warning", msg, ap);
895     va_end(ap);
896 }
897 
898 /**
899  * xmlParserValidityError:
900  * @ctx:  an XML parser context
901  * @msg:  the message to display/transmit
902  * @...:  extra parameters for the message display
903  *
904  * Display and format an validity error messages, gives file,
905  * line, position and extra parameters.
906  */
907 void
xmlParserValidityError(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)908 xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
909 {
910     va_list ap;
911 
912     va_start(ap, msg);
913     xmlVFormatLegacyError(ctx, "validity error", msg, ap);
914     va_end(ap);
915 }
916 
917 /**
918  * xmlParserValidityWarning:
919  * @ctx:  an XML parser context
920  * @msg:  the message to display/transmit
921  * @...:  extra parameters for the message display
922  *
923  * Display and format a validity warning messages, gives file, line,
924  * position and extra parameters.
925  */
926 void
xmlParserValidityWarning(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)927 xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
928 {
929     va_list ap;
930 
931     va_start(ap, msg);
932     xmlVFormatLegacyError(ctx, "validity warning", msg, ap);
933     va_end(ap);
934 }
935 
936 
937 /************************************************************************
938  *									*
939  *			Extended Error Handling				*
940  *									*
941  ************************************************************************/
942 
943 /**
944  * xmlGetLastError:
945  *
946  * Get the last global error registered. This is per thread if compiled
947  * with thread support.
948  *
949  * Returns a pointer to the error
950  */
951 const xmlError *
xmlGetLastError(void)952 xmlGetLastError(void)
953 {
954     const xmlError *error = xmlGetLastErrorInternal();
955 
956     if (error->code == XML_ERR_OK)
957         return(NULL);
958     return(error);
959 }
960 
961 /**
962  * xmlResetError:
963  * @err: pointer to the error.
964  *
965  * Cleanup the error.
966  */
967 void
xmlResetError(xmlErrorPtr err)968 xmlResetError(xmlErrorPtr err)
969 {
970     if (err == NULL)
971         return;
972     if (err->code == XML_ERR_OK)
973         return;
974     if (err->message != NULL)
975         xmlFree(err->message);
976     if (err->file != NULL)
977         xmlFree(err->file);
978     if (err->str1 != NULL)
979         xmlFree(err->str1);
980     if (err->str2 != NULL)
981         xmlFree(err->str2);
982     if (err->str3 != NULL)
983         xmlFree(err->str3);
984     memset(err, 0, sizeof(xmlError));
985     err->code = XML_ERR_OK;
986 }
987 
988 /**
989  * xmlResetLastError:
990  *
991  * Cleanup the last global error registered. For parsing error
992  * this does not change the well-formedness result.
993  */
994 void
xmlResetLastError(void)995 xmlResetLastError(void)
996 {
997     xmlError *error = xmlGetLastErrorInternal();
998 
999     if (error->code != XML_ERR_OK)
1000         xmlResetError(error);
1001 }
1002 
1003 /**
1004  * xmlCopyError:
1005  * @from:  a source error
1006  * @to:  a target error
1007  *
1008  * Save the original error to the new place.
1009  *
1010  * Returns 0 in case of success and -1 in case of error.
1011  */
1012 int
xmlCopyError(const xmlError * from,xmlErrorPtr to)1013 xmlCopyError(const xmlError *from, xmlErrorPtr to) {
1014     const char *fmt = NULL;
1015 
1016     if ((from == NULL) || (to == NULL))
1017         return(-1);
1018 
1019     if (from->message != NULL)
1020         fmt = "%s";
1021 
1022     return(xmlSetError(to, from->ctxt, from->node,
1023                        from->domain, from->code, from->level,
1024                        from->file, from->line,
1025                        from->str1, from->str2, from->str3,
1026                        from->int1, from->int2,
1027                        fmt, from->message));
1028 }
1029 
1030 /**
1031  * xmlErrString:
1032  * @code:  an xmlParserErrors code
1033  *
1034  * Returns an error message for a code.
1035  */
1036 const char *
xmlErrString(xmlParserErrors code)1037 xmlErrString(xmlParserErrors code) {
1038     const char *errmsg;
1039 
1040     switch (code) {
1041         case XML_ERR_INVALID_HEX_CHARREF:
1042             errmsg = "CharRef: invalid hexadecimal value";
1043             break;
1044         case XML_ERR_INVALID_DEC_CHARREF:
1045             errmsg = "CharRef: invalid decimal value";
1046             break;
1047         case XML_ERR_INVALID_CHARREF:
1048             errmsg = "CharRef: invalid value";
1049             break;
1050         case XML_ERR_INTERNAL_ERROR:
1051             errmsg = "internal error";
1052             break;
1053         case XML_ERR_PEREF_AT_EOF:
1054             errmsg = "PEReference at end of document";
1055             break;
1056         case XML_ERR_PEREF_IN_PROLOG:
1057             errmsg = "PEReference in prolog";
1058             break;
1059         case XML_ERR_PEREF_IN_EPILOG:
1060             errmsg = "PEReference in epilog";
1061             break;
1062         case XML_ERR_PEREF_NO_NAME:
1063             errmsg = "PEReference: no name";
1064             break;
1065         case XML_ERR_PEREF_SEMICOL_MISSING:
1066             errmsg = "PEReference: expecting ';'";
1067             break;
1068         case XML_ERR_ENTITY_LOOP:
1069             errmsg = "Detected an entity reference loop";
1070             break;
1071         case XML_ERR_ENTITY_NOT_STARTED:
1072             errmsg = "EntityValue: \" or ' expected";
1073             break;
1074         case XML_ERR_ENTITY_PE_INTERNAL:
1075             errmsg = "PEReferences forbidden in internal subset";
1076             break;
1077         case XML_ERR_ENTITY_NOT_FINISHED:
1078             errmsg = "EntityValue: \" or ' expected";
1079             break;
1080         case XML_ERR_ATTRIBUTE_NOT_STARTED:
1081             errmsg = "AttValue: \" or ' expected";
1082             break;
1083         case XML_ERR_LT_IN_ATTRIBUTE:
1084             errmsg = "Unescaped '<' not allowed in attributes values";
1085             break;
1086         case XML_ERR_LITERAL_NOT_STARTED:
1087             errmsg = "SystemLiteral \" or ' expected";
1088             break;
1089         case XML_ERR_LITERAL_NOT_FINISHED:
1090             errmsg = "Unfinished System or Public ID \" or ' expected";
1091             break;
1092         case XML_ERR_MISPLACED_CDATA_END:
1093             errmsg = "Sequence ']]>' not allowed in content";
1094             break;
1095         case XML_ERR_URI_REQUIRED:
1096             errmsg = "SYSTEM or PUBLIC, the URI is missing";
1097             break;
1098         case XML_ERR_PUBID_REQUIRED:
1099             errmsg = "PUBLIC, the Public Identifier is missing";
1100             break;
1101         case XML_ERR_HYPHEN_IN_COMMENT:
1102             errmsg = "Comment must not contain '--' (double-hyphen)";
1103             break;
1104         case XML_ERR_PI_NOT_STARTED:
1105             errmsg = "xmlParsePI : no target name";
1106             break;
1107         case XML_ERR_RESERVED_XML_NAME:
1108             errmsg = "Invalid PI name";
1109             break;
1110         case XML_ERR_NOTATION_NOT_STARTED:
1111             errmsg = "NOTATION: Name expected here";
1112             break;
1113         case XML_ERR_NOTATION_NOT_FINISHED:
1114             errmsg = "'>' required to close NOTATION declaration";
1115             break;
1116         case XML_ERR_VALUE_REQUIRED:
1117             errmsg = "Entity value required";
1118             break;
1119         case XML_ERR_URI_FRAGMENT:
1120             errmsg = "Fragment not allowed";
1121             break;
1122         case XML_ERR_ATTLIST_NOT_STARTED:
1123             errmsg = "'(' required to start ATTLIST enumeration";
1124             break;
1125         case XML_ERR_NMTOKEN_REQUIRED:
1126             errmsg = "NmToken expected in ATTLIST enumeration";
1127             break;
1128         case XML_ERR_ATTLIST_NOT_FINISHED:
1129             errmsg = "')' required to finish ATTLIST enumeration";
1130             break;
1131         case XML_ERR_MIXED_NOT_STARTED:
1132             errmsg = "MixedContentDecl : '|' or ')*' expected";
1133             break;
1134         case XML_ERR_PCDATA_REQUIRED:
1135             errmsg = "MixedContentDecl : '#PCDATA' expected";
1136             break;
1137         case XML_ERR_ELEMCONTENT_NOT_STARTED:
1138             errmsg = "ContentDecl : Name or '(' expected";
1139             break;
1140         case XML_ERR_ELEMCONTENT_NOT_FINISHED:
1141             errmsg = "ContentDecl : ',' '|' or ')' expected";
1142             break;
1143         case XML_ERR_PEREF_IN_INT_SUBSET:
1144             errmsg =
1145                 "PEReference: forbidden within markup decl in internal subset";
1146             break;
1147         case XML_ERR_GT_REQUIRED:
1148             errmsg = "expected '>'";
1149             break;
1150         case XML_ERR_CONDSEC_INVALID:
1151             errmsg = "XML conditional section '[' expected";
1152             break;
1153         case XML_ERR_INT_SUBSET_NOT_FINISHED:
1154             errmsg = "Content error in the internal subset";
1155             break;
1156         case XML_ERR_EXT_SUBSET_NOT_FINISHED:
1157             errmsg = "Content error in the external subset";
1158             break;
1159         case XML_ERR_CONDSEC_INVALID_KEYWORD:
1160             errmsg =
1161                 "conditional section INCLUDE or IGNORE keyword expected";
1162             break;
1163         case XML_ERR_CONDSEC_NOT_FINISHED:
1164             errmsg = "XML conditional section not closed";
1165             break;
1166         case XML_ERR_XMLDECL_NOT_STARTED:
1167             errmsg = "Text declaration '<?xml' required";
1168             break;
1169         case XML_ERR_XMLDECL_NOT_FINISHED:
1170             errmsg = "parsing XML declaration: '?>' expected";
1171             break;
1172         case XML_ERR_EXT_ENTITY_STANDALONE:
1173             errmsg = "external parsed entities cannot be standalone";
1174             break;
1175         case XML_ERR_ENTITYREF_SEMICOL_MISSING:
1176             errmsg = "EntityRef: expecting ';'";
1177             break;
1178         case XML_ERR_DOCTYPE_NOT_FINISHED:
1179             errmsg = "DOCTYPE improperly terminated";
1180             break;
1181         case XML_ERR_LTSLASH_REQUIRED:
1182             errmsg = "EndTag: '</' not found";
1183             break;
1184         case XML_ERR_EQUAL_REQUIRED:
1185             errmsg = "expected '='";
1186             break;
1187         case XML_ERR_STRING_NOT_CLOSED:
1188             errmsg = "String not closed expecting \" or '";
1189             break;
1190         case XML_ERR_STRING_NOT_STARTED:
1191             errmsg = "String not started expecting ' or \"";
1192             break;
1193         case XML_ERR_ENCODING_NAME:
1194             errmsg = "Invalid XML encoding name";
1195             break;
1196         case XML_ERR_STANDALONE_VALUE:
1197             errmsg = "standalone accepts only 'yes' or 'no'";
1198             break;
1199         case XML_ERR_DOCUMENT_EMPTY:
1200             errmsg = "Document is empty";
1201             break;
1202         case XML_ERR_DOCUMENT_END:
1203             errmsg = "Extra content at the end of the document";
1204             break;
1205         case XML_ERR_NOT_WELL_BALANCED:
1206             errmsg = "chunk is not well balanced";
1207             break;
1208         case XML_ERR_EXTRA_CONTENT:
1209             errmsg = "extra content at the end of well balanced chunk";
1210             break;
1211         case XML_ERR_VERSION_MISSING:
1212             errmsg = "Malformed declaration expecting version";
1213             break;
1214         case XML_ERR_NAME_TOO_LONG:
1215             errmsg = "Name too long";
1216             break;
1217         case XML_ERR_INVALID_ENCODING:
1218             errmsg = "Invalid bytes in character encoding";
1219             break;
1220         case XML_ERR_RESOURCE_LIMIT:
1221             errmsg = "Resource limit exceeded";
1222             break;
1223         case XML_ERR_ARGUMENT:
1224             errmsg = "Invalid argument";
1225             break;
1226         case XML_ERR_SYSTEM:
1227             errmsg = "Out of system resources";
1228             break;
1229         case XML_ERR_REDECL_PREDEF_ENTITY:
1230             errmsg = "Invalid redeclaration of predefined entity";
1231             break;
1232         case XML_ERR_UNSUPPORTED_ENCODING:
1233             errmsg = "Unsupported encoding";
1234             break;
1235         case XML_ERR_INVALID_CHAR:
1236             errmsg = "Invalid character";
1237             break;
1238 
1239         case XML_IO_UNKNOWN:
1240             errmsg = "Unknown IO error"; break;
1241         case XML_IO_EACCES:
1242             errmsg = "Permission denied"; break;
1243         case XML_IO_EAGAIN:
1244             errmsg = "Resource temporarily unavailable"; break;
1245         case XML_IO_EBADF:
1246             errmsg = "Bad file descriptor"; break;
1247         case XML_IO_EBADMSG:
1248             errmsg = "Bad message"; break;
1249         case XML_IO_EBUSY:
1250             errmsg = "Resource busy"; break;
1251         case XML_IO_ECANCELED:
1252             errmsg = "Operation canceled"; break;
1253         case XML_IO_ECHILD:
1254             errmsg = "No child processes"; break;
1255         case XML_IO_EDEADLK:
1256             errmsg = "Resource deadlock avoided"; break;
1257         case XML_IO_EDOM:
1258             errmsg = "Domain error"; break;
1259         case XML_IO_EEXIST:
1260             errmsg = "File exists"; break;
1261         case XML_IO_EFAULT:
1262             errmsg = "Bad address"; break;
1263         case XML_IO_EFBIG:
1264             errmsg = "File too large"; break;
1265         case XML_IO_EINPROGRESS:
1266             errmsg = "Operation in progress"; break;
1267         case XML_IO_EINTR:
1268             errmsg = "Interrupted function call"; break;
1269         case XML_IO_EINVAL:
1270             errmsg = "Invalid argument"; break;
1271         case XML_IO_EIO:
1272             errmsg = "Input/output error"; break;
1273         case XML_IO_EISDIR:
1274             errmsg = "Is a directory"; break;
1275         case XML_IO_EMFILE:
1276             errmsg = "Too many open files"; break;
1277         case XML_IO_EMLINK:
1278             errmsg = "Too many links"; break;
1279         case XML_IO_EMSGSIZE:
1280             errmsg = "Inappropriate message buffer length"; break;
1281         case XML_IO_ENAMETOOLONG:
1282             errmsg = "Filename too long"; break;
1283         case XML_IO_ENFILE:
1284             errmsg = "Too many open files in system"; break;
1285         case XML_IO_ENODEV:
1286             errmsg = "No such device"; break;
1287         case XML_IO_ENOENT:
1288             errmsg = "No such file or directory"; break;
1289         case XML_IO_ENOEXEC:
1290             errmsg = "Exec format error"; break;
1291         case XML_IO_ENOLCK:
1292             errmsg = "No locks available"; break;
1293         case XML_IO_ENOMEM:
1294             errmsg = "Not enough space"; break;
1295         case XML_IO_ENOSPC:
1296             errmsg = "No space left on device"; break;
1297         case XML_IO_ENOSYS:
1298             errmsg = "Function not implemented"; break;
1299         case XML_IO_ENOTDIR:
1300             errmsg = "Not a directory"; break;
1301         case XML_IO_ENOTEMPTY:
1302             errmsg = "Directory not empty"; break;
1303         case XML_IO_ENOTSUP:
1304             errmsg = "Not supported"; break;
1305         case XML_IO_ENOTTY:
1306             errmsg = "Inappropriate I/O control operation"; break;
1307         case XML_IO_ENXIO:
1308             errmsg = "No such device or address"; break;
1309         case XML_IO_EPERM:
1310             errmsg = "Operation not permitted"; break;
1311         case XML_IO_EPIPE:
1312             errmsg = "Broken pipe"; break;
1313         case XML_IO_ERANGE:
1314             errmsg = "Result too large"; break;
1315         case XML_IO_EROFS:
1316             errmsg = "Read-only file system"; break;
1317         case XML_IO_ESPIPE:
1318             errmsg = "Invalid seek"; break;
1319         case XML_IO_ESRCH:
1320             errmsg = "No such process"; break;
1321         case XML_IO_ETIMEDOUT:
1322             errmsg = "Operation timed out"; break;
1323         case XML_IO_EXDEV:
1324             errmsg = "Improper link"; break;
1325         case XML_IO_NETWORK_ATTEMPT:
1326             errmsg = "Attempt to load network entity"; break;
1327         case XML_IO_ENCODER:
1328             errmsg = "encoder error"; break;
1329         case XML_IO_FLUSH:
1330             errmsg = "flush error"; break;
1331         case XML_IO_WRITE:
1332             errmsg = "write error"; break;
1333         case XML_IO_NO_INPUT:
1334             errmsg = "no input"; break;
1335         case XML_IO_BUFFER_FULL:
1336             errmsg = "buffer full"; break;
1337         case XML_IO_LOAD_ERROR:
1338             errmsg = "loading error"; break;
1339         case XML_IO_ENOTSOCK:
1340             errmsg = "not a socket"; break;
1341         case XML_IO_EISCONN:
1342             errmsg = "already connected"; break;
1343         case XML_IO_ECONNREFUSED:
1344             errmsg = "connection refused"; break;
1345         case XML_IO_ENETUNREACH:
1346             errmsg = "unreachable network"; break;
1347         case XML_IO_EADDRINUSE:
1348             errmsg = "address in use"; break;
1349         case XML_IO_EALREADY:
1350             errmsg = "already in use"; break;
1351         case XML_IO_EAFNOSUPPORT:
1352             errmsg = "unknown address family"; break;
1353         case XML_IO_UNSUPPORTED_PROTOCOL:
1354             errmsg = "unsupported protocol"; break;
1355 
1356         default:
1357             errmsg = "Unregistered error message";
1358     }
1359 
1360     return(errmsg);
1361 }
1362 
1363 /**
1364  * xmlVPrintErrorMessage:
1365  * @fmt:  printf format string
1366  * @ap:  arguments
1367  *
1368  * Prints to stderr.
1369  */
1370 void
xmlVPrintErrorMessage(const char * fmt,va_list ap)1371 xmlVPrintErrorMessage(const char *fmt, va_list ap) {
1372     vfprintf(stderr, fmt, ap);
1373 }
1374 
1375 /**
1376  * xmlPrintErrorMessage:
1377  * @fmt:  printf format string
1378  * @...:  arguments
1379  *
1380  * Prints to stderr.
1381  */
1382 void
xmlPrintErrorMessage(const char * fmt,...)1383 xmlPrintErrorMessage(const char *fmt, ...) {
1384     va_list ap;
1385 
1386     va_start(ap, fmt);
1387     xmlVPrintErrorMessage(fmt, ap);
1388     va_end(ap);
1389 }
1390 
1391 /**
1392  * xmlAbort:
1393  * @fmt:  printf format string
1394  * @...:  arguments
1395  *
1396  * Print message to stderr and abort.
1397  */
1398 void
xmlAbort(const char * fmt,...)1399 xmlAbort(const char *fmt, ...) {
1400     va_list ap;
1401 
1402     va_start(ap, fmt);
1403     xmlVPrintErrorMessage(fmt, ap);
1404     va_end(ap);
1405 
1406     abort();
1407 }
1408