blob: fcc0fdd44c5a2aca2fa61c42a09dfc90c8bcebe8 [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
90 (*handler) = xmlGenericErrorDefaultFunc;
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
115/************************************************************************
116 * *
117 * Handling of parsing errors *
118 * *
119 ************************************************************************/
120
121/**
122 * xmlParserPrintFileInfo:
123 * @input: an xmlParserInputPtr input
124 *
125 * Displays the associated file and line informations for the current input
126 */
127
128void
129xmlParserPrintFileInfo(xmlParserInputPtr input) {
130 if (input != NULL) {
131 if (input->filename)
132 xmlGenericError(xmlGenericErrorContext,
133 "%s:%d: ", input->filename,
134 input->line);
135 else
136 xmlGenericError(xmlGenericErrorContext,
137 "Entity: line %d: ", input->line);
138 }
139}
140
141/**
142 * xmlParserPrintFileContext:
143 * @input: an xmlParserInputPtr input
144 *
145 * Displays current context within the input content for error tracking
146 */
147
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000148static void
149xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
150 xmlGenericErrorFunc channel, void *data ) {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000151 const xmlChar *cur, *base;
William M. Brackc1939562003-08-05 15:52:22 +0000152 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
William M. Brack3dd57f72003-05-13 02:06:18 +0000153 xmlChar content[81]; /* space for 80 chars + line terminator */
Daniel Veillard2be30642001-03-27 00:32:28 +0000154 xmlChar *ctnt;
Owen Taylor3473f882001-02-23 17:55:21 +0000155
Daniel Veillard561b7f82002-03-20 21:55:57 +0000156 if (input == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000157 cur = input->cur;
158 base = input->base;
Daniel Veillard2be30642001-03-27 00:32:28 +0000159 /* skip backwards over any end-of-lines */
William M. Brackc1939562003-08-05 15:52:22 +0000160 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000161 cur--;
Owen Taylor3473f882001-02-23 17:55:21 +0000162 }
163 n = 0;
William M. Brack3dd57f72003-05-13 02:06:18 +0000164 /* search backwards for beginning-of-line (to max buff size) */
William M. Brackc1939562003-08-05 15:52:22 +0000165 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
166 (*(cur) != '\n') && (*(cur) != '\r'))
Owen Taylor3473f882001-02-23 17:55:21 +0000167 cur--;
William M. Brackc1939562003-08-05 15:52:22 +0000168 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
William M. Brack3dd57f72003-05-13 02:06:18 +0000169 /* calculate the error position in terms of the current position */
170 col = input->cur - cur;
171 /* search forward for end-of-line (to max buff size) */
Owen Taylor3473f882001-02-23 17:55:21 +0000172 n = 0;
Daniel Veillard2be30642001-03-27 00:32:28 +0000173 ctnt = content;
William M. Brack3dd57f72003-05-13 02:06:18 +0000174 /* copy selected text to our buffer */
William M. Brackc1939562003-08-05 15:52:22 +0000175 while ((*cur != 0) && (*(cur) != '\n') &&
176 (*(cur) != '\r') && (n < sizeof(content)-1)) {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000177 *ctnt++ = *cur++;
178 n++;
Owen Taylor3473f882001-02-23 17:55:21 +0000179 }
Daniel Veillard2be30642001-03-27 00:32:28 +0000180 *ctnt = 0;
William M. Brack3dd57f72003-05-13 02:06:18 +0000181 /* print out the selected text */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000182 channel(data ,"%s\n", content);
Daniel Veillard2be30642001-03-27 00:32:28 +0000183 /* create blank line with problem pointer */
Owen Taylor3473f882001-02-23 17:55:21 +0000184 n = 0;
Daniel Veillard7533cc82001-04-24 15:52:00 +0000185 ctnt = content;
William M. Brack3dd57f72003-05-13 02:06:18 +0000186 /* (leave buffer space for pointer + line terminator) */
187 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
William M. Brackc1939562003-08-05 15:52:22 +0000188 if (*(ctnt) != '\t')
189 *(ctnt) = ' ';
William M. Brack69848302003-09-22 00:24:51 +0000190 ctnt++;
Owen Taylor3473f882001-02-23 17:55:21 +0000191 }
William M. Brack3dd57f72003-05-13 02:06:18 +0000192 *ctnt++ = '^';
193 *ctnt = 0;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000194 channel(data ,"%s\n", content);
Owen Taylor3473f882001-02-23 17:55:21 +0000195}
196
Daniel Veillard561b7f82002-03-20 21:55:57 +0000197/**
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000198 * xmlParserPrintFileContext:
199 * @input: an xmlParserInputPtr input
200 *
201 * Displays current context within the input content for error tracking
Daniel Veillard561b7f82002-03-20 21:55:57 +0000202 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000203void
204xmlParserPrintFileContext(xmlParserInputPtr input) {
205 xmlParserPrintFileContextInternal(input, xmlGenericError,
206 xmlGenericErrorContext);
Daniel Veillard561b7f82002-03-20 21:55:57 +0000207}
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000208
209/**
210 * xmlReportError:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000211 * @err: the error
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000212 * @ctx: the parser context or NULL
213 * @str: the formatted error message
214 *
215 * Report an erro with its context, replace the 4 old error/warning
216 * routines.
217 */
218static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000219xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str,
220 xmlGenericErrorFunc channel, void *data)
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000221{
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000222 char *file = NULL;
223 int line = 0;
224 int code = -1;
225 int domain;
Daniel Veillard4c004142003-10-07 11:33:24 +0000226 const xmlChar *name = NULL;
227 xmlNodePtr node;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000228 xmlErrorLevel level;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000229 xmlParserInputPtr input = NULL;
230 xmlParserInputPtr cur = NULL;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000231
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000232 if (err == NULL)
233 return;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000234
Daniel Veillard4c004142003-10-07 11:33:24 +0000235 if (channel == NULL) {
236 channel = xmlGenericError;
237 data = xmlGenericErrorContext;
238 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000239 file = err->file;
240 line = err->line;
241 code = err->code;
242 domain = err->domain;
243 level = err->level;
Daniel Veillard4c004142003-10-07 11:33:24 +0000244 node = err->node;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000245
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000246 if (code == XML_ERR_OK)
247 return;
248
Daniel Veillard4c004142003-10-07 11:33:24 +0000249 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
250 name = node->name;
251
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000252 /*
253 * Maintain the compatibility with the legacy error handling
254 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000255 if (ctxt != NULL) {
256 input = ctxt->input;
257 if ((input != NULL) && (input->filename == NULL) &&
258 (ctxt->inputNr > 1)) {
259 cur = input;
260 input = ctxt->inputTab[ctxt->inputNr - 2];
261 }
262 if (input != NULL) {
263 if (input->filename)
264 channel(data, "%s:%d: ", input->filename, input->line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000265 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000266 channel(data, "Entity: line %d: ", input->line);
267 }
268 } else {
269 if (file != NULL)
270 channel(data, "%s:%d: ", file, line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000271 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000272 channel(data, "Entity: line %d: ", line);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000273 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000274 if (name != NULL) {
275 channel(data, "element %s: ", name);
276 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000277 if (code == XML_ERR_OK)
278 return;
279 switch (domain) {
280 case XML_FROM_PARSER:
281 channel(data, "parser ");
282 break;
283 case XML_FROM_NAMESPACE:
284 channel(data, "namespace ");
285 break;
286 case XML_FROM_DTD:
287 channel(data, "validity ");
288 break;
289 case XML_FROM_HTML:
290 channel(data, "HTML parser ");
291 break;
292 case XML_FROM_MEMORY:
293 channel(data, "memory ");
294 break;
295 case XML_FROM_OUTPUT:
296 channel(data, "output ");
297 break;
298 case XML_FROM_IO:
299 channel(data, "I/O ");
300 break;
301 case XML_FROM_XINCLUDE:
302 channel(data, "XInclude ");
303 break;
304 case XML_FROM_XPATH:
305 channel(data, "XPath ");
306 break;
307 case XML_FROM_XPOINTER:
308 channel(data, "parser ");
309 break;
310 case XML_FROM_REGEXP:
311 channel(data, "regexp ");
312 break;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000313 case XML_FROM_SCHEMASV:
Daniel Veillard87db3a82003-10-10 10:52:58 +0000314 channel(data, "Schemas validity ");
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000315 break;
316 case XML_FROM_SCHEMASP:
Daniel Veillard87db3a82003-10-10 10:52:58 +0000317 channel(data, "Schemas parser ");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000318 break;
Daniel Veillard4c004142003-10-07 11:33:24 +0000319 case XML_FROM_RELAXNGP:
320 channel(data, "Relax-NG parser ");
321 break;
322 case XML_FROM_RELAXNGV:
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000323 channel(data, "Relax-NG validity ");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000324 break;
325 case XML_FROM_CATALOG:
326 channel(data, "Catalog ");
327 break;
328 case XML_FROM_C14N:
329 channel(data, "C14N ");
330 break;
331 case XML_FROM_XSLT:
332 channel(data, "XSLT ");
333 break;
334 default:
335 break;
336 }
337 if (code == XML_ERR_OK)
338 return;
339 switch (level) {
340 case XML_ERR_NONE:
341 channel(data, ": ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000342 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000343 case XML_ERR_WARNING:
344 channel(data, "warning : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000345 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000346 case XML_ERR_ERROR:
347 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000348 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000349 case XML_ERR_FATAL:
350 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000351 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000352 }
353 if (code == XML_ERR_OK)
354 return;
355 if (str != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +0000356 int len;
357 len = xmlStrlen((const xmlChar *)str);
358 if ((len > 0) && (str[len - 1] != '\n'))
Daniel Veillard828ce832003-10-08 19:19:10 +0000359 channel(data, "%s\n", str);
Daniel Veillarda8856222003-10-08 19:26:03 +0000360 else
361 channel(data, "%s", str);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000362 } else {
Daniel Veillard828ce832003-10-08 19:19:10 +0000363 channel(data, "%s\n", "out of memory error");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000364 }
365 if (code == XML_ERR_OK)
366 return;
367
368 if (ctxt != NULL) {
369 xmlParserPrintFileContextInternal(input, channel, data);
370 if (cur != NULL) {
371 if (cur->filename)
372 channel(data, "%s:%d: \n", cur->filename, cur->line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000373 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000374 channel(data, "Entity: line %d: \n", cur->line);
375 xmlParserPrintFileContextInternal(cur, channel, data);
376 }
377 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000378 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
379 (err->int1 < 100) &&
380 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
381 xmlChar buf[150];
382 int i;
383
384 channel(data, "%s\n", err->str1);
385 for (i=0;i < err->int1;i++)
386 buf[i] = ' ';
387 buf[i++] = '^';
388 buf[i] = 0;
389 channel(data, "%s\n", buf);
390 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000391}
392
393/**
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000394 * __xmlRaiseError:
395 * @channel: the callback channel
396 * @data: the callback data
397 * @ctx: the parser context or NULL
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000398 * @ctx: the parser context or NULL
399 * @domain: the domain for the error
400 * @code: the code for the error
401 * @level: the xmlErrorLevel for the error
402 * @file: the file source of the error (or NULL)
403 * @line: the line of the error or 0 if N/A
404 * @str1: extra string info
405 * @str2: extra string info
406 * @str3: extra string info
407 * @int1: extra int info
408 * @int2: extra int info
409 * @msg: the message to display/transmit
410 * @...: extra parameters for the message display
411 *
412 * Update teh appropriate global or contextual error structure,
413 * then forward the error message down the parser or generic
414 * error callback handler
415 */
416void
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000417__xmlRaiseError(xmlGenericErrorFunc channel, void *data, void *ctx,
418 void *nod, int domain, int code, xmlErrorLevel level,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000419 const char *file, int line, const char *str1,
420 const char *str2, const char *str3, int int1, int int2,
421 const char *msg, ...)
422{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000423 xmlParserCtxtPtr ctxt = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000424 xmlNodePtr node = (xmlNodePtr) nod;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000425 char *str = NULL;
426 xmlParserInputPtr input = NULL;
427 xmlErrorPtr to = &xmlLastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000428 xmlChar *base = NULL;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000429
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000430 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
431 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
432 (domain == XML_FROM_IO)) {
433 ctxt = (xmlParserCtxtPtr) ctx;
434 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000435 if (code == XML_ERR_OK)
436 return;
437 /*
438 * Formatting the message
439 */
440 if (msg == NULL) {
441 str = (char *) xmlStrdup(BAD_CAST "No error message provided");
442 } else {
443 XML_GET_VAR_STR(msg, str);
444 }
445
446 /*
447 * specific processing if a parser context is provided
448 */
449 if (ctxt != NULL) {
450 if (file == NULL) {
451 input = ctxt->input;
452 if ((input != NULL) && (input->filename == NULL) &&
453 (ctxt->inputNr > 1)) {
454 input = ctxt->inputTab[ctxt->inputNr - 2];
455 }
456 if (input != NULL) {
457 file = input->filename;
458 line = input->line;
459 }
460 }
461 to = &ctxt->lastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000462 } else if ((node != NULL) && (file == NULL)) {
463 int i;
Daniel Veillard4c004142003-10-07 11:33:24 +0000464
465 if ((node->doc != NULL) && (node->doc->URL != NULL))
466 base = xmlStrdup(node->doc->URL);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000467 for (i = 0;
468 ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
469 i++)
470 node = node->parent;
Daniel Veillard4c004142003-10-07 11:33:24 +0000471 if ((base == NULL) && (node != NULL) &&
472 (node->doc != NULL) && (node->doc->URL != NULL))
473 base = xmlStrdup(node->doc->URL);
474
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000475 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
476 line = (int) node->content;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000477 }
478
479 /*
480 * Save the informations about the error
481 */
482 xmlResetError(to);
483 to->domain = domain;
484 to->code = code;
485 to->message = str;
486 to->level = level;
487 if (file != NULL)
488 to->file = (char *) xmlStrdup((const xmlChar *) file);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000489 else if (base != NULL) {
490 to->file = (char *) base;
491 file = (char *) base;
492 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000493 to->line = line;
494 if (str1 != NULL)
495 to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
496 if (str2 != NULL)
497 to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
498 if (str3 != NULL)
499 to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
500 to->int1 = int1;
501 to->int2 = int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000502 to->node = node;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000503 to->ctxt = ctx;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000504
505 /*
506 * Find the callback channel.
507 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000508 if ((ctxt != NULL) && (channel == NULL)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000509 if (level == XML_ERR_WARNING)
510 channel = ctxt->sax->warning;
511 else
512 channel = ctxt->sax->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000513 data = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000514 } else if (channel == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000515 channel = xmlGenericError;
516 data = xmlGenericErrorContext;
517 }
518 if (channel == NULL)
519 return;
520
521 if ((channel == xmlParserError) ||
522 (channel == xmlParserWarning) ||
523 (channel == xmlParserValidityError) ||
524 (channel == xmlParserValidityWarning))
Daniel Veillard4c004142003-10-07 11:33:24 +0000525 xmlReportError(to, ctxt, str, NULL, NULL);
526 else if ((channel == (xmlGenericErrorFunc) fprintf) ||
527 (channel == xmlGenericErrorDefaultFunc))
528 xmlReportError(to, ctxt, str, channel, data);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000529 else
530 channel(data, "%s", str);
531}
Daniel Veillard561b7f82002-03-20 21:55:57 +0000532
Daniel Veillarde356c282001-03-10 12:32:04 +0000533/**
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000534 * __xmlSimpleError:
535 * @domain: where the error comes from
536 * @code: the error code
537 * @node: the context node
538 * @extra: extra informations
539 *
540 * Handle an out of memory condition
541 */
542void
543__xmlSimpleError(int domain, int code, xmlNodePtr node,
544 const char *msg, const char *extra)
545{
546
547 if (code == XML_ERR_NO_MEMORY) {
548 if (extra)
549 __xmlRaiseError(NULL, NULL, NULL, node, domain,
550 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
551 NULL, NULL, 0, 0,
552 "Memory allocation failed : %s\n", extra);
553 else
554 __xmlRaiseError(NULL, NULL, NULL, node, domain,
555 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
556 NULL, NULL, 0, 0, "Memory allocation failed\n");
557 } else {
558 __xmlRaiseError(NULL, NULL, NULL, node, domain,
559 code, XML_ERR_ERROR, NULL, 0, extra,
560 NULL, NULL, 0, 0, msg, extra);
561 }
562}
563/**
Owen Taylor3473f882001-02-23 17:55:21 +0000564 * xmlParserError:
565 * @ctx: an XML parser context
566 * @msg: the message to display/transmit
567 * @...: extra parameters for the message display
568 *
569 * Display and format an error messages, gives file, line, position and
570 * extra parameters.
571 */
572void
573xmlParserError(void *ctx, const char *msg, ...)
574{
575 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
576 xmlParserInputPtr input = NULL;
577 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000578 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000579
580 if (ctxt != NULL) {
581 input = ctxt->input;
582 if ((input != NULL) && (input->filename == NULL) &&
583 (ctxt->inputNr > 1)) {
584 cur = input;
585 input = ctxt->inputTab[ctxt->inputNr - 2];
586 }
587 xmlParserPrintFileInfo(input);
588 }
589
590 xmlGenericError(xmlGenericErrorContext, "error: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000591 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000592 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000593 if (str != NULL)
594 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000595
596 if (ctxt != NULL) {
597 xmlParserPrintFileContext(input);
598 if (cur != NULL) {
599 xmlParserPrintFileInfo(cur);
600 xmlGenericError(xmlGenericErrorContext, "\n");
601 xmlParserPrintFileContext(cur);
602 }
603 }
604}
605
606/**
607 * xmlParserWarning:
608 * @ctx: an XML parser context
609 * @msg: the message to display/transmit
610 * @...: extra parameters for the message display
611 *
612 * Display and format a warning messages, gives file, line, position and
613 * extra parameters.
614 */
615void
616xmlParserWarning(void *ctx, const char *msg, ...)
617{
618 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
619 xmlParserInputPtr input = NULL;
620 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000621 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000622
623 if (ctxt != NULL) {
624 input = ctxt->input;
625 if ((input != NULL) && (input->filename == NULL) &&
626 (ctxt->inputNr > 1)) {
627 cur = input;
628 input = ctxt->inputTab[ctxt->inputNr - 2];
629 }
630 xmlParserPrintFileInfo(input);
631 }
632
633 xmlGenericError(xmlGenericErrorContext, "warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000634 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000635 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000636 if (str != NULL)
637 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000638
639 if (ctxt != NULL) {
640 xmlParserPrintFileContext(input);
641 if (cur != NULL) {
642 xmlParserPrintFileInfo(cur);
643 xmlGenericError(xmlGenericErrorContext, "\n");
644 xmlParserPrintFileContext(cur);
645 }
646 }
647}
648
649/************************************************************************
650 * *
651 * Handling of validation errors *
652 * *
653 ************************************************************************/
654
655/**
656 * xmlParserValidityError:
657 * @ctx: an XML parser context
658 * @msg: the message to display/transmit
659 * @...: extra parameters for the message display
660 *
661 * Display and format an validity error messages, gives file,
662 * line, position and extra parameters.
663 */
664void
665xmlParserValidityError(void *ctx, const char *msg, ...)
666{
667 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
668 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000669 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000670 int len = xmlStrlen((const xmlChar *) msg);
671 static int had_info = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000672
Daniel Veillard76575762002-09-05 14:21:15 +0000673 if ((len > 1) && (msg[len - 2] != ':')) {
674 if (ctxt != NULL) {
675 input = ctxt->input;
676 if ((input->filename == NULL) && (ctxt->inputNr > 1))
677 input = ctxt->inputTab[ctxt->inputNr - 2];
678
679 if (had_info == 0) {
680 xmlParserPrintFileInfo(input);
681 }
682 }
683 xmlGenericError(xmlGenericErrorContext, "validity error: ");
Daniel Veillard76575762002-09-05 14:21:15 +0000684 had_info = 0;
685 } else {
686 had_info = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000687 }
688
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000689 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000690 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000691 if (str != NULL)
692 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000693
Daniel Veillard76575762002-09-05 14:21:15 +0000694 if ((ctxt != NULL) && (input != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000695 xmlParserPrintFileContext(input);
696 }
697}
698
699/**
700 * xmlParserValidityWarning:
701 * @ctx: an XML parser context
702 * @msg: the message to display/transmit
703 * @...: extra parameters for the message display
704 *
705 * Display and format a validity warning messages, gives file, line,
706 * position and extra parameters.
707 */
708void
709xmlParserValidityWarning(void *ctx, const char *msg, ...)
710{
711 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
712 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000713 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000714 int len = xmlStrlen((const xmlChar *) msg);
Owen Taylor3473f882001-02-23 17:55:21 +0000715
Daniel Veillard76575762002-09-05 14:21:15 +0000716 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +0000717 input = ctxt->input;
718 if ((input->filename == NULL) && (ctxt->inputNr > 1))
719 input = ctxt->inputTab[ctxt->inputNr - 2];
720
721 xmlParserPrintFileInfo(input);
722 }
723
724 xmlGenericError(xmlGenericErrorContext, "validity warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000725 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000726 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000727 if (str != NULL)
728 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000729
730 if (ctxt != NULL) {
731 xmlParserPrintFileContext(input);
732 }
733}
734
735
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000736/************************************************************************
737 * *
738 * Extended Error Handling *
739 * *
740 ************************************************************************/
741
742/**
743 * xmlGetLastError:
744 *
745 * Get the last global error registered. This is per thread if compiled
746 * with thread support.
747 *
748 * Returns NULL if no error occured or a pointer to the error
749 */
750xmlErrorPtr
751xmlGetLastError(void)
752{
753 if (xmlLastError.code == XML_ERR_OK)
754 return (NULL);
755 return (&xmlLastError);
756}
757
758/**
759 * xmlResetError:
760 * @err: pointer to the error.
761 *
762 * Cleanup the error.
763 */
764void
765xmlResetError(xmlErrorPtr err)
766{
767 if (err == NULL)
768 return;
769 if (err->code == XML_ERR_OK)
770 return;
771 if (err->message != NULL)
772 xmlFree(err->message);
773 if (err->file != NULL)
774 xmlFree(err->file);
775 if (err->str1 != NULL)
776 xmlFree(err->str1);
777 if (err->str2 != NULL)
778 xmlFree(err->str2);
779 if (err->str3 != NULL)
780 xmlFree(err->str3);
781 memset(err, 0, sizeof(xmlError));
782 err->code = XML_ERR_OK;
783}
784
785/**
786 * xmlResetLastError:
787 *
788 * Cleanup the last global error registered. For parsing error
789 * this does not change the well-formedness result.
790 */
791void
792xmlResetLastError(void)
793{
794 if (xmlLastError.code == XML_ERR_OK)
795 return;
796 xmlResetError(&xmlLastError);
797}
798
799/**
800 * xmlCtxtGetLastError:
801 * @ctx: an XML parser context
802 *
803 * Get the last parsing error registered.
804 *
805 * Returns NULL if no error occured or a pointer to the error
806 */
807xmlErrorPtr
808xmlCtxtGetLastError(void *ctx)
809{
810 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
811
812 if (ctxt == NULL)
813 return (NULL);
814 if (ctxt->lastError.code == XML_ERR_OK)
815 return (NULL);
816 return (&ctxt->lastError);
817}
818
819/**
820 * xmlCtxtResetLastError:
821 * @ctx: an XML parser context
822 *
823 * Cleanup the last global error registered. For parsing error
824 * this does not change the well-formedness result.
825 */
826void
827xmlCtxtResetLastError(void *ctx)
828{
829 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
830
831 if (ctxt == NULL)
832 return;
833 if (ctxt->lastError.code == XML_ERR_OK)
834 return;
835 xmlResetError(&ctxt->lastError);
836}
837
838/**
839 * xmlCopyError:
840 * @from: a source error
841 * @to: a target error
842 *
843 * Save the original error to the new place.
844 *
845 * Returns 0 in case of success and -1 in case of error.
846 */
847int
848xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
849 if ((from == NULL) || (to == NULL))
850 return(-1);
851 if (to->message != NULL)
852 xmlFree(to->message);
853 if (to->file != NULL)
854 xmlFree(to->file);
855 if (to->str1 != NULL)
856 xmlFree(to->str1);
857 if (to->str2 != NULL)
858 xmlFree(to->str2);
859 if (to->str3 != NULL)
860 xmlFree(to->str3);
861 to->domain = from->domain;
862 to->code = from->code;
863 to->level = from->level;
864 to->line = from->line;
Daniel Veillard4c004142003-10-07 11:33:24 +0000865 to->node = from->node;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000866 to->int1 = from->int1;
867 to->int2 = from->int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000868 to->node = from->node;
869 to->ctxt = from->ctxt;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000870 if (from->message != NULL)
871 to->message = (char *) xmlStrdup((xmlChar *) from->message);
872 else
873 to->message = NULL;
874 if (from->file != NULL)
875 to->file = (char *) xmlStrdup((xmlChar *) from->file);
876 else
877 to->file = NULL;
878 if (from->str1 != NULL)
879 to->str1 = (char *) xmlStrdup((xmlChar *) from->str1);
880 else
881 to->str1 = NULL;
882 if (from->str2 != NULL)
883 to->str2 = (char *) xmlStrdup((xmlChar *) from->str2);
884 else
885 to->str2 = NULL;
886 if (from->str3 != NULL)
887 to->str3 = (char *) xmlStrdup((xmlChar *) from->str3);
888 else
889 to->str3 = NULL;
890 return(0);
891}
892