blob: 96666932cbf8d6027608237d3419e98eab936d9f [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
Owen Taylor3473f882001-02-23 17:55:21 +000012#include <stdarg.h>
13#include <libxml/parser.h>
14#include <libxml/xmlerror.h>
Daniel Veillarde356c282001-03-10 12:32:04 +000015#include <libxml/xmlmemory.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000016#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000017
Daniel Veillard635ef722001-10-29 11:48:19 +000018void xmlGenericErrorDefaultFunc (void *ctx ATTRIBUTE_UNUSED,
19 const char *msg,
20 ...);
21
Daniel Veillard1c43dbf2001-06-05 17:12:52 +000022#define XML_GET_VAR_STR(msg, str) { \
23 int size; \
24 int chars; \
25 char *larger; \
26 va_list ap; \
27 \
28 str = (char *) xmlMalloc(150); \
29 if (str == NULL) \
30 return; \
31 \
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) {\
45 xmlFree(str); \
46 return; \
47 } \
48 str = larger; \
49 } \
50}
Bjorn Reese570ff082001-06-05 12:45:55 +000051
Owen Taylor3473f882001-02-23 17:55:21 +000052/************************************************************************
53 * *
54 * Handling of out of context errors *
55 * *
56 ************************************************************************/
57
58/**
59 * xmlGenericErrorDefaultFunc:
60 * @ctx: an error context
61 * @msg: the message to display/transmit
62 * @...: extra parameters for the message display
63 *
64 * Default handler for out of context error messages.
65 */
Daniel Veillard635ef722001-10-29 11:48:19 +000066void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +000067xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
Owen Taylor3473f882001-02-23 17:55:21 +000068 va_list args;
69
70 if (xmlGenericErrorContext == NULL)
71 xmlGenericErrorContext = (void *) stderr;
72
73 va_start(args, msg);
74 vfprintf((FILE *)xmlGenericErrorContext, msg, args);
75 va_end(args);
76}
77
Daniel Veillard9d06d302002-01-22 18:15:52 +000078/**
79 * initGenericErrorDefaultFunc:
80 * @handler: the handler
81 *
82 * Set or reset (if NULL) the default handler for generic errors
Daniel Veillard7424eb62003-01-24 14:14:52 +000083 * to the builtin error function.
Daniel Veillard9d06d302002-01-22 18:15:52 +000084 */
Daniel Veillardd0463562001-10-13 09:15:48 +000085void
Daniel Veillarddb5850a2002-01-18 11:49:26 +000086initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)
Daniel Veillardd0463562001-10-13 09:15:48 +000087{
Daniel Veillarddb5850a2002-01-18 11:49:26 +000088 if (handler == NULL)
89 xmlGenericError = xmlGenericErrorDefaultFunc;
90 else
91 (*handler) = xmlGenericErrorDefaultFunc;
Daniel Veillardd0463562001-10-13 09:15:48 +000092}
Owen Taylor3473f882001-02-23 17:55:21 +000093
94/**
95 * xmlSetGenericErrorFunc:
96 * @ctx: the new error handling context
97 * @handler: the new handler function
98 *
99 * Function to reset the handler and the error context for out of
100 * context error messages.
101 * This simply means that @handler will be called for subsequent
102 * error messages while not parsing nor validating. And @ctx will
103 * be passed as first argument to @handler
104 * One can simply force messages to be emitted to another FILE * than
105 * stderr by setting @ctx to this file handle and @handler to NULL.
106 */
107void
108xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
109 xmlGenericErrorContext = ctx;
110 if (handler != NULL)
111 xmlGenericError = handler;
112 else
113 xmlGenericError = xmlGenericErrorDefaultFunc;
114}
115
116/************************************************************************
117 * *
118 * Handling of parsing errors *
119 * *
120 ************************************************************************/
121
122/**
123 * xmlParserPrintFileInfo:
124 * @input: an xmlParserInputPtr input
125 *
126 * Displays the associated file and line informations for the current input
127 */
128
129void
130xmlParserPrintFileInfo(xmlParserInputPtr input) {
131 if (input != NULL) {
132 if (input->filename)
133 xmlGenericError(xmlGenericErrorContext,
134 "%s:%d: ", input->filename,
135 input->line);
136 else
137 xmlGenericError(xmlGenericErrorContext,
138 "Entity: line %d: ", input->line);
139 }
140}
141
142/**
143 * xmlParserPrintFileContext:
144 * @input: an xmlParserInputPtr input
145 *
146 * Displays current context within the input content for error tracking
147 */
148
149void
Daniel Veillard561b7f82002-03-20 21:55:57 +0000150xmlParserPrintFileContext(xmlParserInputPtr input) {
151 const xmlChar *cur, *base;
Owen Taylor3473f882001-02-23 17:55:21 +0000152 int n;
Daniel Veillard561b7f82002-03-20 21:55:57 +0000153 xmlChar content[81];
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 */
Daniel Veillard561b7f82002-03-20 21:55:57 +0000160 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
161 cur--;
Owen Taylor3473f882001-02-23 17:55:21 +0000162 }
163 n = 0;
Daniel Veillard2be30642001-03-27 00:32:28 +0000164 /* search backwards for beginning-of-line maximum 80 characters */
Daniel Veillard561b7f82002-03-20 21:55:57 +0000165 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
Owen Taylor3473f882001-02-23 17:55:21 +0000166 cur--;
Daniel Veillard561b7f82002-03-20 21:55:57 +0000167 if ((*cur == '\n') || (*cur == '\r')) cur++;
168 /* search forward for end-of-line maximum 80 characters */
Owen Taylor3473f882001-02-23 17:55:21 +0000169 n = 0;
Daniel Veillard2be30642001-03-27 00:32:28 +0000170 ctnt = content;
Daniel Veillard561b7f82002-03-20 21:55:57 +0000171 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
172 *ctnt++ = *cur++;
173 n++;
Owen Taylor3473f882001-02-23 17:55:21 +0000174 }
Daniel Veillard2be30642001-03-27 00:32:28 +0000175 *ctnt = 0;
Daniel Veillard561b7f82002-03-20 21:55:57 +0000176 xmlGenericError(xmlGenericErrorContext,"%s\n", content);
Daniel Veillard2be30642001-03-27 00:32:28 +0000177 /* create blank line with problem pointer */
Owen Taylor3473f882001-02-23 17:55:21 +0000178 cur = input->cur;
Daniel Veillard561b7f82002-03-20 21:55:57 +0000179 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
180 cur--;
181 }
Owen Taylor3473f882001-02-23 17:55:21 +0000182 n = 0;
Daniel Veillard7533cc82001-04-24 15:52:00 +0000183 ctnt = content;
Daniel Veillard561b7f82002-03-20 21:55:57 +0000184 while ((n++ < 79) && (cur > base) && (*cur != '\n') && (*cur != '\r')) {
185 *ctnt++ = ' ';
186 cur--;
Owen Taylor3473f882001-02-23 17:55:21 +0000187 }
Daniel Veillard5a7c3452001-04-26 09:16:13 +0000188 if (ctnt > content) {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000189 *(--ctnt) = '^';
190 *(++ctnt) = 0;
Daniel Veillard5a7c3452001-04-26 09:16:13 +0000191 } else {
Daniel Veillard561b7f82002-03-20 21:55:57 +0000192 *ctnt = '^';
193 *(++ctnt) = 0;
Daniel Veillard5a7c3452001-04-26 09:16:13 +0000194 }
Daniel Veillard561b7f82002-03-20 21:55:57 +0000195 xmlGenericError(xmlGenericErrorContext,"%s\n", content);
Owen Taylor3473f882001-02-23 17:55:21 +0000196}
197
Daniel Veillard561b7f82002-03-20 21:55:57 +0000198#if 0
199/**
200 * xmlGetVarStr:
201 * @msg: the message format
202 * @args: a va_list argument list
203 *
204 * SGS contribution
205 * Get an arbitrary-sized string for an error argument
206 * The caller must free() the returned string
207 */
208static char *
209xmlGetVarStr(const char * msg, va_list args) {
210 int size;
211 int length;
212 int chars, left;
213 char *str, *larger;
214 va_list ap;
215
216 str = (char *) xmlMalloc(150);
217 if (str == NULL)
218 return(NULL);
219
220 size = 150;
221 length = 0;
222
223 while (1) {
224 left = size - length;
225 /* Try to print in the allocated space. */
226 va_start(msg, ap);
227 chars = vsnprintf(str + length, left, msg, ap);
228 va_end(ap);
229 /* If that worked, we're done. */
230 if ((chars > -1) && (chars < left ))
231 break;
232 /* Else try again with more space. */
233 if (chars > -1) /* glibc 2.1 */
234 size += chars + 1; /* precisely what is needed */
235 else /* glibc 2.0 */
236 size += 100;
237 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
238 xmlFree(str);
239 return(NULL);
240 }
241 str = larger;
242 }
243 return(str);
244}
245#endif
246
Daniel Veillarde356c282001-03-10 12:32:04 +0000247/**
Owen Taylor3473f882001-02-23 17:55:21 +0000248 * xmlParserError:
249 * @ctx: an XML parser context
250 * @msg: the message to display/transmit
251 * @...: extra parameters for the message display
252 *
253 * Display and format an error messages, gives file, line, position and
254 * extra parameters.
255 */
256void
257xmlParserError(void *ctx, const char *msg, ...)
258{
259 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
260 xmlParserInputPtr input = NULL;
261 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000262 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000263
264 if (ctxt != NULL) {
265 input = ctxt->input;
266 if ((input != NULL) && (input->filename == NULL) &&
267 (ctxt->inputNr > 1)) {
268 cur = input;
269 input = ctxt->inputTab[ctxt->inputNr - 2];
270 }
271 xmlParserPrintFileInfo(input);
272 }
273
274 xmlGenericError(xmlGenericErrorContext, "error: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000275 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000276 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000277 if (str != NULL)
278 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000279
280 if (ctxt != NULL) {
281 xmlParserPrintFileContext(input);
282 if (cur != NULL) {
283 xmlParserPrintFileInfo(cur);
284 xmlGenericError(xmlGenericErrorContext, "\n");
285 xmlParserPrintFileContext(cur);
286 }
287 }
288}
289
290/**
291 * xmlParserWarning:
292 * @ctx: an XML parser context
293 * @msg: the message to display/transmit
294 * @...: extra parameters for the message display
295 *
296 * Display and format a warning messages, gives file, line, position and
297 * extra parameters.
298 */
299void
300xmlParserWarning(void *ctx, const char *msg, ...)
301{
302 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
303 xmlParserInputPtr input = NULL;
304 xmlParserInputPtr cur = NULL;
Daniel Veillarde356c282001-03-10 12:32:04 +0000305 char * str;
Owen Taylor3473f882001-02-23 17:55:21 +0000306
307 if (ctxt != NULL) {
308 input = ctxt->input;
309 if ((input != NULL) && (input->filename == NULL) &&
310 (ctxt->inputNr > 1)) {
311 cur = input;
312 input = ctxt->inputTab[ctxt->inputNr - 2];
313 }
314 xmlParserPrintFileInfo(input);
315 }
316
317 xmlGenericError(xmlGenericErrorContext, "warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000318 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000319 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000320 if (str != NULL)
321 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000322
323 if (ctxt != NULL) {
324 xmlParserPrintFileContext(input);
325 if (cur != NULL) {
326 xmlParserPrintFileInfo(cur);
327 xmlGenericError(xmlGenericErrorContext, "\n");
328 xmlParserPrintFileContext(cur);
329 }
330 }
331}
332
333/************************************************************************
334 * *
335 * Handling of validation errors *
336 * *
337 ************************************************************************/
338
339/**
340 * xmlParserValidityError:
341 * @ctx: an XML parser context
342 * @msg: the message to display/transmit
343 * @...: extra parameters for the message display
344 *
345 * Display and format an validity error messages, gives file,
346 * line, position and extra parameters.
347 */
348void
349xmlParserValidityError(void *ctx, const char *msg, ...)
350{
351 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
352 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000353 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000354 int len = xmlStrlen((const xmlChar *) msg);
355 static int had_info = 0;
356 int need_context = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000357
Daniel Veillard76575762002-09-05 14:21:15 +0000358 if ((len > 1) && (msg[len - 2] != ':')) {
359 if (ctxt != NULL) {
360 input = ctxt->input;
361 if ((input->filename == NULL) && (ctxt->inputNr > 1))
362 input = ctxt->inputTab[ctxt->inputNr - 2];
363
364 if (had_info == 0) {
365 xmlParserPrintFileInfo(input);
366 }
367 }
368 xmlGenericError(xmlGenericErrorContext, "validity error: ");
369 need_context = 1;
370 had_info = 0;
371 } else {
372 had_info = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000373 }
374
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000375 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000376 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000377 if (str != NULL)
378 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000379
Daniel Veillard76575762002-09-05 14:21:15 +0000380 if ((ctxt != NULL) && (input != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000381 xmlParserPrintFileContext(input);
382 }
383}
384
385/**
386 * xmlParserValidityWarning:
387 * @ctx: an XML parser context
388 * @msg: the message to display/transmit
389 * @...: extra parameters for the message display
390 *
391 * Display and format a validity warning messages, gives file, line,
392 * position and extra parameters.
393 */
394void
395xmlParserValidityWarning(void *ctx, const char *msg, ...)
396{
397 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
398 xmlParserInputPtr input = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000399 char * str;
Daniel Veillard76575762002-09-05 14:21:15 +0000400 int len = xmlStrlen((const xmlChar *) msg);
Owen Taylor3473f882001-02-23 17:55:21 +0000401
Daniel Veillard76575762002-09-05 14:21:15 +0000402 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +0000403 input = ctxt->input;
404 if ((input->filename == NULL) && (ctxt->inputNr > 1))
405 input = ctxt->inputTab[ctxt->inputNr - 2];
406
407 xmlParserPrintFileInfo(input);
408 }
409
410 xmlGenericError(xmlGenericErrorContext, "validity warning: ");
Daniel Veillard1c43dbf2001-06-05 17:12:52 +0000411 XML_GET_VAR_STR(msg, str);
Daniel Veillard635ef722001-10-29 11:48:19 +0000412 xmlGenericError(xmlGenericErrorContext, "%s", str);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413 if (str != NULL)
414 xmlFree(str);
Owen Taylor3473f882001-02-23 17:55:21 +0000415
416 if (ctxt != NULL) {
417 xmlParserPrintFileContext(input);
418 }
419}
420
421