Home | History | Annotate | Download | only in libxml2
      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 (at) veillard.com>
      7  */
      8 
      9 #define IN_LIBXML
     10 #include "libxml.h"
     11 
     12 #include <string.h>
     13 #include <stdarg.h>
     14 #include <libxml/parser.h>
     15 #include <libxml/xmlerror.h>
     16 #include <libxml/xmlmemory.h>
     17 #include <libxml/globals.h>
     18 
     19 void XMLCDECL xmlGenericErrorDefaultFunc	(void *ctx ATTRIBUTE_UNUSED,
     20 				 const char *msg,
     21 				 ...) LIBXML_ATTR_FORMAT(2,3);
     22 
     23 #define XML_GET_VAR_STR(msg, str) {				\
     24     int       size, prev_size = -1;				\
     25     int       chars;						\
     26     char      *larger;						\
     27     va_list   ap;						\
     28 								\
     29     str = (char *) xmlMalloc(150);				\
     30     if (str != NULL) {						\
     31 								\
     32     size = 150;							\
     33 								\
     34     while (size < 64000) {					\
     35 	va_start(ap, msg);					\
     36 	chars = vsnprintf(str, size, msg, ap);			\
     37 	va_end(ap);						\
     38 	if ((chars > -1) && (chars < size)) {			\
     39 	    if (prev_size == chars) {				\
     40 		break;						\
     41 	    } else {						\
     42 		prev_size = chars;				\
     43 	    }							\
     44 	}							\
     45 	if (chars > -1)						\
     46 	    size += chars + 1;					\
     47 	else							\
     48 	    size += 100;					\
     49 	if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
     50 	    break;						\
     51 	}							\
     52 	str = larger;						\
     53     }}								\
     54 }
     55 
     56 /************************************************************************
     57  *									*
     58  *			Handling of out of context errors		*
     59  *									*
     60  ************************************************************************/
     61 
     62 /**
     63  * xmlGenericErrorDefaultFunc:
     64  * @ctx:  an error context
     65  * @msg:  the message to display/transmit
     66  * @...:  extra parameters for the message display
     67  *
     68  * Default handler for out of context error messages.
     69  */
     70 void XMLCDECL
     71 xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
     72     va_list args;
     73 
     74     if (xmlGenericErrorContext == NULL)
     75 	xmlGenericErrorContext = (void *) stderr;
     76 
     77     va_start(args, msg);
     78     vfprintf((FILE *)xmlGenericErrorContext, msg, args);
     79     va_end(args);
     80 }
     81 
     82 /**
     83  * initGenericErrorDefaultFunc:
     84  * @handler:  the handler
     85  *
     86  * Set or reset (if NULL) the default handler for generic errors
     87  * to the builtin error function.
     88  */
     89 void
     90 initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)
     91 {
     92     if (handler == NULL)
     93         xmlGenericError = xmlGenericErrorDefaultFunc;
     94     else
     95         xmlGenericError = (*handler);
     96 }
     97 
     98 /**
     99  * xmlSetGenericErrorFunc:
    100  * @ctx:  the new error handling context
    101  * @handler:  the new handler function
    102  *
    103  * Function to reset the handler and the error context for out of
    104  * context error messages.
    105  * This simply means that @handler will be called for subsequent
    106  * error messages while not parsing nor validating. And @ctx will
    107  * be passed as first argument to @handler
    108  * One can simply force messages to be emitted to another FILE * than
    109  * stderr by setting @ctx to this file handle and @handler to NULL.
    110  * For multi-threaded applications, this must be set separately for each thread.
    111  */
    112 void
    113 xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
    114     xmlGenericErrorContext = ctx;
    115     if (handler != NULL)
    116 	xmlGenericError = handler;
    117     else
    118 	xmlGenericError = xmlGenericErrorDefaultFunc;
    119 }
    120 
    121 /**
    122  * xmlSetStructuredErrorFunc:
    123  * @ctx:  the new error handling context
    124  * @handler:  the new handler function
    125  *
    126  * Function to reset the handler and the error context for out of
    127  * context structured error messages.
    128  * This simply means that @handler will be called for subsequent
    129  * error messages while not parsing nor validating. And @ctx will
    130  * be passed as first argument to @handler
    131  * For multi-threaded applications, this must be set separately for each thread.
    132  */
    133 void
    134 xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
    135     xmlStructuredErrorContext = ctx;
    136     xmlStructuredError = handler;
    137 }
    138 
    139 /************************************************************************
    140  *									*
    141  *			Handling of parsing errors			*
    142  *									*
    143  ************************************************************************/
    144 
    145 /**
    146  * xmlParserPrintFileInfo:
    147  * @input:  an xmlParserInputPtr input
    148  *
    149  * Displays the associated file and line informations for the current input
    150  */
    151 
    152 void
    153 xmlParserPrintFileInfo(xmlParserInputPtr input) {
    154     if (input != NULL) {
    155 	if (input->filename)
    156 	    xmlGenericError(xmlGenericErrorContext,
    157 		    "%s:%d: ", input->filename,
    158 		    input->line);
    159 	else
    160 	    xmlGenericError(xmlGenericErrorContext,
    161 		    "Entity: line %d: ", input->line);
    162     }
    163 }
    164 
    165 /**
    166  * xmlParserPrintFileContext:
    167  * @input:  an xmlParserInputPtr input
    168  *
    169  * Displays current context within the input content for error tracking
    170  */
    171 
    172 static void
    173 xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
    174 		xmlGenericErrorFunc channel, void *data ) {
    175     const xmlChar *cur, *base;
    176     unsigned int n, col;	/* GCC warns if signed, because compared with sizeof() */
    177     xmlChar  content[81]; /* space for 80 chars + line terminator */
    178     xmlChar *ctnt;
    179 
    180     if ((input == NULL) || (input->cur == NULL))
    181         return;
    182 
    183     cur = input->cur;
    184     base = input->base;
    185     /* skip backwards over any end-of-lines */
    186     while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
    187 	cur--;
    188     }
    189     n = 0;
    190     /* search backwards for beginning-of-line (to max buff size) */
    191     while ((n++ < (sizeof(content)-1)) && (cur > base) &&
    192 	   (*(cur) != '\n') && (*(cur) != '\r'))
    193         cur--;
    194     if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
    195     /* calculate the error position in terms of the current position */
    196     col = input->cur - cur;
    197     /* search forward for end-of-line (to max buff size) */
    198     n = 0;
    199     ctnt = content;
    200     /* copy selected text to our buffer */
    201     while ((*cur != 0) && (*(cur) != '\n') &&
    202 	   (*(cur) != '\r') && (n < sizeof(content)-1)) {
    203 		*ctnt++ = *cur++;
    204 	n++;
    205     }
    206     *ctnt = 0;
    207     /* print out the selected text */
    208     channel(data ,"%s\n", content);
    209     /* create blank line with problem pointer */
    210     n = 0;
    211     ctnt = content;
    212     /* (leave buffer space for pointer + line terminator) */
    213     while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
    214 	if (*(ctnt) != '\t')
    215 	    *(ctnt) = ' ';
    216 	ctnt++;
    217     }
    218     *ctnt++ = '^';
    219     *ctnt = 0;
    220     channel(data ,"%s\n", content);
    221 }
    222 
    223 /**
    224  * xmlParserPrintFileContext:
    225  * @input:  an xmlParserInputPtr input
    226  *
    227  * Displays current context within the input content for error tracking
    228  */
    229 void
    230 xmlParserPrintFileContext(xmlParserInputPtr input) {
    231    xmlParserPrintFileContextInternal(input, xmlGenericError,
    232                                      xmlGenericErrorContext);
    233 }
    234 
    235 /**
    236  * xmlReportError:
    237  * @err: the error
    238  * @ctx: the parser context or NULL
    239  * @str: the formatted error message
    240  *
    241  * Report an erro with its context, replace the 4 old error/warning
    242  * routines.
    243  */
    244 static void
    245 xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str,
    246                xmlGenericErrorFunc channel, void *data)
    247 {
    248     char *file = NULL;
    249     int line = 0;
    250     int code = -1;
    251     int domain;
    252     const xmlChar *name = NULL;
    253     xmlNodePtr node;
    254     xmlErrorLevel level;
    255     xmlParserInputPtr input = NULL;
    256     xmlParserInputPtr cur = NULL;
    257 
    258     if (err == NULL)
    259         return;
    260 
    261     if (channel == NULL) {
    262 	channel = xmlGenericError;
    263 	data = xmlGenericErrorContext;
    264     }
    265     file = err->file;
    266     line = err->line;
    267     code = err->code;
    268     domain = err->domain;
    269     level = err->level;
    270     node = err->node;
    271 
    272     if (code == XML_ERR_OK)
    273         return;
    274 
    275     if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
    276         name = node->name;
    277 
    278     /*
    279      * Maintain the compatibility with the legacy error handling
    280      */
    281     if (ctxt != NULL) {
    282         input = ctxt->input;
    283         if ((input != NULL) && (input->filename == NULL) &&
    284             (ctxt->inputNr > 1)) {
    285             cur = input;
    286             input = ctxt->inputTab[ctxt->inputNr - 2];
    287         }
    288         if (input != NULL) {
    289             if (input->filename)
    290                 channel(data, "%s:%d: ", input->filename, input->line);
    291             else if ((line != 0) && (domain == XML_FROM_PARSER))
    292                 channel(data, "Entity: line %d: ", input->line);
    293         }
    294     } else {
    295         if (file != NULL)
    296             channel(data, "%s:%d: ", file, line);
    297         else if ((line != 0) &&
    298 	         ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)||
    299 		  (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) ||
    300 		  (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV)))
    301             channel(data, "Entity: line %d: ", line);
    302     }
    303     if (name != NULL) {
    304         channel(data, "element %s: ", name);
    305     }
    306     switch (domain) {
    307         case XML_FROM_PARSER:
    308             channel(data, "parser ");
    309             break;
    310         case XML_FROM_NAMESPACE:
    311             channel(data, "namespace ");
    312             break;
    313         case XML_FROM_DTD:
    314         case XML_FROM_VALID:
    315             channel(data, "validity ");
    316             break;
    317         case XML_FROM_HTML:
    318             channel(data, "HTML parser ");
    319             break;
    320         case XML_FROM_MEMORY:
    321             channel(data, "memory ");
    322             break;
    323         case XML_FROM_OUTPUT:
    324             channel(data, "output ");
    325             break;
    326         case XML_FROM_IO:
    327             channel(data, "I/O ");
    328             break;
    329         case XML_FROM_XINCLUDE:
    330             channel(data, "XInclude ");
    331             break;
    332         case XML_FROM_XPATH:
    333             channel(data, "XPath ");
    334             break;
    335         case XML_FROM_XPOINTER:
    336             channel(data, "parser ");
    337             break;
    338         case XML_FROM_REGEXP:
    339             channel(data, "regexp ");
    340             break;
    341         case XML_FROM_MODULE:
    342             channel(data, "module ");
    343             break;
    344         case XML_FROM_SCHEMASV:
    345             channel(data, "Schemas validity ");
    346             break;
    347         case XML_FROM_SCHEMASP:
    348             channel(data, "Schemas parser ");
    349             break;
    350         case XML_FROM_RELAXNGP:
    351             channel(data, "Relax-NG parser ");
    352             break;
    353         case XML_FROM_RELAXNGV:
    354             channel(data, "Relax-NG validity ");
    355             break;
    356         case XML_FROM_CATALOG:
    357             channel(data, "Catalog ");
    358             break;
    359         case XML_FROM_C14N:
    360             channel(data, "C14N ");
    361             break;
    362         case XML_FROM_XSLT:
    363             channel(data, "XSLT ");
    364             break;
    365         case XML_FROM_I18N:
    366             channel(data, "encoding ");
    367             break;
    368         case XML_FROM_SCHEMATRONV:
    369             channel(data, "schematron ");
    370             break;
    371         case XML_FROM_BUFFER:
    372             channel(data, "internal buffer ");
    373             break;
    374         case XML_FROM_URI:
    375             channel(data, "URI ");
    376             break;
    377         default:
    378             break;
    379     }
    380     switch (level) {
    381         case XML_ERR_NONE:
    382             channel(data, ": ");
    383             break;
    384         case XML_ERR_WARNING:
    385             channel(data, "warning : ");
    386             break;
    387         case XML_ERR_ERROR:
    388             channel(data, "error : ");
    389             break;
    390         case XML_ERR_FATAL:
    391             channel(data, "error : ");
    392             break;
    393     }
    394     if (str != NULL) {
    395         int len;
    396 	len = xmlStrlen((const xmlChar *)str);
    397 	if ((len > 0) && (str[len - 1] != '\n'))
    398 	    channel(data, "%s\n", str);
    399 	else
    400 	    channel(data, "%s", str);
    401     } else {
    402         channel(data, "%s\n", "out of memory error");
    403     }
    404 
    405     if (ctxt != NULL) {
    406         xmlParserPrintFileContextInternal(input, channel, data);
    407         if (cur != NULL) {
    408             if (cur->filename)
    409                 channel(data, "%s:%d: \n", cur->filename, cur->line);
    410             else if ((line != 0) && (domain == XML_FROM_PARSER))
    411                 channel(data, "Entity: line %d: \n", cur->line);
    412             xmlParserPrintFileContextInternal(cur, channel, data);
    413         }
    414     }
    415     if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
    416         (err->int1 < 100) &&
    417 	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
    418 	xmlChar buf[150];
    419 	int i;
    420 
    421 	channel(data, "%s\n", err->str1);
    422 	for (i=0;i < err->int1;i++)
    423 	     buf[i] = ' ';
    424 	buf[i++] = '^';
    425 	buf[i] = 0;
    426 	channel(data, "%s\n", buf);
    427     }
    428 }
    429 
    430 /**
    431  * __xmlRaiseError:
    432  * @schannel: the structured callback channel
    433  * @channel: the old callback channel
    434  * @data: the callback data
    435  * @ctx: the parser context or NULL
    436  * @ctx: the parser context or NULL
    437  * @domain: the domain for the error
    438  * @code: the code for the error
    439  * @level: the xmlErrorLevel for the error
    440  * @file: the file source of the error (or NULL)
    441  * @line: the line of the error or 0 if N/A
    442  * @str1: extra string info
    443  * @str2: extra string info
    444  * @str3: extra string info
    445  * @int1: extra int info
    446  * @col: column number of the error or 0 if N/A
    447  * @msg:  the message to display/transmit
    448  * @...:  extra parameters for the message display
    449  *
    450  * Update the appropriate global or contextual error structure,
    451  * then forward the error message down the parser or generic
    452  * error callback handler
    453  */
    454 void XMLCDECL
    455 __xmlRaiseError(xmlStructuredErrorFunc schannel,
    456               xmlGenericErrorFunc channel, void *data, void *ctx,
    457               void *nod, int domain, int code, xmlErrorLevel level,
    458               const char *file, int line, const char *str1,
    459               const char *str2, const char *str3, int int1, int col,
    460 	      const char *msg, ...)
    461 {
    462     xmlParserCtxtPtr ctxt = NULL;
    463     xmlNodePtr node = (xmlNodePtr) nod;
    464     char *str = NULL;
    465     xmlParserInputPtr input = NULL;
    466     xmlErrorPtr to = &xmlLastError;
    467     xmlNodePtr baseptr = NULL;
    468 
    469     if (code == XML_ERR_OK)
    470         return;
    471     if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
    472         return;
    473     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
    474         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
    475 	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
    476 	ctxt = (xmlParserCtxtPtr) ctx;
    477 	if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
    478 	    (ctxt->sax->initialized == XML_SAX2_MAGIC) &&
    479 	    (ctxt->sax->serror != NULL)) {
    480 	    schannel = ctxt->sax->serror;
    481 	    data = ctxt->userData;
    482 	}
    483     }
    484     /*
    485      * Check if structured error handler set
    486      */
    487     if (schannel == NULL) {
    488 	schannel = xmlStructuredError;
    489 	/*
    490 	 * if user has defined handler, change data ptr to user's choice
    491 	 */
    492 	if (schannel != NULL)
    493 	    data = xmlStructuredErrorContext;
    494     }
    495     /*
    496      * Formatting the message
    497      */
    498     if (msg == NULL) {
    499         str = (char *) xmlStrdup(BAD_CAST "No error message provided");
    500     } else {
    501         XML_GET_VAR_STR(msg, str);
    502     }
    503 
    504     /*
    505      * specific processing if a parser context is provided
    506      */
    507     if (ctxt != NULL) {
    508         if (file == NULL) {
    509             input = ctxt->input;
    510             if ((input != NULL) && (input->filename == NULL) &&
    511                 (ctxt->inputNr > 1)) {
    512                 input = ctxt->inputTab[ctxt->inputNr - 2];
    513             }
    514             if (input != NULL) {
    515                 file = input->filename;
    516                 line = input->line;
    517                 col = input->col;
    518             }
    519         }
    520         to = &ctxt->lastError;
    521     } else if ((node != NULL) && (file == NULL)) {
    522 	int i;
    523 
    524 	if ((node->doc != NULL) && (node->doc->URL != NULL)) {
    525 	    baseptr = node;
    526 /*	    file = (const char *) node->doc->URL; */
    527 	}
    528 	for (i = 0;
    529 	     ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
    530 	     i++)
    531 	     node = node->parent;
    532         if ((baseptr == NULL) && (node != NULL) &&
    533 	    (node->doc != NULL) && (node->doc->URL != NULL))
    534 	    baseptr = node;
    535 
    536 	if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
    537 	    line = node->line;
    538 	if ((line == 0) || (line == 65535))
    539 	    line = xmlGetLineNo(node);
    540     }
    541 
    542     /*
    543      * Save the information about the error
    544      */
    545     xmlResetError(to);
    546     to->domain = domain;
    547     to->code = code;
    548     to->message = str;
    549     to->level = level;
    550     if (file != NULL)
    551         to->file = (char *) xmlStrdup((const xmlChar *) file);
    552     else if (baseptr != NULL) {
    553 #ifdef LIBXML_XINCLUDE_ENABLED
    554 	/*
    555 	 * We check if the error is within an XInclude section and,
    556 	 * if so, attempt to print out the href of the XInclude instead
    557 	 * of the usual "base" (doc->URL) for the node (bug 152623).
    558 	 */
    559         xmlNodePtr prev = baseptr;
    560 	int inclcount = 0;
    561 	while (prev != NULL) {
    562 	    if (prev->prev == NULL)
    563 	        prev = prev->parent;
    564 	    else {
    565 	        prev = prev->prev;
    566 		if (prev->type == XML_XINCLUDE_START) {
    567 		    if (--inclcount < 0)
    568 		        break;
    569 		} else if (prev->type == XML_XINCLUDE_END)
    570 		    inclcount++;
    571 	    }
    572 	}
    573 	if (prev != NULL) {
    574 	    if (prev->type == XML_XINCLUDE_START) {
    575 		prev->type = XML_ELEMENT_NODE;
    576 		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
    577 		prev->type = XML_XINCLUDE_START;
    578 	    } else {
    579 		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
    580 	    }
    581 	} else
    582 #endif
    583 	    to->file = (char *) xmlStrdup(baseptr->doc->URL);
    584 	if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) {
    585 	    to->file = (char *) xmlStrdup(node->doc->URL);
    586 	}
    587     }
    588     to->line = line;
    589     if (str1 != NULL)
    590         to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
    591     if (str2 != NULL)
    592         to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
    593     if (str3 != NULL)
    594         to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
    595     to->int1 = int1;
    596     to->int2 = col;
    597     to->node = node;
    598     to->ctxt = ctx;
    599 
    600     if (to != &xmlLastError)
    601         xmlCopyError(to,&xmlLastError);
    602 
    603     if (schannel != NULL) {
    604 	schannel(data, to);
    605 	return;
    606     }
    607 
    608     /*
    609      * Find the callback channel if channel param is NULL
    610      */
    611     if ((ctxt != NULL) && (channel == NULL) &&
    612         (xmlStructuredError == NULL) && (ctxt->sax != NULL)) {
    613         if (level == XML_ERR_WARNING)
    614 	    channel = ctxt->sax->warning;
    615         else
    616 	    channel = ctxt->sax->error;
    617 	data = ctxt->userData;
    618     } else if (channel == NULL) {
    619 	channel = xmlGenericError;
    620 	if (ctxt != NULL) {
    621 	    data = ctxt;
    622 	} else {
    623 	    data = xmlGenericErrorContext;
    624 	}
    625     }
    626     if (channel == NULL)
    627         return;
    628 
    629     if ((channel == xmlParserError) ||
    630         (channel == xmlParserWarning) ||
    631 	(channel == xmlParserValidityError) ||
    632 	(channel == xmlParserValidityWarning))
    633 	xmlReportError(to, ctxt, str, NULL, NULL);
    634     else if ((channel == (xmlGenericErrorFunc) fprintf) ||
    635              (channel == xmlGenericErrorDefaultFunc))
    636 	xmlReportError(to, ctxt, str, channel, data);
    637     else
    638 	channel(data, "%s", str);
    639 }
    640 
    641 /**
    642  * __xmlSimpleError:
    643  * @domain: where the error comes from
    644  * @code: the error code
    645  * @node: the context node
    646  * @extra:  extra informations
    647  *
    648  * Handle an out of memory condition
    649  */
    650 void
    651 __xmlSimpleError(int domain, int code, xmlNodePtr node,
    652                  const char *msg, const char *extra)
    653 {
    654 
    655     if (code == XML_ERR_NO_MEMORY) {
    656 	if (extra)
    657 	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
    658 			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
    659 			    NULL, NULL, 0, 0,
    660 			    "Memory allocation failed : %s\n", extra);
    661 	else
    662 	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
    663 			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
    664 			    NULL, NULL, 0, 0, "Memory allocation failed\n");
    665     } else {
    666 	__xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
    667 			code, XML_ERR_ERROR, NULL, 0, extra,
    668 			NULL, NULL, 0, 0, msg, extra);
    669     }
    670 }
    671 /**
    672  * xmlParserError:
    673  * @ctx:  an XML parser context
    674  * @msg:  the message to display/transmit
    675  * @...:  extra parameters for the message display
    676  *
    677  * Display and format an error messages, gives file, line, position and
    678  * extra parameters.
    679  */
    680 void XMLCDECL
    681 xmlParserError(void *ctx, const char *msg, ...)
    682 {
    683     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    684     xmlParserInputPtr input = NULL;
    685     xmlParserInputPtr cur = NULL;
    686     char * str;
    687 
    688     if (ctxt != NULL) {
    689 	input = ctxt->input;
    690 	if ((input != NULL) && (input->filename == NULL) &&
    691 	    (ctxt->inputNr > 1)) {
    692 	    cur = input;
    693 	    input = ctxt->inputTab[ctxt->inputNr - 2];
    694 	}
    695 	xmlParserPrintFileInfo(input);
    696     }
    697 
    698     xmlGenericError(xmlGenericErrorContext, "error: ");
    699     XML_GET_VAR_STR(msg, str);
    700     xmlGenericError(xmlGenericErrorContext, "%s", str);
    701     if (str != NULL)
    702 	xmlFree(str);
    703 
    704     if (ctxt != NULL) {
    705 	xmlParserPrintFileContext(input);
    706 	if (cur != NULL) {
    707 	    xmlParserPrintFileInfo(cur);
    708 	    xmlGenericError(xmlGenericErrorContext, "\n");
    709 	    xmlParserPrintFileContext(cur);
    710 	}
    711     }
    712 }
    713 
    714 /**
    715  * xmlParserWarning:
    716  * @ctx:  an XML parser context
    717  * @msg:  the message to display/transmit
    718  * @...:  extra parameters for the message display
    719  *
    720  * Display and format a warning messages, gives file, line, position and
    721  * extra parameters.
    722  */
    723 void XMLCDECL
    724 xmlParserWarning(void *ctx, const char *msg, ...)
    725 {
    726     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    727     xmlParserInputPtr input = NULL;
    728     xmlParserInputPtr cur = NULL;
    729     char * str;
    730 
    731     if (ctxt != NULL) {
    732 	input = ctxt->input;
    733 	if ((input != NULL) && (input->filename == NULL) &&
    734 	    (ctxt->inputNr > 1)) {
    735 	    cur = input;
    736 	    input = ctxt->inputTab[ctxt->inputNr - 2];
    737 	}
    738 	xmlParserPrintFileInfo(input);
    739     }
    740 
    741     xmlGenericError(xmlGenericErrorContext, "warning: ");
    742     XML_GET_VAR_STR(msg, str);
    743     xmlGenericError(xmlGenericErrorContext, "%s", str);
    744     if (str != NULL)
    745 	xmlFree(str);
    746 
    747     if (ctxt != NULL) {
    748 	xmlParserPrintFileContext(input);
    749 	if (cur != NULL) {
    750 	    xmlParserPrintFileInfo(cur);
    751 	    xmlGenericError(xmlGenericErrorContext, "\n");
    752 	    xmlParserPrintFileContext(cur);
    753 	}
    754     }
    755 }
    756 
    757 /************************************************************************
    758  *									*
    759  *			Handling of validation errors			*
    760  *									*
    761  ************************************************************************/
    762 
    763 /**
    764  * xmlParserValidityError:
    765  * @ctx:  an XML parser context
    766  * @msg:  the message to display/transmit
    767  * @...:  extra parameters for the message display
    768  *
    769  * Display and format an validity error messages, gives file,
    770  * line, position and extra parameters.
    771  */
    772 void XMLCDECL
    773 xmlParserValidityError(void *ctx, const char *msg, ...)
    774 {
    775     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    776     xmlParserInputPtr input = NULL;
    777     char * str;
    778     int len = xmlStrlen((const xmlChar *) msg);
    779     static int had_info = 0;
    780 
    781     if ((len > 1) && (msg[len - 2] != ':')) {
    782 	if (ctxt != NULL) {
    783 	    input = ctxt->input;
    784 	    if ((input->filename == NULL) && (ctxt->inputNr > 1))
    785 		input = ctxt->inputTab[ctxt->inputNr - 2];
    786 
    787 	    if (had_info == 0) {
    788 		xmlParserPrintFileInfo(input);
    789 	    }
    790 	}
    791 	xmlGenericError(xmlGenericErrorContext, "validity error: ");
    792 	had_info = 0;
    793     } else {
    794 	had_info = 1;
    795     }
    796 
    797     XML_GET_VAR_STR(msg, str);
    798     xmlGenericError(xmlGenericErrorContext, "%s", str);
    799     if (str != NULL)
    800 	xmlFree(str);
    801 
    802     if ((ctxt != NULL) && (input != NULL)) {
    803 	xmlParserPrintFileContext(input);
    804     }
    805 }
    806 
    807 /**
    808  * xmlParserValidityWarning:
    809  * @ctx:  an XML parser context
    810  * @msg:  the message to display/transmit
    811  * @...:  extra parameters for the message display
    812  *
    813  * Display and format a validity warning messages, gives file, line,
    814  * position and extra parameters.
    815  */
    816 void XMLCDECL
    817 xmlParserValidityWarning(void *ctx, const char *msg, ...)
    818 {
    819     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    820     xmlParserInputPtr input = NULL;
    821     char * str;
    822     int len = xmlStrlen((const xmlChar *) msg);
    823 
    824     if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
    825 	input = ctxt->input;
    826 	if ((input->filename == NULL) && (ctxt->inputNr > 1))
    827 	    input = ctxt->inputTab[ctxt->inputNr - 2];
    828 
    829 	xmlParserPrintFileInfo(input);
    830     }
    831 
    832     xmlGenericError(xmlGenericErrorContext, "validity warning: ");
    833     XML_GET_VAR_STR(msg, str);
    834     xmlGenericError(xmlGenericErrorContext, "%s", str);
    835     if (str != NULL)
    836 	xmlFree(str);
    837 
    838     if (ctxt != NULL) {
    839 	xmlParserPrintFileContext(input);
    840     }
    841 }
    842 
    843 
    844 /************************************************************************
    845  *									*
    846  *			Extended Error Handling				*
    847  *									*
    848  ************************************************************************/
    849 
    850 /**
    851  * xmlGetLastError:
    852  *
    853  * Get the last global error registered. This is per thread if compiled
    854  * with thread support.
    855  *
    856  * Returns NULL if no error occurred or a pointer to the error
    857  */
    858 xmlErrorPtr
    859 xmlGetLastError(void)
    860 {
    861     if (xmlLastError.code == XML_ERR_OK)
    862         return (NULL);
    863     return (&xmlLastError);
    864 }
    865 
    866 /**
    867  * xmlResetError:
    868  * @err: pointer to the error.
    869  *
    870  * Cleanup the error.
    871  */
    872 void
    873 xmlResetError(xmlErrorPtr err)
    874 {
    875     if (err == NULL)
    876         return;
    877     if (err->code == XML_ERR_OK)
    878         return;
    879     if (err->message != NULL)
    880         xmlFree(err->message);
    881     if (err->file != NULL)
    882         xmlFree(err->file);
    883     if (err->str1 != NULL)
    884         xmlFree(err->str1);
    885     if (err->str2 != NULL)
    886         xmlFree(err->str2);
    887     if (err->str3 != NULL)
    888         xmlFree(err->str3);
    889     memset(err, 0, sizeof(xmlError));
    890     err->code = XML_ERR_OK;
    891 }
    892 
    893 /**
    894  * xmlResetLastError:
    895  *
    896  * Cleanup the last global error registered. For parsing error
    897  * this does not change the well-formedness result.
    898  */
    899 void
    900 xmlResetLastError(void)
    901 {
    902     if (xmlLastError.code == XML_ERR_OK)
    903         return;
    904     xmlResetError(&xmlLastError);
    905 }
    906 
    907 /**
    908  * xmlCtxtGetLastError:
    909  * @ctx:  an XML parser context
    910  *
    911  * Get the last parsing error registered.
    912  *
    913  * Returns NULL if no error occurred or a pointer to the error
    914  */
    915 xmlErrorPtr
    916 xmlCtxtGetLastError(void *ctx)
    917 {
    918     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    919 
    920     if (ctxt == NULL)
    921         return (NULL);
    922     if (ctxt->lastError.code == XML_ERR_OK)
    923         return (NULL);
    924     return (&ctxt->lastError);
    925 }
    926 
    927 /**
    928  * xmlCtxtResetLastError:
    929  * @ctx:  an XML parser context
    930  *
    931  * Cleanup the last global error registered. For parsing error
    932  * this does not change the well-formedness result.
    933  */
    934 void
    935 xmlCtxtResetLastError(void *ctx)
    936 {
    937     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    938 
    939     if (ctxt == NULL)
    940         return;
    941     ctxt->errNo = XML_ERR_OK;
    942     if (ctxt->lastError.code == XML_ERR_OK)
    943         return;
    944     xmlResetError(&ctxt->lastError);
    945 }
    946 
    947 /**
    948  * xmlCopyError:
    949  * @from:  a source error
    950  * @to:  a target error
    951  *
    952  * Save the original error to the new place.
    953  *
    954  * Returns 0 in case of success and -1 in case of error.
    955  */
    956 int
    957 xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
    958     char *message, *file, *str1, *str2, *str3;
    959 
    960     if ((from == NULL) || (to == NULL))
    961         return(-1);
    962 
    963     message = (char *) xmlStrdup((xmlChar *) from->message);
    964     file = (char *) xmlStrdup ((xmlChar *) from->file);
    965     str1 = (char *) xmlStrdup ((xmlChar *) from->str1);
    966     str2 = (char *) xmlStrdup ((xmlChar *) from->str2);
    967     str3 = (char *) xmlStrdup ((xmlChar *) from->str3);
    968 
    969     if (to->message != NULL)
    970         xmlFree(to->message);
    971     if (to->file != NULL)
    972         xmlFree(to->file);
    973     if (to->str1 != NULL)
    974         xmlFree(to->str1);
    975     if (to->str2 != NULL)
    976         xmlFree(to->str2);
    977     if (to->str3 != NULL)
    978         xmlFree(to->str3);
    979     to->domain = from->domain;
    980     to->code = from->code;
    981     to->level = from->level;
    982     to->line = from->line;
    983     to->node = from->node;
    984     to->int1 = from->int1;
    985     to->int2 = from->int2;
    986     to->node = from->node;
    987     to->ctxt = from->ctxt;
    988     to->message = message;
    989     to->file = file;
    990     to->str1 = str1;
    991     to->str2 = str2;
    992     to->str3 = str3;
    993 
    994     return 0;
    995 }
    996 
    997 #define bottom_error
    998 #include "elfgcchack.h"
    999