blob: 3d4188bea1bd70954abc27930e4df06c0016b599 [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
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:
Daniel Veillard659e71e2003-10-10 14:10:40 +0000413 * @channel: the structured callback channel
414 * @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 *
431 * Update teh appropriate global or contextual error structure,
432 * 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 Veillardcd6ff282003-10-08 22:38:13 +0000450 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
451 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
452 (domain == XML_FROM_IO)) {
453 ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000454 if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
455 (ctxt->sax->initialized == XML_SAX2_MAGIC))
456 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000457 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000458 if ((domain == XML_FROM_VALID) &&
459 ((channel == xmlParserValidityError) ||
460 (channel == xmlParserValidityWarning))) {
461 ctxt = (xmlParserCtxtPtr) ctx;
462 if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
463 (ctxt->sax->initialized == XML_SAX2_MAGIC))
464 schannel = ctxt->sax->serror;
465 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000466 if (code == XML_ERR_OK)
467 return;
468 /*
469 * Formatting the message
470 */
471 if (msg == NULL) {
472 str = (char *) xmlStrdup(BAD_CAST "No error message provided");
473 } else {
474 XML_GET_VAR_STR(msg, str);
475 }
476
477 /*
478 * specific processing if a parser context is provided
479 */
480 if (ctxt != NULL) {
481 if (file == NULL) {
482 input = ctxt->input;
483 if ((input != NULL) && (input->filename == NULL) &&
484 (ctxt->inputNr > 1)) {
485 input = ctxt->inputTab[ctxt->inputNr - 2];
486 }
487 if (input != NULL) {
488 file = input->filename;
489 line = input->line;
490 }
491 }
492 to = &ctxt->lastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000493 } else if ((node != NULL) && (file == NULL)) {
494 int i;
Daniel Veillard4c004142003-10-07 11:33:24 +0000495
496 if ((node->doc != NULL) && (node->doc->URL != NULL))
497 base = xmlStrdup(node->doc->URL);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000498 for (i = 0;
499 ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
500 i++)
501 node = node->parent;
Daniel Veillard4c004142003-10-07 11:33:24 +0000502 if ((base == NULL) && (node != NULL) &&
503 (node->doc != NULL) && (node->doc->URL != NULL))
504 base = xmlStrdup(node->doc->URL);
505
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000506 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +0000507 line = node->line;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000508 }
509
510 /*
511 * Save the informations about the error
512 */
513 xmlResetError(to);
514 to->domain = domain;
515 to->code = code;
516 to->message = str;
517 to->level = level;
518 if (file != NULL)
519 to->file = (char *) xmlStrdup((const xmlChar *) file);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000520 else if (base != NULL) {
521 to->file = (char *) base;
522 file = (char *) base;
523 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000524 to->line = line;
525 if (str1 != NULL)
526 to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
527 if (str2 != NULL)
528 to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
529 if (str3 != NULL)
530 to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
531 to->int1 = int1;
532 to->int2 = int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000533 to->node = node;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000534 to->ctxt = ctx;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000535
536 /*
537 * Find the callback channel.
538 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000539 if ((ctxt != NULL) && (channel == NULL)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000540 if (level == XML_ERR_WARNING)
541 channel = ctxt->sax->warning;
542 else
543 channel = ctxt->sax->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000544 data = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000545 } else if (channel == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000546 if (xmlStructuredError != NULL)
547 schannel = xmlStructuredError;
548 else
549 channel = xmlGenericError;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000550 data = xmlGenericErrorContext;
551 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000552 if (schannel != NULL) {
553 schannel(data, to);
554 return;
555 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000556 if (channel == NULL)
557 return;
558
559 if ((channel == xmlParserError) ||
560 (channel == xmlParserWarning) ||
561 (channel == xmlParserValidityError) ||
562 (channel == xmlParserValidityWarning))
Daniel Veillard4c004142003-10-07 11:33:24 +0000563 xmlReportError(to, ctxt, str, NULL, NULL);
564 else if ((channel == (xmlGenericErrorFunc) fprintf) ||
565 (channel == xmlGenericErrorDefaultFunc))
566 xmlReportError(to, ctxt, str, channel, data);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000567 else
568 channel(data, "%s", str);
569}
Daniel Veillard561b7f82002-03-20 21:55:57 +0000570
Daniel Veillarde356c282001-03-10 12:32:04 +0000571/**
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000572 * __xmlSimpleError:
573 * @domain: where the error comes from
574 * @code: the error code
575 * @node: the context node
576 * @extra: extra informations
577 *
578 * Handle an out of memory condition
579 */
580void
581__xmlSimpleError(int domain, int code, xmlNodePtr node,
582 const char *msg, const char *extra)
583{
584
585 if (code == XML_ERR_NO_MEMORY) {
586 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000587 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000588 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
589 NULL, NULL, 0, 0,
590 "Memory allocation failed : %s\n", extra);
591 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000592 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000593 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
594 NULL, NULL, 0, 0, "Memory allocation failed\n");
595 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000596 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000597 code, XML_ERR_ERROR, NULL, 0, extra,
598 NULL, NULL, 0, 0, msg, extra);
599 }
600}
601/**
Owen Taylor3473f882001-02-23 17:55:21 +0000602 * xmlParserError:
603 * @ctx: an XML parser context
604 * @msg: the message to display/transmit
605 * @...: extra parameters for the message display
606 *
607 * Display and format an error messages, gives file, line, position and
608 * extra parameters.
609 */
610void
611xmlParserError(void *ctx, const char *msg, ...)
612{
613 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
614 xmlParserInputPtr input = NULL;
615 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000616 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000617
618 if (ctxt != NULL) {
619 input = ctxt->input;
620 if ((input != NULL) && (input->filename == NULL) &&
621 (ctxt->inputNr > 1)) {
622 cur = input;
623 input = ctxt->inputTab[ctxt->inputNr - 2];
624 }
625 xmlParserPrintFileInfo(input);
626 }
627
628 xmlGenericError(xmlGenericErrorContext, "error: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000629 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000630 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000631 if (str != NULL)
632 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000633
634 if (ctxt != NULL) {
635 xmlParserPrintFileContext(input);
636 if (cur != NULL) {
637 xmlParserPrintFileInfo(cur);
638 xmlGenericError(xmlGenericErrorContext, "\n");
639 xmlParserPrintFileContext(cur);
640 }
641 }
642}
643
644/**
645 * xmlParserWarning:
646 * @ctx: an XML parser context
647 * @msg: the message to display/transmit
648 * @...: extra parameters for the message display
649 *
650 * Display and format a warning messages, gives file, line, position and
651 * extra parameters.
652 */
653void
654xmlParserWarning(void *ctx, const char *msg, ...)
655{
656 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
657 xmlParserInputPtr input = NULL;
658 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000659 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000660
661 if (ctxt != NULL) {
662 input = ctxt->input;
663 if ((input != NULL) && (input->filename == NULL) &&
664 (ctxt->inputNr > 1)) {
665 cur = input;
666 input = ctxt->inputTab[ctxt->inputNr - 2];
667 }
668 xmlParserPrintFileInfo(input);
669 }
670
671 xmlGenericError(xmlGenericErrorContext, "warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000672 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000673 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000674 if (str != NULL)
675 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000676
677 if (ctxt != NULL) {
678 xmlParserPrintFileContext(input);
679 if (cur != NULL) {
680 xmlParserPrintFileInfo(cur);
681 xmlGenericError(xmlGenericErrorContext, "\n");
682 xmlParserPrintFileContext(cur);
683 }
684 }
685}
686
687/************************************************************************
688 * *
689 * Handling of validation errors *
690 * *
691 ************************************************************************/
692
693/**
694 * xmlParserValidityError:
695 * @ctx: an XML parser context
696 * @msg: the message to display/transmit
697 * @...: extra parameters for the message display
698 *
699 * Display and format an validity error messages, gives file,
700 * line, position and extra parameters.
701 */
702void
703xmlParserValidityError(void *ctx, const char *msg, ...)
704{
705 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
706 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000707 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000708 int len = xmlStrlen((const xmlChar *) msg);
709 static int had_info = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000710
Daniel Veillard76575762002-09-05 14:21:15 +0000711 if ((len > 1) && (msg[len - 2] != ':')) {
712 if (ctxt != NULL) {
713 input = ctxt->input;
714 if ((input->filename == NULL) && (ctxt->inputNr > 1))
715 input = ctxt->inputTab[ctxt->inputNr - 2];
716
717 if (had_info == 0) {
718 xmlParserPrintFileInfo(input);
719 }
720 }
721 xmlGenericError(xmlGenericErrorContext, "validity error: ");
Daniel Veillard76575762002-09-05 14:21:15 +0000722 had_info = 0;
723 } else {
724 had_info = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000725 }
726
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000727 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000728 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000729 if (str != NULL)
730 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000731
Daniel Veillard76575762002-09-05 14:21:15 +0000732 if ((ctxt != NULL) && (input != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000733 xmlParserPrintFileContext(input);
734 }
735}
736
737/**
738 * xmlParserValidityWarning:
739 * @ctx: an XML parser context
740 * @msg: the message to display/transmit
741 * @...: extra parameters for the message display
742 *
743 * Display and format a validity warning messages, gives file, line,
744 * position and extra parameters.
745 */
746void
747xmlParserValidityWarning(void *ctx, const char *msg, ...)
748{
749 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
750 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000751 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000752 int len = xmlStrlen((const xmlChar *) msg);
Owen Taylor3473f882001-02-23 17:55:21 +0000753
Daniel Veillard76575762002-09-05 14:21:15 +0000754 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +0000755 input = ctxt->input;
756 if ((input->filename == NULL) && (ctxt->inputNr > 1))
757 input = ctxt->inputTab[ctxt->inputNr - 2];
758
759 xmlParserPrintFileInfo(input);
760 }
761
762 xmlGenericError(xmlGenericErrorContext, "validity warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000763 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000764 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000765 if (str != NULL)
766 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000767
768 if (ctxt != NULL) {
769 xmlParserPrintFileContext(input);
770 }
771}
772
773
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000774/************************************************************************
775 * *
776 * Extended Error Handling *
777 * *
778 ************************************************************************/
779
780/**
781 * xmlGetLastError:
782 *
783 * Get the last global error registered. This is per thread if compiled
784 * with thread support.
785 *
786 * Returns NULL if no error occured or a pointer to the error
787 */
788xmlErrorPtr
789xmlGetLastError(void)
790{
791 if (xmlLastError.code == XML_ERR_OK)
792 return (NULL);
793 return (&xmlLastError);
794}
795
796/**
797 * xmlResetError:
798 * @err: pointer to the error.
799 *
800 * Cleanup the error.
801 */
802void
803xmlResetError(xmlErrorPtr err)
804{
805 if (err == NULL)
806 return;
807 if (err->code == XML_ERR_OK)
808 return;
809 if (err->message != NULL)
810 xmlFree(err->message);
811 if (err->file != NULL)
812 xmlFree(err->file);
813 if (err->str1 != NULL)
814 xmlFree(err->str1);
815 if (err->str2 != NULL)
816 xmlFree(err->str2);
817 if (err->str3 != NULL)
818 xmlFree(err->str3);
819 memset(err, 0, sizeof(xmlError));
820 err->code = XML_ERR_OK;
821}
822
823/**
824 * xmlResetLastError:
825 *
826 * Cleanup the last global error registered. For parsing error
827 * this does not change the well-formedness result.
828 */
829void
830xmlResetLastError(void)
831{
832 if (xmlLastError.code == XML_ERR_OK)
833 return;
834 xmlResetError(&xmlLastError);
835}
836
837/**
838 * xmlCtxtGetLastError:
839 * @ctx: an XML parser context
840 *
841 * Get the last parsing error registered.
842 *
843 * Returns NULL if no error occured or a pointer to the error
844 */
845xmlErrorPtr
846xmlCtxtGetLastError(void *ctx)
847{
848 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
849
850 if (ctxt == NULL)
851 return (NULL);
852 if (ctxt->lastError.code == XML_ERR_OK)
853 return (NULL);
854 return (&ctxt->lastError);
855}
856
857/**
858 * xmlCtxtResetLastError:
859 * @ctx: an XML parser context
860 *
861 * Cleanup the last global error registered. For parsing error
862 * this does not change the well-formedness result.
863 */
864void
865xmlCtxtResetLastError(void *ctx)
866{
867 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
868
869 if (ctxt == NULL)
870 return;
871 if (ctxt->lastError.code == XML_ERR_OK)
872 return;
873 xmlResetError(&ctxt->lastError);
874}
875
876/**
877 * xmlCopyError:
878 * @from: a source error
879 * @to: a target error
880 *
881 * Save the original error to the new place.
882 *
883 * Returns 0 in case of success and -1 in case of error.
884 */
885int
886xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
887 if ((from == NULL) || (to == NULL))
888 return(-1);
889 if (to->message != NULL)
890 xmlFree(to->message);
891 if (to->file != NULL)
892 xmlFree(to->file);
893 if (to->str1 != NULL)
894 xmlFree(to->str1);
895 if (to->str2 != NULL)
896 xmlFree(to->str2);
897 if (to->str3 != NULL)
898 xmlFree(to->str3);
899 to->domain = from->domain;
900 to->code = from->code;
901 to->level = from->level;
902 to->line = from->line;
Daniel Veillard4c004142003-10-07 11:33:24 +0000903 to->node = from->node;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000904 to->int1 = from->int1;
905 to->int2 = from->int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000906 to->node = from->node;
907 to->ctxt = from->ctxt;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000908 if (from->message != NULL)
909 to->message = (char *) xmlStrdup((xmlChar *) from->message);
910 else
911 to->message = NULL;
912 if (from->file != NULL)
913 to->file = (char *) xmlStrdup((xmlChar *) from->file);
914 else
915 to->file = NULL;
916 if (from->str1 != NULL)
917 to->str1 = (char *) xmlStrdup((xmlChar *) from->str1);
918 else
919 to->str1 = NULL;
920 if (from->str2 != NULL)
921 to->str2 = (char *) xmlStrdup((xmlChar *) from->str2);
922 else
923 to->str2 = NULL;
924 if (from->str3 != NULL)
925 to->str3 = (char *) xmlStrdup((xmlChar *) from->str3);
926 else
927 to->str3 = NULL;
928 return(0);
929}
930