blob: b5d5fc31b23c574cb24a8fb4a3d3c7f095bd24da [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;
313 case XML_FROM_SCHEMAS:
314 channel(data, "Schemas ");
315 break;
Daniel Veillard4c004142003-10-07 11:33:24 +0000316 case XML_FROM_RELAXNGP:
317 channel(data, "Relax-NG parser ");
318 break;
319 case XML_FROM_RELAXNGV:
320 channel(data, "Relax-NG validaty ");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000321 break;
322 case XML_FROM_CATALOG:
323 channel(data, "Catalog ");
324 break;
325 case XML_FROM_C14N:
326 channel(data, "C14N ");
327 break;
328 case XML_FROM_XSLT:
329 channel(data, "XSLT ");
330 break;
331 default:
332 break;
333 }
334 if (code == XML_ERR_OK)
335 return;
336 switch (level) {
337 case XML_ERR_NONE:
338 channel(data, ": ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000339 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000340 case XML_ERR_WARNING:
341 channel(data, "warning : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000342 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000343 case XML_ERR_ERROR:
344 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000345 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000346 case XML_ERR_FATAL:
347 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000348 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000349 }
350 if (code == XML_ERR_OK)
351 return;
352 if (str != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +0000353 int len;
354 len = xmlStrlen((const xmlChar *)str);
355 if ((len > 0) && (str[len - 1] != '\n'))
356 channel(data, "%s", str);
357 else
358 channel(data, "%s\n", str);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000359 } else {
Daniel Veillard828ce832003-10-08 19:19:10 +0000360 channel(data, "%s\n", "out of memory error");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000361 }
362 if (code == XML_ERR_OK)
363 return;
364
365 if (ctxt != NULL) {
366 xmlParserPrintFileContextInternal(input, channel, data);
367 if (cur != NULL) {
368 if (cur->filename)
369 channel(data, "%s:%d: \n", cur->filename, cur->line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000370 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000371 channel(data, "Entity: line %d: \n", cur->line);
372 xmlParserPrintFileContextInternal(cur, channel, data);
373 }
374 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000375 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
376 (err->int1 < 100) &&
377 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
378 xmlChar buf[150];
379 int i;
380
381 channel(data, "%s\n", err->str1);
382 for (i=0;i < err->int1;i++)
383 buf[i] = ' ';
384 buf[i++] = '^';
385 buf[i] = 0;
386 channel(data, "%s\n", buf);
387 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000388}
389
390/**
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000391 * __xmlRaiseError:
392 * @channel: the callback channel
393 * @data: the callback data
394 * @ctx: the parser context or NULL
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000395 * @ctx: the parser context or NULL
396 * @domain: the domain for the error
397 * @code: the code for the error
398 * @level: the xmlErrorLevel for the error
399 * @file: the file source of the error (or NULL)
400 * @line: the line of the error or 0 if N/A
401 * @str1: extra string info
402 * @str2: extra string info
403 * @str3: extra string info
404 * @int1: extra int info
405 * @int2: extra int info
406 * @msg: the message to display/transmit
407 * @...: extra parameters for the message display
408 *
409 * Update teh appropriate global or contextual error structure,
410 * then forward the error message down the parser or generic
411 * error callback handler
412 */
413void
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000414__xmlRaiseError(xmlGenericErrorFunc channel, void *data, void *ctx,
415 void *nod, int domain, int code, xmlErrorLevel level,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000416 const char *file, int line, const char *str1,
417 const char *str2, const char *str3, int int1, int int2,
418 const char *msg, ...)
419{
420 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000421 xmlNodePtr node = (xmlNodePtr) nod;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000422 char *str = NULL;
423 xmlParserInputPtr input = NULL;
424 xmlErrorPtr to = &xmlLastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000425 xmlChar *base = NULL;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000426
427 if (code == XML_ERR_OK)
428 return;
429 /*
430 * Formatting the message
431 */
432 if (msg == NULL) {
433 str = (char *) xmlStrdup(BAD_CAST "No error message provided");
434 } else {
435 XML_GET_VAR_STR(msg, str);
436 }
437
438 /*
439 * specific processing if a parser context is provided
440 */
441 if (ctxt != NULL) {
442 if (file == NULL) {
443 input = ctxt->input;
444 if ((input != NULL) && (input->filename == NULL) &&
445 (ctxt->inputNr > 1)) {
446 input = ctxt->inputTab[ctxt->inputNr - 2];
447 }
448 if (input != NULL) {
449 file = input->filename;
450 line = input->line;
451 }
452 }
453 to = &ctxt->lastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000454 } else if ((node != NULL) && (file == NULL)) {
455 int i;
Daniel Veillard4c004142003-10-07 11:33:24 +0000456
457 if ((node->doc != NULL) && (node->doc->URL != NULL))
458 base = xmlStrdup(node->doc->URL);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000459 for (i = 0;
460 ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
461 i++)
462 node = node->parent;
Daniel Veillard4c004142003-10-07 11:33:24 +0000463 if ((base == NULL) && (node != NULL) &&
464 (node->doc != NULL) && (node->doc->URL != NULL))
465 base = xmlStrdup(node->doc->URL);
466
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000467 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
468 line = (int) node->content;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000469 }
470
471 /*
472 * Save the informations about the error
473 */
474 xmlResetError(to);
475 to->domain = domain;
476 to->code = code;
477 to->message = str;
478 to->level = level;
479 if (file != NULL)
480 to->file = (char *) xmlStrdup((const xmlChar *) file);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000481 else if (base != NULL) {
482 to->file = (char *) base;
483 file = (char *) base;
484 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000485 to->line = line;
486 if (str1 != NULL)
487 to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
488 if (str2 != NULL)
489 to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
490 if (str3 != NULL)
491 to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
492 to->int1 = int1;
493 to->int2 = int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000494 to->node = node;
495 to->ctxt = ctxt;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000496
497 /*
498 * Find the callback channel.
499 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000500 if ((ctxt != NULL) && (channel == NULL)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000501 if (level == XML_ERR_WARNING)
502 channel = ctxt->sax->warning;
503 else
504 channel = ctxt->sax->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000505 data = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000506 } else if (channel == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000507 channel = xmlGenericError;
508 data = xmlGenericErrorContext;
509 }
510 if (channel == NULL)
511 return;
512
513 if ((channel == xmlParserError) ||
514 (channel == xmlParserWarning) ||
515 (channel == xmlParserValidityError) ||
516 (channel == xmlParserValidityWarning))
Daniel Veillard4c004142003-10-07 11:33:24 +0000517 xmlReportError(to, ctxt, str, NULL, NULL);
518 else if ((channel == (xmlGenericErrorFunc) fprintf) ||
519 (channel == xmlGenericErrorDefaultFunc))
520 xmlReportError(to, ctxt, str, channel, data);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000521 else
522 channel(data, "%s", str);
523}
Daniel Veillard561b7f82002-03-20 21:55:57 +0000524
Daniel Veillarde356c282001-03-10 12:32:04 +0000525/**
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000526 * __xmlSimpleError:
527 * @domain: where the error comes from
528 * @code: the error code
529 * @node: the context node
530 * @extra: extra informations
531 *
532 * Handle an out of memory condition
533 */
534void
535__xmlSimpleError(int domain, int code, xmlNodePtr node,
536 const char *msg, const char *extra)
537{
538
539 if (code == XML_ERR_NO_MEMORY) {
540 if (extra)
541 __xmlRaiseError(NULL, NULL, NULL, node, domain,
542 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
543 NULL, NULL, 0, 0,
544 "Memory allocation failed : %s\n", extra);
545 else
546 __xmlRaiseError(NULL, NULL, NULL, node, domain,
547 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
548 NULL, NULL, 0, 0, "Memory allocation failed\n");
549 } else {
550 __xmlRaiseError(NULL, NULL, NULL, node, domain,
551 code, XML_ERR_ERROR, NULL, 0, extra,
552 NULL, NULL, 0, 0, msg, extra);
553 }
554}
555/**
Owen Taylor3473f882001-02-23 17:55:21 +0000556 * xmlParserError:
557 * @ctx: an XML parser context
558 * @msg: the message to display/transmit
559 * @...: extra parameters for the message display
560 *
561 * Display and format an error messages, gives file, line, position and
562 * extra parameters.
563 */
564void
565xmlParserError(void *ctx, const char *msg, ...)
566{
567 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
568 xmlParserInputPtr input = NULL;
569 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000570 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000571
572 if (ctxt != NULL) {
573 input = ctxt->input;
574 if ((input != NULL) && (input->filename == NULL) &&
575 (ctxt->inputNr > 1)) {
576 cur = input;
577 input = ctxt->inputTab[ctxt->inputNr - 2];
578 }
579 xmlParserPrintFileInfo(input);
580 }
581
582 xmlGenericError(xmlGenericErrorContext, "error: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000583 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000584 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000585 if (str != NULL)
586 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000587
588 if (ctxt != NULL) {
589 xmlParserPrintFileContext(input);
590 if (cur != NULL) {
591 xmlParserPrintFileInfo(cur);
592 xmlGenericError(xmlGenericErrorContext, "\n");
593 xmlParserPrintFileContext(cur);
594 }
595 }
596}
597
598/**
599 * xmlParserWarning:
600 * @ctx: an XML parser context
601 * @msg: the message to display/transmit
602 * @...: extra parameters for the message display
603 *
604 * Display and format a warning messages, gives file, line, position and
605 * extra parameters.
606 */
607void
608xmlParserWarning(void *ctx, const char *msg, ...)
609{
610 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
611 xmlParserInputPtr input = NULL;
612 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000613 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000614
615 if (ctxt != NULL) {
616 input = ctxt->input;
617 if ((input != NULL) && (input->filename == NULL) &&
618 (ctxt->inputNr > 1)) {
619 cur = input;
620 input = ctxt->inputTab[ctxt->inputNr - 2];
621 }
622 xmlParserPrintFileInfo(input);
623 }
624
625 xmlGenericError(xmlGenericErrorContext, "warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000626 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000627 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000628 if (str != NULL)
629 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000630
631 if (ctxt != NULL) {
632 xmlParserPrintFileContext(input);
633 if (cur != NULL) {
634 xmlParserPrintFileInfo(cur);
635 xmlGenericError(xmlGenericErrorContext, "\n");
636 xmlParserPrintFileContext(cur);
637 }
638 }
639}
640
641/************************************************************************
642 * *
643 * Handling of validation errors *
644 * *
645 ************************************************************************/
646
647/**
648 * xmlParserValidityError:
649 * @ctx: an XML parser context
650 * @msg: the message to display/transmit
651 * @...: extra parameters for the message display
652 *
653 * Display and format an validity error messages, gives file,
654 * line, position and extra parameters.
655 */
656void
657xmlParserValidityError(void *ctx, const char *msg, ...)
658{
659 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
660 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000661 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000662 int len = xmlStrlen((const xmlChar *) msg);
663 static int had_info = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000664
Daniel Veillard76575762002-09-05 14:21:15 +0000665 if ((len > 1) && (msg[len - 2] != ':')) {
666 if (ctxt != NULL) {
667 input = ctxt->input;
668 if ((input->filename == NULL) && (ctxt->inputNr > 1))
669 input = ctxt->inputTab[ctxt->inputNr - 2];
670
671 if (had_info == 0) {
672 xmlParserPrintFileInfo(input);
673 }
674 }
675 xmlGenericError(xmlGenericErrorContext, "validity error: ");
Daniel Veillard76575762002-09-05 14:21:15 +0000676 had_info = 0;
677 } else {
678 had_info = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000679 }
680
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000681 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000682 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000683 if (str != NULL)
684 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000685
Daniel Veillard76575762002-09-05 14:21:15 +0000686 if ((ctxt != NULL) && (input != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000687 xmlParserPrintFileContext(input);
688 }
689}
690
691/**
692 * xmlParserValidityWarning:
693 * @ctx: an XML parser context
694 * @msg: the message to display/transmit
695 * @...: extra parameters for the message display
696 *
697 * Display and format a validity warning messages, gives file, line,
698 * position and extra parameters.
699 */
700void
701xmlParserValidityWarning(void *ctx, const char *msg, ...)
702{
703 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
704 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000705 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000706 int len = xmlStrlen((const xmlChar *) msg);
Owen Taylor3473f882001-02-23 17:55:21 +0000707
Daniel Veillard76575762002-09-05 14:21:15 +0000708 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +0000709 input = ctxt->input;
710 if ((input->filename == NULL) && (ctxt->inputNr > 1))
711 input = ctxt->inputTab[ctxt->inputNr - 2];
712
713 xmlParserPrintFileInfo(input);
714 }
715
716 xmlGenericError(xmlGenericErrorContext, "validity warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000717 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000718 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000719 if (str != NULL)
720 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000721
722 if (ctxt != NULL) {
723 xmlParserPrintFileContext(input);
724 }
725}
726
727
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000728/************************************************************************
729 * *
730 * Extended Error Handling *
731 * *
732 ************************************************************************/
733
734/**
735 * xmlGetLastError:
736 *
737 * Get the last global error registered. This is per thread if compiled
738 * with thread support.
739 *
740 * Returns NULL if no error occured or a pointer to the error
741 */
742xmlErrorPtr
743xmlGetLastError(void)
744{
745 if (xmlLastError.code == XML_ERR_OK)
746 return (NULL);
747 return (&xmlLastError);
748}
749
750/**
751 * xmlResetError:
752 * @err: pointer to the error.
753 *
754 * Cleanup the error.
755 */
756void
757xmlResetError(xmlErrorPtr err)
758{
759 if (err == NULL)
760 return;
761 if (err->code == XML_ERR_OK)
762 return;
763 if (err->message != NULL)
764 xmlFree(err->message);
765 if (err->file != NULL)
766 xmlFree(err->file);
767 if (err->str1 != NULL)
768 xmlFree(err->str1);
769 if (err->str2 != NULL)
770 xmlFree(err->str2);
771 if (err->str3 != NULL)
772 xmlFree(err->str3);
773 memset(err, 0, sizeof(xmlError));
774 err->code = XML_ERR_OK;
775}
776
777/**
778 * xmlResetLastError:
779 *
780 * Cleanup the last global error registered. For parsing error
781 * this does not change the well-formedness result.
782 */
783void
784xmlResetLastError(void)
785{
786 if (xmlLastError.code == XML_ERR_OK)
787 return;
788 xmlResetError(&xmlLastError);
789}
790
791/**
792 * xmlCtxtGetLastError:
793 * @ctx: an XML parser context
794 *
795 * Get the last parsing error registered.
796 *
797 * Returns NULL if no error occured or a pointer to the error
798 */
799xmlErrorPtr
800xmlCtxtGetLastError(void *ctx)
801{
802 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
803
804 if (ctxt == NULL)
805 return (NULL);
806 if (ctxt->lastError.code == XML_ERR_OK)
807 return (NULL);
808 return (&ctxt->lastError);
809}
810
811/**
812 * xmlCtxtResetLastError:
813 * @ctx: an XML parser context
814 *
815 * Cleanup the last global error registered. For parsing error
816 * this does not change the well-formedness result.
817 */
818void
819xmlCtxtResetLastError(void *ctx)
820{
821 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
822
823 if (ctxt == NULL)
824 return;
825 if (ctxt->lastError.code == XML_ERR_OK)
826 return;
827 xmlResetError(&ctxt->lastError);
828}
829
830/**
831 * xmlCopyError:
832 * @from: a source error
833 * @to: a target error
834 *
835 * Save the original error to the new place.
836 *
837 * Returns 0 in case of success and -1 in case of error.
838 */
839int
840xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
841 if ((from == NULL) || (to == NULL))
842 return(-1);
843 if (to->message != NULL)
844 xmlFree(to->message);
845 if (to->file != NULL)
846 xmlFree(to->file);
847 if (to->str1 != NULL)
848 xmlFree(to->str1);
849 if (to->str2 != NULL)
850 xmlFree(to->str2);
851 if (to->str3 != NULL)
852 xmlFree(to->str3);
853 to->domain = from->domain;
854 to->code = from->code;
855 to->level = from->level;
856 to->line = from->line;
Daniel Veillard4c004142003-10-07 11:33:24 +0000857 to->node = from->node;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000858 to->int1 = from->int1;
859 to->int2 = from->int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000860 to->node = from->node;
861 to->ctxt = from->ctxt;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000862 if (from->message != NULL)
863 to->message = (char *) xmlStrdup((xmlChar *) from->message);
864 else
865 to->message = NULL;
866 if (from->file != NULL)
867 to->file = (char *) xmlStrdup((xmlChar *) from->file);
868 else
869 to->file = NULL;
870 if (from->str1 != NULL)
871 to->str1 = (char *) xmlStrdup((xmlChar *) from->str1);
872 else
873 to->str1 = NULL;
874 if (from->str2 != NULL)
875 to->str2 = (char *) xmlStrdup((xmlChar *) from->str2);
876 else
877 to->str2 = NULL;
878 if (from->str3 != NULL)
879 to->str3 = (char *) xmlStrdup((xmlChar *) from->str3);
880 else
881 to->str3 = NULL;
882 return(0);
883}
884