blob: acf7ff3609b0ed0a24c189e1829d42e31d9c2aa0 [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:
304 channel(data, "validity ");
305 break;
306 case XML_FROM_HTML:
307 channel(data, "HTML parser ");
308 break;
309 case XML_FROM_MEMORY:
310 channel(data, "memory ");
311 break;
312 case XML_FROM_OUTPUT:
313 channel(data, "output ");
314 break;
315 case XML_FROM_IO:
316 channel(data, "I/O ");
317 break;
318 case XML_FROM_XINCLUDE:
319 channel(data, "XInclude ");
320 break;
321 case XML_FROM_XPATH:
322 channel(data, "XPath ");
323 break;
324 case XML_FROM_XPOINTER:
325 channel(data, "parser ");
326 break;
327 case XML_FROM_REGEXP:
328 channel(data, "regexp ");
329 break;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000330 case XML_FROM_SCHEMASV:
Daniel Veillard87db3a82003-10-10 10:52:58 +0000331 channel(data, "Schemas validity ");
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000332 break;
333 case XML_FROM_SCHEMASP:
Daniel Veillard87db3a82003-10-10 10:52:58 +0000334 channel(data, "Schemas parser ");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000335 break;
Daniel Veillard4c004142003-10-07 11:33:24 +0000336 case XML_FROM_RELAXNGP:
337 channel(data, "Relax-NG parser ");
338 break;
339 case XML_FROM_RELAXNGV:
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000340 channel(data, "Relax-NG validity ");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000341 break;
342 case XML_FROM_CATALOG:
343 channel(data, "Catalog ");
344 break;
345 case XML_FROM_C14N:
346 channel(data, "C14N ");
347 break;
348 case XML_FROM_XSLT:
349 channel(data, "XSLT ");
350 break;
351 default:
352 break;
353 }
354 if (code == XML_ERR_OK)
355 return;
356 switch (level) {
357 case XML_ERR_NONE:
358 channel(data, ": ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000359 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000360 case XML_ERR_WARNING:
361 channel(data, "warning : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000362 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000363 case XML_ERR_ERROR:
364 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000365 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000366 case XML_ERR_FATAL:
367 channel(data, "error : ");
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000368 break;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000369 }
370 if (code == XML_ERR_OK)
371 return;
372 if (str != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +0000373 int len;
374 len = xmlStrlen((const xmlChar *)str);
375 if ((len > 0) && (str[len - 1] != '\n'))
Daniel Veillard828ce832003-10-08 19:19:10 +0000376 channel(data, "%s\n", str);
Daniel Veillarda8856222003-10-08 19:26:03 +0000377 else
378 channel(data, "%s", str);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000379 } else {
Daniel Veillard828ce832003-10-08 19:19:10 +0000380 channel(data, "%s\n", "out of memory error");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000381 }
382 if (code == XML_ERR_OK)
383 return;
384
385 if (ctxt != NULL) {
386 xmlParserPrintFileContextInternal(input, channel, data);
387 if (cur != NULL) {
388 if (cur->filename)
389 channel(data, "%s:%d: \n", cur->filename, cur->line);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000390 else if ((line != 0) && (domain == XML_FROM_PARSER))
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000391 channel(data, "Entity: line %d: \n", cur->line);
392 xmlParserPrintFileContextInternal(cur, channel, data);
393 }
394 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000395 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
396 (err->int1 < 100) &&
397 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
398 xmlChar buf[150];
399 int i;
400
401 channel(data, "%s\n", err->str1);
402 for (i=0;i < err->int1;i++)
403 buf[i] = ' ';
404 buf[i++] = '^';
405 buf[i] = 0;
406 channel(data, "%s\n", buf);
407 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000408}
409
410/**
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000411 * __xmlRaiseError:
Daniel Veillard659e71e2003-10-10 14:10:40 +0000412 * @channel: the structured callback channel
413 * @channel: the old callback channel
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000414 * @data: the callback data
415 * @ctx: the parser context or NULL
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000416 * @ctx: the parser context or NULL
417 * @domain: the domain for the error
418 * @code: the code for the error
419 * @level: the xmlErrorLevel for the error
420 * @file: the file source of the error (or NULL)
421 * @line: the line of the error or 0 if N/A
422 * @str1: extra string info
423 * @str2: extra string info
424 * @str3: extra string info
425 * @int1: extra int info
426 * @int2: extra int info
427 * @msg: the message to display/transmit
428 * @...: extra parameters for the message display
429 *
430 * Update teh appropriate global or contextual error structure,
431 * then forward the error message down the parser or generic
432 * error callback handler
433 */
434void
Daniel Veillard659e71e2003-10-10 14:10:40 +0000435__xmlRaiseError(xmlStructuredErrorFunc schannel,
436 xmlGenericErrorFunc channel, void *data, void *ctx,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000437 void *nod, int domain, int code, xmlErrorLevel level,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000438 const char *file, int line, const char *str1,
439 const char *str2, const char *str3, int int1, int int2,
440 const char *msg, ...)
441{
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000442 xmlParserCtxtPtr ctxt = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000443 xmlNodePtr node = (xmlNodePtr) nod;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000444 char *str = NULL;
445 xmlParserInputPtr input = NULL;
446 xmlErrorPtr to = &xmlLastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000447 xmlChar *base = NULL;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000448
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000449 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
450 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
451 (domain == XML_FROM_IO)) {
452 ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000453 if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
454 (ctxt->sax->initialized == XML_SAX2_MAGIC))
455 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000456 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000457 if (code == XML_ERR_OK)
458 return;
459 /*
460 * Formatting the message
461 */
462 if (msg == NULL) {
463 str = (char *) xmlStrdup(BAD_CAST "No error message provided");
464 } else {
465 XML_GET_VAR_STR(msg, str);
466 }
467
468 /*
469 * specific processing if a parser context is provided
470 */
471 if (ctxt != NULL) {
472 if (file == NULL) {
473 input = ctxt->input;
474 if ((input != NULL) && (input->filename == NULL) &&
475 (ctxt->inputNr > 1)) {
476 input = ctxt->inputTab[ctxt->inputNr - 2];
477 }
478 if (input != NULL) {
479 file = input->filename;
480 line = input->line;
481 }
482 }
483 to = &ctxt->lastError;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000484 } else if ((node != NULL) && (file == NULL)) {
485 int i;
Daniel Veillard4c004142003-10-07 11:33:24 +0000486
487 if ((node->doc != NULL) && (node->doc->URL != NULL))
488 base = xmlStrdup(node->doc->URL);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000489 for (i = 0;
490 ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
491 i++)
492 node = node->parent;
Daniel Veillard4c004142003-10-07 11:33:24 +0000493 if ((base == NULL) && (node != NULL) &&
494 (node->doc != NULL) && (node->doc->URL != NULL))
495 base = xmlStrdup(node->doc->URL);
496
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000497 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
Daniel Veillard3e35f8e2003-10-21 00:05:38 +0000498 line = node->line;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000499 }
500
501 /*
502 * Save the informations about the error
503 */
504 xmlResetError(to);
505 to->domain = domain;
506 to->code = code;
507 to->message = str;
508 to->level = level;
509 if (file != NULL)
510 to->file = (char *) xmlStrdup((const xmlChar *) file);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000511 else if (base != NULL) {
512 to->file = (char *) base;
513 file = (char *) base;
514 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000515 to->line = line;
516 if (str1 != NULL)
517 to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
518 if (str2 != NULL)
519 to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
520 if (str3 != NULL)
521 to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
522 to->int1 = int1;
523 to->int2 = int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000524 to->node = node;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000525 to->ctxt = ctx;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000526
527 /*
528 * Find the callback channel.
529 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000530 if ((ctxt != NULL) && (channel == NULL)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000531 if (level == XML_ERR_WARNING)
532 channel = ctxt->sax->warning;
533 else
534 channel = ctxt->sax->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000535 data = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000536 } else if (channel == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000537 if (xmlStructuredError != NULL)
538 schannel = xmlStructuredError;
539 else
540 channel = xmlGenericError;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000541 data = xmlGenericErrorContext;
542 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000543 if (schannel != NULL) {
544 schannel(data, to);
545 return;
546 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000547 if (channel == NULL)
548 return;
549
550 if ((channel == xmlParserError) ||
551 (channel == xmlParserWarning) ||
552 (channel == xmlParserValidityError) ||
553 (channel == xmlParserValidityWarning))
Daniel Veillard4c004142003-10-07 11:33:24 +0000554 xmlReportError(to, ctxt, str, NULL, NULL);
555 else if ((channel == (xmlGenericErrorFunc) fprintf) ||
556 (channel == xmlGenericErrorDefaultFunc))
557 xmlReportError(to, ctxt, str, channel, data);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000558 else
559 channel(data, "%s", str);
560}
Daniel Veillard561b7f82002-03-20 21:55:57 +0000561
Daniel Veillarde356c282001-03-10 12:32:04 +0000562/**
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000563 * __xmlSimpleError:
564 * @domain: where the error comes from
565 * @code: the error code
566 * @node: the context node
567 * @extra: extra informations
568 *
569 * Handle an out of memory condition
570 */
571void
572__xmlSimpleError(int domain, int code, xmlNodePtr node,
573 const char *msg, const char *extra)
574{
575
576 if (code == XML_ERR_NO_MEMORY) {
577 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000578 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000579 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
580 NULL, NULL, 0, 0,
581 "Memory allocation failed : %s\n", extra);
582 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000583 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000584 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
585 NULL, NULL, 0, 0, "Memory allocation failed\n");
586 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000587 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000588 code, XML_ERR_ERROR, NULL, 0, extra,
589 NULL, NULL, 0, 0, msg, extra);
590 }
591}
592/**
Owen Taylor3473f882001-02-23 17:55:21 +0000593 * xmlParserError:
594 * @ctx: an XML parser context
595 * @msg: the message to display/transmit
596 * @...: extra parameters for the message display
597 *
598 * Display and format an error messages, gives file, line, position and
599 * extra parameters.
600 */
601void
602xmlParserError(void *ctx, const char *msg, ...)
603{
604 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
605 xmlParserInputPtr input = NULL;
606 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000607 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000608
609 if (ctxt != NULL) {
610 input = ctxt->input;
611 if ((input != NULL) && (input->filename == NULL) &&
612 (ctxt->inputNr > 1)) {
613 cur = input;
614 input = ctxt->inputTab[ctxt->inputNr - 2];
615 }
616 xmlParserPrintFileInfo(input);
617 }
618
619 xmlGenericError(xmlGenericErrorContext, "error: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000620 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000621 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000622 if (str != NULL)
623 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000624
625 if (ctxt != NULL) {
626 xmlParserPrintFileContext(input);
627 if (cur != NULL) {
628 xmlParserPrintFileInfo(cur);
629 xmlGenericError(xmlGenericErrorContext, "\n");
630 xmlParserPrintFileContext(cur);
631 }
632 }
633}
634
635/**
636 * xmlParserWarning:
637 * @ctx: an XML parser context
638 * @msg: the message to display/transmit
639 * @...: extra parameters for the message display
640 *
641 * Display and format a warning messages, gives file, line, position and
642 * extra parameters.
643 */
644void
645xmlParserWarning(void *ctx, const char *msg, ...)
646{
647 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
648 xmlParserInputPtr input = NULL;
649 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000650 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000651
652 if (ctxt != NULL) {
653 input = ctxt->input;
654 if ((input != NULL) && (input->filename == NULL) &&
655 (ctxt->inputNr > 1)) {
656 cur = input;
657 input = ctxt->inputTab[ctxt->inputNr - 2];
658 }
659 xmlParserPrintFileInfo(input);
660 }
661
662 xmlGenericError(xmlGenericErrorContext, "warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000663 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000664 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000665 if (str != NULL)
666 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000667
668 if (ctxt != NULL) {
669 xmlParserPrintFileContext(input);
670 if (cur != NULL) {
671 xmlParserPrintFileInfo(cur);
672 xmlGenericError(xmlGenericErrorContext, "\n");
673 xmlParserPrintFileContext(cur);
674 }
675 }
676}
677
678/************************************************************************
679 * *
680 * Handling of validation errors *
681 * *
682 ************************************************************************/
683
684/**
685 * xmlParserValidityError:
686 * @ctx: an XML parser context
687 * @msg: the message to display/transmit
688 * @...: extra parameters for the message display
689 *
690 * Display and format an validity error messages, gives file,
691 * line, position and extra parameters.
692 */
693void
694xmlParserValidityError(void *ctx, const char *msg, ...)
695{
696 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
697 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000698 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000699 int len = xmlStrlen((const xmlChar *) msg);
700 static int had_info = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000701
Daniel Veillard76575762002-09-05 14:21:15 +0000702 if ((len > 1) && (msg[len - 2] != ':')) {
703 if (ctxt != NULL) {
704 input = ctxt->input;
705 if ((input->filename == NULL) && (ctxt->inputNr > 1))
706 input = ctxt->inputTab[ctxt->inputNr - 2];
707
708 if (had_info == 0) {
709 xmlParserPrintFileInfo(input);
710 }
711 }
712 xmlGenericError(xmlGenericErrorContext, "validity error: ");
Daniel Veillard76575762002-09-05 14:21:15 +0000713 had_info = 0;
714 } else {
715 had_info = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000716 }
717
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000718 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000719 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000720 if (str != NULL)
721 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000722
Daniel Veillard76575762002-09-05 14:21:15 +0000723 if ((ctxt != NULL) && (input != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000724 xmlParserPrintFileContext(input);
725 }
726}
727
728/**
729 * xmlParserValidityWarning:
730 * @ctx: an XML parser context
731 * @msg: the message to display/transmit
732 * @...: extra parameters for the message display
733 *
734 * Display and format a validity warning messages, gives file, line,
735 * position and extra parameters.
736 */
737void
738xmlParserValidityWarning(void *ctx, const char *msg, ...)
739{
740 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
741 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000742 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000743 int len = xmlStrlen((const xmlChar *) msg);
Owen Taylor3473f882001-02-23 17:55:21 +0000744
Daniel Veillard76575762002-09-05 14:21:15 +0000745 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +0000746 input = ctxt->input;
747 if ((input->filename == NULL) && (ctxt->inputNr > 1))
748 input = ctxt->inputTab[ctxt->inputNr - 2];
749
750 xmlParserPrintFileInfo(input);
751 }
752
753 xmlGenericError(xmlGenericErrorContext, "validity warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000754 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000755 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000756 if (str != NULL)
757 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000758
759 if (ctxt != NULL) {
760 xmlParserPrintFileContext(input);
761 }
762}
763
764
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000765/************************************************************************
766 * *
767 * Extended Error Handling *
768 * *
769 ************************************************************************/
770
771/**
772 * xmlGetLastError:
773 *
774 * Get the last global error registered. This is per thread if compiled
775 * with thread support.
776 *
777 * Returns NULL if no error occured or a pointer to the error
778 */
779xmlErrorPtr
780xmlGetLastError(void)
781{
782 if (xmlLastError.code == XML_ERR_OK)
783 return (NULL);
784 return (&xmlLastError);
785}
786
787/**
788 * xmlResetError:
789 * @err: pointer to the error.
790 *
791 * Cleanup the error.
792 */
793void
794xmlResetError(xmlErrorPtr err)
795{
796 if (err == NULL)
797 return;
798 if (err->code == XML_ERR_OK)
799 return;
800 if (err->message != NULL)
801 xmlFree(err->message);
802 if (err->file != NULL)
803 xmlFree(err->file);
804 if (err->str1 != NULL)
805 xmlFree(err->str1);
806 if (err->str2 != NULL)
807 xmlFree(err->str2);
808 if (err->str3 != NULL)
809 xmlFree(err->str3);
810 memset(err, 0, sizeof(xmlError));
811 err->code = XML_ERR_OK;
812}
813
814/**
815 * xmlResetLastError:
816 *
817 * Cleanup the last global error registered. For parsing error
818 * this does not change the well-formedness result.
819 */
820void
821xmlResetLastError(void)
822{
823 if (xmlLastError.code == XML_ERR_OK)
824 return;
825 xmlResetError(&xmlLastError);
826}
827
828/**
829 * xmlCtxtGetLastError:
830 * @ctx: an XML parser context
831 *
832 * Get the last parsing error registered.
833 *
834 * Returns NULL if no error occured or a pointer to the error
835 */
836xmlErrorPtr
837xmlCtxtGetLastError(void *ctx)
838{
839 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
840
841 if (ctxt == NULL)
842 return (NULL);
843 if (ctxt->lastError.code == XML_ERR_OK)
844 return (NULL);
845 return (&ctxt->lastError);
846}
847
848/**
849 * xmlCtxtResetLastError:
850 * @ctx: an XML parser context
851 *
852 * Cleanup the last global error registered. For parsing error
853 * this does not change the well-formedness result.
854 */
855void
856xmlCtxtResetLastError(void *ctx)
857{
858 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
859
860 if (ctxt == NULL)
861 return;
862 if (ctxt->lastError.code == XML_ERR_OK)
863 return;
864 xmlResetError(&ctxt->lastError);
865}
866
867/**
868 * xmlCopyError:
869 * @from: a source error
870 * @to: a target error
871 *
872 * Save the original error to the new place.
873 *
874 * Returns 0 in case of success and -1 in case of error.
875 */
876int
877xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
878 if ((from == NULL) || (to == NULL))
879 return(-1);
880 if (to->message != NULL)
881 xmlFree(to->message);
882 if (to->file != NULL)
883 xmlFree(to->file);
884 if (to->str1 != NULL)
885 xmlFree(to->str1);
886 if (to->str2 != NULL)
887 xmlFree(to->str2);
888 if (to->str3 != NULL)
889 xmlFree(to->str3);
890 to->domain = from->domain;
891 to->code = from->code;
892 to->level = from->level;
893 to->line = from->line;
Daniel Veillard4c004142003-10-07 11:33:24 +0000894 to->node = from->node;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000895 to->int1 = from->int1;
896 to->int2 = from->int2;
Daniel Veillard4c004142003-10-07 11:33:24 +0000897 to->node = from->node;
898 to->ctxt = from->ctxt;
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000899 if (from->message != NULL)
900 to->message = (char *) xmlStrdup((xmlChar *) from->message);
901 else
902 to->message = NULL;
903 if (from->file != NULL)
904 to->file = (char *) xmlStrdup((xmlChar *) from->file);
905 else
906 to->file = NULL;
907 if (from->str1 != NULL)
908 to->str1 = (char *) xmlStrdup((xmlChar *) from->str1);
909 else
910 to->str1 = NULL;
911 if (from->str2 != NULL)
912 to->str2 = (char *) xmlStrdup((xmlChar *) from->str2);
913 else
914 to->str2 = NULL;
915 if (from->str3 != NULL)
916 to->str3 = (char *) xmlStrdup((xmlChar *) from->str3);
917 else
918 to->str3 = NULL;
919 return(0);
920}
921