blob: 2e903dc411aee86fabbbf756f0ffcfe4c87e9a88 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * error.c: module displaying/handling XML parser errors
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * Daniel Veillard <daniel@veillard.com>
Owen Taylor3473f882001-02-23 17:55:21 +00007 */
8
Daniel Veillard34ce8be2002-03-18 19:37:11 +00009#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000010#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000011
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000012#include <string.h>
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <stdarg.h>
14#include <libxml/parser.h>
15#include <libxml/xmlerror.h>
Daniel Veillarde356c282001-03-10 12:32:04 +000016#include <libxml/xmlmemory.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000017#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000018
Daniel Veillard635ef722001-10-29 11:48:19 +000019void xmlGenericErrorDefaultFunc (void *ctx ATTRIBUTE_UNUSED,
20 const char *msg,
21 ...);
22
Daniel Veillard1c43dbf2001-06-05 17:12:52 +000023#define XML_GET_VAR_STR(msg, str) { \
24 int size; \
25 int chars; \
26 char *larger; \
27 va_list ap; \
28 \
29 str = (char *) xmlMalloc(150); \
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000030 if (str != NULL) { \
Daniel Veillard1c43dbf2001-06-05 17:12:52 +000031 \
32 size = 150; \
33 \
34 while (1) { \
35 va_start(ap, msg); \
36 chars = vsnprintf(str, size, msg, ap); \
37 va_end(ap); \
38 if ((chars > -1) && (chars < size)) \
39 break; \
40 if (chars > -1) \
41 size += chars + 1; \
42 else \
43 size += 100; \
44 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000045 break; \
Daniel Veillard1c43dbf2001-06-05 17:12:52 +000046 } \
47 str = larger; \
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000048 }} \
Daniel Veillard1c43dbf2001-06-05 17:12:52 +000049}
Bjorn Reese570ff082001-06-05 12:45:55 +000050
Owen Taylor3473f882001-02-23 17:55:21 +000051/************************************************************************
52 * *
53 * Handling of out of context errors *
54 * *
55 ************************************************************************/
56
57/**
58 * xmlGenericErrorDefaultFunc:
59 * @ctx: an error context
60 * @msg: the message to display/transmit
61 * @...: extra parameters for the message display
62 *
63 * Default handler for out of context error messages.
64 */
Daniel Veillard635ef722001-10-29 11:48:19 +000065void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +000066xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
Owen Taylor3473f882001-02-23 17:55:21 +000067 va_list args;
68
69 if (xmlGenericErrorContext == NULL)
70 xmlGenericErrorContext = (void *) stderr;
71
72 va_start(args, msg);
73 vfprintf((FILE *)xmlGenericErrorContext, msg, args);
74 va_end(args);
75}
76
Daniel Veillard9d06d302002-01-22 18:15:52 +000077/**
78 * initGenericErrorDefaultFunc:
79 * @handler: the handler
80 *
81 * Set or reset (if NULL) the default handler for generic errors
Daniel Veillard7424eb62003-01-24 14:14:52 +000082 * to the builtin error function.
Daniel Veillard9d06d302002-01-22 18:15:52 +000083 */
Daniel Veillardd0463562001-10-13 09:15:48 +000084void
Daniel Veillarddb5850a2002-01-18 11:49:26 +000085initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)
Daniel Veillardd0463562001-10-13 09:15:48 +000086{
Daniel Veillarddb5850a2002-01-18 11:49:26 +000087 if (handler == NULL)
88 xmlGenericError = xmlGenericErrorDefaultFunc;
89 else
Daniel Veillardda0ff5d2004-04-20 09:45:26 +000090 xmlGenericError = (*handler);
Daniel Veillardd0463562001-10-13 09:15:48 +000091}
Owen Taylor3473f882001-02-23 17:55:21 +000092
93/**
94 * xmlSetGenericErrorFunc:
95 * @ctx: the new error handling context
96 * @handler: the new handler function
97 *
98 * Function to reset the handler and the error context for out of
99 * context error messages.
100 * This simply means that @handler will be called for subsequent
101 * error messages while not parsing nor validating. And @ctx will
102 * be passed as first argument to @handler
103 * One can simply force messages to be emitted to another FILE * than
104 * stderr by setting @ctx to this file handle and @handler to NULL.
105 */
106void
107xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
108 xmlGenericErrorContext = ctx;
109 if (handler != NULL)
110 xmlGenericError = handler;
111 else
112 xmlGenericError = xmlGenericErrorDefaultFunc;
113}
114
Daniel Veillard659e71e2003-10-10 14:10:40 +0000115/**
116 * xmlSetStructuredErrorFunc:
117 * @ctx: the new error handling context
118 * @handler: the new handler function
119 *
120 * Function to reset the handler and the error context for out of
121 * context structured error messages.
122 * This simply means that @handler will be called for subsequent
123 * error messages while not parsing nor validating. And @ctx will
124 * be passed as first argument to @handler
125 */
126void
127xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
128 xmlGenericErrorContext = ctx;
129 xmlStructuredError = handler;
130}
131
Owen Taylor3473f882001-02-23 17:55:21 +0000132/************************************************************************
133 * *
134 * Handling of parsing errors *
135 * *
136 ************************************************************************/
137
138/**
139 * xmlParserPrintFileInfo:
140 * @input: an xmlParserInputPtr input
141 *
142 * Displays the associated file and line informations for the current input
143 */
144
145void
146xmlParserPrintFileInfo(xmlParserInputPtr input) {
147 if (input != NULL) {
148 if (input->filename)
149 xmlGenericError(xmlGenericErrorContext,
150 "%s:%d: ", input->filename,
151 input->line);
152 else
153 xmlGenericError(xmlGenericErrorContext,
154 "Entity: line %d: ", input->line);
155 }
156}
157
158/**
159 * xmlParserPrintFileContext:
160 * @input: an xmlParserInputPtr input
161 *
162 * Displays current context within the input content for error tracking
163 */
164
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000165static void
166xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
167 xmlGenericErrorFunc channel, void *data ) {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000168 const xmlChar *cur, *base;
William M. Brackc1939562003-08-05 15:52:22 +0000169 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
William M. Brack3dd57f72003-05-13 02:06:18 +0000170 xmlChar content[81]; /* space for 80 chars + line terminator */
Daniel Veillard2be30642001-03-27 00:32:28 +0000171 xmlChar *ctnt;
Owen Taylor3473f882001-02-23 17:55:21 +0000172
Daniel Veillard561b7f82002-03-20 21:55:57 +0000173 if (input == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000174 cur = input->cur;
175 base = input->base;
Daniel Veillard2be30642001-03-27 00:32:28 +0000176 /* skip backwards over any end-of-lines */
William M. Brackc1939562003-08-05 15:52:22 +0000177 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000178 cur--;
Owen Taylor3473f882001-02-23 17:55:21 +0000179 }
180 n = 0;
William M. Brack3dd57f72003-05-13 02:06:18 +0000181 /* search backwards for beginning-of-line (to max buff size) */
William M. Brackc1939562003-08-05 15:52:22 +0000182 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
183 (*(cur) != '\n') && (*(cur) != '\r'))
Owen Taylor3473f882001-02-23 17:55:21 +0000184 cur--;
William M. Brackc1939562003-08-05 15:52:22 +0000185 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
William M. Brack3dd57f72003-05-13 02:06:18 +0000186 /* calculate the error position in terms of the current position */
187 col = input->cur - cur;
188 /* search forward for end-of-line (to max buff size) */
Owen Taylor3473f882001-02-23 17:55:21 +0000189 n = 0;
Daniel Veillard2be30642001-03-27 00:32:28 +0000190 ctnt = content;
William M. Brack3dd57f72003-05-13 02:06:18 +0000191 /* copy selected text to our buffer */
William M. Brackc1939562003-08-05 15:52:22 +0000192 while ((*cur != 0) && (*(cur) != '\n') &&
193 (*(cur) != '\r') && (n < sizeof(content)-1)) {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000194 *ctnt++ = *cur++;
195 n++;
Owen Taylor3473f882001-02-23 17:55:21 +0000196 }
Daniel Veillard2be30642001-03-27 00:32:28 +0000197 *ctnt = 0;
William M. Brack3dd57f72003-05-13 02:06:18 +0000198 /* print out the selected text */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000199 channel(data ,"%s\n", content);
Daniel Veillard2be30642001-03-27 00:32:28 +0000200 /* create blank line with problem pointer */
Owen Taylor3473f882001-02-23 17:55:21 +0000201 n = 0;
Daniel Veillard7533cc82001-04-24 15:52:00 +0000202 ctnt = content;
William M. Brack3dd57f72003-05-13 02:06:18 +0000203 /* (leave buffer space for pointer + line terminator) */
204 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
William M. Brackc1939562003-08-05 15:52:22 +0000205 if (*(ctnt) != '\t')
206 *(ctnt) = ' ';
William M. Brack69848302003-09-22 00:24:51 +0000207 ctnt++;
Owen Taylor3473f882001-02-23 17:55:21 +0000208 }
William M. Brack3dd57f72003-05-13 02:06:18 +0000209 *ctnt++ = '^';
210 *ctnt = 0;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000211 channel(data ,"%s\n", content);
Owen Taylor3473f882001-02-23 17:55:21 +0000212}
213
Daniel Veillard561b7f82002-03-20 21:55:57 +0000214/**
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000215 * xmlParserPrintFileContext:
216 * @input: an xmlParserInputPtr input
217 *
218 * Displays current context within the input content for error tracking
Daniel Veillard561b7f82002-03-20 21:55:57 +0000219 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000220void
221xmlParserPrintFileContext(xmlParserInputPtr input) {
222 xmlParserPrintFileContextInternal(input, xmlGenericError,
223 xmlGenericErrorContext);
Daniel Veillard561b7f82002-03-20 21:55:57 +0000224}
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000225
226/**
227 * xmlReportError:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000228 * @err: the error
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000229 * @ctx: the parser context or NULL
230 * @str: the formatted error message
231 *
232 * Report an erro with its context, replace the 4 old error/warning
233 * routines.
234 */
235static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000236xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str,
237 xmlGenericErrorFunc channel, void *data)
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000238{
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000239 char *file = NULL;
240 int line = 0;
241 int code = -1;
242 int domain;
Daniel Veillard4c004142003-10-07 11:33:24 +0000243 const xmlChar *name = NULL;
244 xmlNodePtr node;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000245 xmlErrorLevel level;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000246 xmlParserInputPtr input = NULL;
247 xmlParserInputPtr cur = NULL;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000248
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000249 if (err == NULL)
250 return;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000251
Daniel Veillard4c004142003-10-07 11:33:24 +0000252 if (channel == NULL) {
253 channel = xmlGenericError;
254 data = xmlGenericErrorContext;
255 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000256 file = err->file;
257 line = err->line;
258 code = err->code;
259 domain = err->domain;
260 level = err->level;
Daniel Veillard4c004142003-10-07 11:33:24 +0000261 node = err->node;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000262
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000263 if (code == XML_ERR_OK)
264 return;
265
Daniel Veillard4c004142003-10-07 11:33:24 +0000266 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
267 name = node->name;
268
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000269 /*
270 * Maintain the compatibility with the legacy error handling
271 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000272 if (ctxt != NULL) {
273 input = ctxt->input;
274 if ((input != NULL) && (input->filename == NULL) &&
275 (ctxt->inputNr > 1)) {
276 cur = input;
277 input = ctxt->inputTab[ctxt->inputNr - 2];
278 }
279 if (input != NULL) {
280 if (input->filename)
281 channel(data, "%s:%d: ", input->filename, input->line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000282 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000283 channel(data, "Entity: line %d: ", input->line);
284 }
285 } else {
286 if (file != NULL)
287 channel(data, "%s:%d: ", file, line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000289 channel(data, "Entity: line %d: ", line);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000290 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000291 if (name != NULL) {
292 channel(data, "element %s: ", name);
293 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000294 if (code == XML_ERR_OK)
295 return;
296 switch (domain) {
297 case XML_FROM_PARSER:
298 channel(data, "parser ");
299 break;
300 case XML_FROM_NAMESPACE:
301 channel(data, "namespace ");
302 break;
303 case XML_FROM_DTD:
Daniel Veillard72b9e292003-10-28 15:44:17 +0000304 case XML_FROM_VALID:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000305 channel(data, "validity ");
306 break;
307 case XML_FROM_HTML:
308 channel(data, "HTML parser ");
309 break;
310 case XML_FROM_MEMORY:
311 channel(data, "memory ");
312 break;
313 case XML_FROM_OUTPUT:
314 channel(data, "output ");
315 break;
316 case XML_FROM_IO:
317 channel(data, "I/O ");
318 break;
319 case XML_FROM_XINCLUDE:
320 channel(data, "XInclude ");
321 break;
322 case XML_FROM_XPATH:
323 channel(data, "XPath ");
324 break;
325 case XML_FROM_XPOINTER:
326 channel(data, "parser ");
327 break;
328 case XML_FROM_REGEXP:
329 channel(data, "regexp ");
330 break;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000331 case XML_FROM_SCHEMASV:
Daniel Veillard87db3a82003-10-10 10:52:58 +0000332 channel(data, "Schemas validity ");
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000333 break;
334 case XML_FROM_SCHEMASP:
Daniel Veillard87db3a82003-10-10 10:52:58 +0000335 channel(data, "Schemas parser ");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000336 break;
Daniel Veillard4c004142003-10-07 11:33:24 +0000337 case XML_FROM_RELAXNGP:
338 channel(data, "Relax-NG parser ");
339 break;
340 case XML_FROM_RELAXNGV:
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000341 channel(data, "Relax-NG validity ");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000342 break;
343 case XML_FROM_CATALOG:
344 channel(data, "Catalog ");
345 break;
346 case XML_FROM_C14N:
347 channel(data, "C14N ");
348 break;
349 case XML_FROM_XSLT:
350 channel(data, "XSLT ");
351 break;
352 default:
353 break;
354 }
355 if (code == XML_ERR_OK)
356 return;
357 switch (level) {
358 case XML_ERR_NONE:
359 channel(data, ": ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000360 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000361 case XML_ERR_WARNING:
362 channel(data, "warning : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000363 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000364 case XML_ERR_ERROR:
365 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000366 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000367 case XML_ERR_FATAL:
368 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000369 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000370 }
371 if (code == XML_ERR_OK)
372 return;
373 if (str != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +0000374 int len;
375 len = xmlStrlen((const xmlChar *)str);
376 if ((len > 0) && (str[len - 1] != '\n'))
Daniel Veillard828ce832003-10-08 19:19:10 +0000377 channel(data, "%s\n", str);
Daniel Veillarda8856222003-10-08 19:26:03 +0000378 else
379 channel(data, "%s", str);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000380 } else {
Daniel Veillard828ce832003-10-08 19:19:10 +0000381 channel(data, "%s\n", "out of memory error");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000382 }
383 if (code == XML_ERR_OK)
384 return;
385
386 if (ctxt != NULL) {
387 xmlParserPrintFileContextInternal(input, channel, data);
388 if (cur != NULL) {
389 if (cur->filename)
390 channel(data, "%s:%d: \n", cur->filename, cur->line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000391 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000392 channel(data, "Entity: line %d: \n", cur->line);
393 xmlParserPrintFileContextInternal(cur, channel, data);
394 }
395 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000396 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
397 (err->int1 < 100) &&
398 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
399 xmlChar buf[150];
400 int i;
401
402 channel(data, "%s\n", err->str1);
403 for (i=0;i < err->int1;i++)
404 buf[i] = ' ';
405 buf[i++] = '^';
406 buf[i] = 0;
407 channel(data, "%s\n", buf);
408 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000409}
410
411/**
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000412 * __xmlRaiseError:
William M. Brackd233e392004-05-16 03:12:08 +0000413 * @schannel: the structured callback channel
Daniel Veillard659e71e2003-10-10 14:10:40 +0000414 * @channel: the old callback channel
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000415 * @data: the callback data
416 * @ctx: the parser context or NULL
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000417 * @ctx: the parser context or NULL
418 * @domain: the domain for the error
419 * @code: the code for the error
420 * @level: the xmlErrorLevel for the error
421 * @file: the file source of the error (or NULL)
422 * @line: the line of the error or 0 if N/A
423 * @str1: extra string info
424 * @str2: extra string info
425 * @str3: extra string info
426 * @int1: extra int info
427 * @int2: extra int info
428 * @msg: the message to display/transmit
429 * @...: extra parameters for the message display
430 *
William M. Brackd233e392004-05-16 03:12:08 +0000431 * Update the appropriate global or contextual error structure,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000432 * then forward the error message down the parser or generic
433 * error callback handler
434 */
435void
Daniel Veillard659e71e2003-10-10 14:10:40 +0000436__xmlRaiseError(xmlStructuredErrorFunc schannel,
437 xmlGenericErrorFunc channel, void *data, void *ctx,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000438 void *nod, int domain, int code, xmlErrorLevel level,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000439 const char *file, int line, const char *str1,
440 const char *str2, const char *str3, int int1, int int2,
441 const char *msg, ...)
442{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000443 xmlParserCtxtPtr ctxt = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000444 xmlNodePtr node = (xmlNodePtr) nod;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000445 char *str = NULL;
446 xmlParserInputPtr input = NULL;
447 xmlErrorPtr to = &xmlLastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000448 xmlChar *base = NULL;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000449
Daniel Veillardb5fa0202003-12-08 17:41:29 +0000450 if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
451 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000452 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
453 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
454 (domain == XML_FROM_IO)) {
455 ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000456 if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
457 (ctxt->sax->initialized == XML_SAX2_MAGIC))
458 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000459 }
William M. Brackcd3628b2004-07-25 21:07:29 +0000460 /*
461 * Check if structured error handler set
462 */
463 if (schannel == NULL) {
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000464 schannel = xmlStructuredError;
William M. Brackcd3628b2004-07-25 21:07:29 +0000465 /*
466 * if user has defined handler, change data ptr to user's choice
467 */
468 if (schannel != NULL)
469 data = xmlGenericErrorContext;
470 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000471 if ((domain == XML_FROM_VALID) &&
472 ((channel == xmlParserValidityError) ||
473 (channel == xmlParserValidityWarning))) {
474 ctxt = (xmlParserCtxtPtr) ctx;
475 if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
476 (ctxt->sax->initialized == XML_SAX2_MAGIC))
477 schannel = ctxt->sax->serror;
478 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000479 if (code == XML_ERR_OK)
480 return;
481 /*
482 * Formatting the message
483 */
484 if (msg == NULL) {
485 str = (char *) xmlStrdup(BAD_CAST "No error message provided");
486 } else {
487 XML_GET_VAR_STR(msg, str);
488 }
489
490 /*
491 * specific processing if a parser context is provided
492 */
493 if (ctxt != NULL) {
494 if (file == NULL) {
495 input = ctxt->input;
496 if ((input != NULL) && (input->filename == NULL) &&
497 (ctxt->inputNr > 1)) {
498 input = ctxt->inputTab[ctxt->inputNr - 2];
499 }
500 if (input != NULL) {
501 file = input->filename;
502 line = input->line;
503 }
504 }
505 to = &ctxt->lastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000506 } else if ((node != NULL) && (file == NULL)) {
507 int i;
Daniel Veillard4c004142003-10-07 11:33:24 +0000508
509 if ((node->doc != NULL) && (node->doc->URL != NULL))
510 base = xmlStrdup(node->doc->URL);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000511 for (i = 0;
512 ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
513 i++)
514 node = node->parent;
Daniel Veillard4c004142003-10-07 11:33:24 +0000515 if ((base == NULL) && (node != NULL) &&
516 (node->doc != NULL) && (node->doc->URL != NULL))
517 base = xmlStrdup(node->doc->URL);
518
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000519 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +0000520 line = node->line;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000521 }
522
523 /*
William M. Brackd233e392004-05-16 03:12:08 +0000524 * Save the information about the error
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000525 */
526 xmlResetError(to);
527 to->domain = domain;
528 to->code = code;
529 to->message = str;
530 to->level = level;
531 if (file != NULL)
532 to->file = (char *) xmlStrdup((const xmlChar *) file);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000533 else if (base != NULL) {
534 to->file = (char *) base;
535 file = (char *) base;
536 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000537 to->line = line;
538 if (str1 != NULL)
539 to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
540 if (str2 != NULL)
541 to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
542 if (str3 != NULL)
543 to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
544 to->int1 = int1;
545 to->int2 = int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000546 to->node = node;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000547 to->ctxt = ctx;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000548
Daniel Veillardd34b0b82004-01-02 20:26:01 +0000549 if (to != &xmlLastError)
550 xmlCopyError(to,&xmlLastError);
551
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000552 /*
William M. Brackcd3628b2004-07-25 21:07:29 +0000553 * Find the callback channel if channel param is NULL
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000554 */
William M. Brackd233e392004-05-16 03:12:08 +0000555 if ((ctxt != NULL) && (channel == NULL) && (xmlStructuredError == NULL)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000556 if (level == XML_ERR_WARNING)
557 channel = ctxt->sax->warning;
558 else
559 channel = ctxt->sax->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000560 data = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000561 } else if (channel == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000562 if (xmlStructuredError != NULL)
563 schannel = xmlStructuredError;
564 else
565 channel = xmlGenericError;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000566 data = xmlGenericErrorContext;
567 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000568 if (schannel != NULL) {
569 schannel(data, to);
570 return;
571 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000572 if (channel == NULL)
573 return;
574
575 if ((channel == xmlParserError) ||
576 (channel == xmlParserWarning) ||
577 (channel == xmlParserValidityError) ||
578 (channel == xmlParserValidityWarning))
Daniel Veillard4c004142003-10-07 11:33:24 +0000579 xmlReportError(to, ctxt, str, NULL, NULL);
580 else if ((channel == (xmlGenericErrorFunc) fprintf) ||
581 (channel == xmlGenericErrorDefaultFunc))
582 xmlReportError(to, ctxt, str, channel, data);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000583 else
584 channel(data, "%s", str);
585}
Daniel Veillard561b7f82002-03-20 21:55:57 +0000586
Daniel Veillarde356c282001-03-10 12:32:04 +0000587/**
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000588 * __xmlSimpleError:
589 * @domain: where the error comes from
590 * @code: the error code
591 * @node: the context node
592 * @extra: extra informations
593 *
594 * Handle an out of memory condition
595 */
596void
597__xmlSimpleError(int domain, int code, xmlNodePtr node,
598 const char *msg, const char *extra)
599{
600
601 if (code == XML_ERR_NO_MEMORY) {
602 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000603 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000604 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
605 NULL, NULL, 0, 0,
606 "Memory allocation failed : %s\n", extra);
607 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000608 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000609 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
610 NULL, NULL, 0, 0, "Memory allocation failed\n");
611 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000612 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000613 code, XML_ERR_ERROR, NULL, 0, extra,
614 NULL, NULL, 0, 0, msg, extra);
615 }
616}
617/**
Owen Taylor3473f882001-02-23 17:55:21 +0000618 * xmlParserError:
619 * @ctx: an XML parser context
620 * @msg: the message to display/transmit
621 * @...: extra parameters for the message display
622 *
623 * Display and format an error messages, gives file, line, position and
624 * extra parameters.
625 */
626void
627xmlParserError(void *ctx, const char *msg, ...)
628{
629 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
630 xmlParserInputPtr input = NULL;
631 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000632 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000633
634 if (ctxt != NULL) {
635 input = ctxt->input;
636 if ((input != NULL) && (input->filename == NULL) &&
637 (ctxt->inputNr > 1)) {
638 cur = input;
639 input = ctxt->inputTab[ctxt->inputNr - 2];
640 }
641 xmlParserPrintFileInfo(input);
642 }
643
644 xmlGenericError(xmlGenericErrorContext, "error: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000645 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000646 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000647 if (str != NULL)
648 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000649
650 if (ctxt != NULL) {
651 xmlParserPrintFileContext(input);
652 if (cur != NULL) {
653 xmlParserPrintFileInfo(cur);
654 xmlGenericError(xmlGenericErrorContext, "\n");
655 xmlParserPrintFileContext(cur);
656 }
657 }
658}
659
660/**
661 * xmlParserWarning:
662 * @ctx: an XML parser context
663 * @msg: the message to display/transmit
664 * @...: extra parameters for the message display
665 *
666 * Display and format a warning messages, gives file, line, position and
667 * extra parameters.
668 */
669void
670xmlParserWarning(void *ctx, const char *msg, ...)
671{
672 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
673 xmlParserInputPtr input = NULL;
674 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000675 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000676
677 if (ctxt != NULL) {
678 input = ctxt->input;
679 if ((input != NULL) && (input->filename == NULL) &&
680 (ctxt->inputNr > 1)) {
681 cur = input;
682 input = ctxt->inputTab[ctxt->inputNr - 2];
683 }
684 xmlParserPrintFileInfo(input);
685 }
686
687 xmlGenericError(xmlGenericErrorContext, "warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000688 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000689 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000690 if (str != NULL)
691 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000692
693 if (ctxt != NULL) {
694 xmlParserPrintFileContext(input);
695 if (cur != NULL) {
696 xmlParserPrintFileInfo(cur);
697 xmlGenericError(xmlGenericErrorContext, "\n");
698 xmlParserPrintFileContext(cur);
699 }
700 }
701}
702
703/************************************************************************
704 * *
705 * Handling of validation errors *
706 * *
707 ************************************************************************/
708
709/**
710 * xmlParserValidityError:
711 * @ctx: an XML parser context
712 * @msg: the message to display/transmit
713 * @...: extra parameters for the message display
714 *
715 * Display and format an validity error messages, gives file,
716 * line, position and extra parameters.
717 */
718void
719xmlParserValidityError(void *ctx, const char *msg, ...)
720{
721 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
722 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000723 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000724 int len = xmlStrlen((const xmlChar *) msg);
725 static int had_info = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000726
Daniel Veillard76575762002-09-05 14:21:15 +0000727 if ((len > 1) && (msg[len - 2] != ':')) {
728 if (ctxt != NULL) {
729 input = ctxt->input;
730 if ((input->filename == NULL) && (ctxt->inputNr > 1))
731 input = ctxt->inputTab[ctxt->inputNr - 2];
732
733 if (had_info == 0) {
734 xmlParserPrintFileInfo(input);
735 }
736 }
737 xmlGenericError(xmlGenericErrorContext, "validity error: ");
Daniel Veillard76575762002-09-05 14:21:15 +0000738 had_info = 0;
739 } else {
740 had_info = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000741 }
742
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000743 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000744 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000745 if (str != NULL)
746 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000747
Daniel Veillard76575762002-09-05 14:21:15 +0000748 if ((ctxt != NULL) && (input != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000749 xmlParserPrintFileContext(input);
750 }
751}
752
753/**
754 * xmlParserValidityWarning:
755 * @ctx: an XML parser context
756 * @msg: the message to display/transmit
757 * @...: extra parameters for the message display
758 *
759 * Display and format a validity warning messages, gives file, line,
760 * position and extra parameters.
761 */
762void
763xmlParserValidityWarning(void *ctx, const char *msg, ...)
764{
765 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
766 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000767 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000768 int len = xmlStrlen((const xmlChar *) msg);
Owen Taylor3473f882001-02-23 17:55:21 +0000769
Daniel Veillard76575762002-09-05 14:21:15 +0000770 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +0000771 input = ctxt->input;
772 if ((input->filename == NULL) && (ctxt->inputNr > 1))
773 input = ctxt->inputTab[ctxt->inputNr - 2];
774
775 xmlParserPrintFileInfo(input);
776 }
777
778 xmlGenericError(xmlGenericErrorContext, "validity warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000779 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000780 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000781 if (str != NULL)
782 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000783
784 if (ctxt != NULL) {
785 xmlParserPrintFileContext(input);
786 }
787}
788
789
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000790/************************************************************************
791 * *
792 * Extended Error Handling *
793 * *
794 ************************************************************************/
795
796/**
797 * xmlGetLastError:
798 *
799 * Get the last global error registered. This is per thread if compiled
800 * with thread support.
801 *
802 * Returns NULL if no error occured or a pointer to the error
803 */
804xmlErrorPtr
805xmlGetLastError(void)
806{
807 if (xmlLastError.code == XML_ERR_OK)
808 return (NULL);
809 return (&xmlLastError);
810}
811
812/**
813 * xmlResetError:
814 * @err: pointer to the error.
815 *
816 * Cleanup the error.
817 */
818void
819xmlResetError(xmlErrorPtr err)
820{
821 if (err == NULL)
822 return;
823 if (err->code == XML_ERR_OK)
824 return;
825 if (err->message != NULL)
826 xmlFree(err->message);
827 if (err->file != NULL)
828 xmlFree(err->file);
829 if (err->str1 != NULL)
830 xmlFree(err->str1);
831 if (err->str2 != NULL)
832 xmlFree(err->str2);
833 if (err->str3 != NULL)
834 xmlFree(err->str3);
835 memset(err, 0, sizeof(xmlError));
836 err->code = XML_ERR_OK;
837}
838
839/**
840 * xmlResetLastError:
841 *
842 * Cleanup the last global error registered. For parsing error
843 * this does not change the well-formedness result.
844 */
845void
846xmlResetLastError(void)
847{
848 if (xmlLastError.code == XML_ERR_OK)
849 return;
850 xmlResetError(&xmlLastError);
851}
852
853/**
854 * xmlCtxtGetLastError:
855 * @ctx: an XML parser context
856 *
857 * Get the last parsing error registered.
858 *
859 * Returns NULL if no error occured or a pointer to the error
860 */
861xmlErrorPtr
862xmlCtxtGetLastError(void *ctx)
863{
864 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
865
866 if (ctxt == NULL)
867 return (NULL);
868 if (ctxt->lastError.code == XML_ERR_OK)
869 return (NULL);
870 return (&ctxt->lastError);
871}
872
873/**
874 * xmlCtxtResetLastError:
875 * @ctx: an XML parser context
876 *
877 * Cleanup the last global error registered. For parsing error
878 * this does not change the well-formedness result.
879 */
880void
881xmlCtxtResetLastError(void *ctx)
882{
883 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
884
885 if (ctxt == NULL)
886 return;
887 if (ctxt->lastError.code == XML_ERR_OK)
888 return;
889 xmlResetError(&ctxt->lastError);
890}
891
892/**
893 * xmlCopyError:
894 * @from: a source error
895 * @to: a target error
896 *
897 * Save the original error to the new place.
898 *
899 * Returns 0 in case of success and -1 in case of error.
900 */
901int
902xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
903 if ((from == NULL) || (to == NULL))
904 return(-1);
905 if (to->message != NULL)
906 xmlFree(to->message);
907 if (to->file != NULL)
908 xmlFree(to->file);
909 if (to->str1 != NULL)
910 xmlFree(to->str1);
911 if (to->str2 != NULL)
912 xmlFree(to->str2);
913 if (to->str3 != NULL)
914 xmlFree(to->str3);
915 to->domain = from->domain;
916 to->code = from->code;
917 to->level = from->level;
918 to->line = from->line;
Daniel Veillard4c004142003-10-07 11:33:24 +0000919 to->node = from->node;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000920 to->int1 = from->int1;
921 to->int2 = from->int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000922 to->node = from->node;
923 to->ctxt = from->ctxt;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000924 if (from->message != NULL)
925 to->message = (char *) xmlStrdup((xmlChar *) from->message);
926 else
927 to->message = NULL;
928 if (from->file != NULL)
929 to->file = (char *) xmlStrdup((xmlChar *) from->file);
930 else
931 to->file = NULL;
932 if (from->str1 != NULL)
933 to->str1 = (char *) xmlStrdup((xmlChar *) from->str1);
934 else
935 to->str1 = NULL;
936 if (from->str2 != NULL)
937 to->str2 = (char *) xmlStrdup((xmlChar *) from->str2);
938 else
939 to->str2 = NULL;
940 if (from->str3 != NULL)
941 to->str3 = (char *) xmlStrdup((xmlChar *) from->str3);
942 else
943 to->str3 = NULL;
944 return(0);
945}
946