Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * error.c: module displaying/handling XML parser errors |
3 | | * |
4 | | * See Copyright for the status of this software. |
5 | | * |
6 | | * Daniel Veillard <daniel@veillard.com> |
7 | | */ |
8 | | |
9 | | #define IN_LIBXML |
10 | | #include "libxml.h" |
11 | | |
12 | | #include <string.h> |
13 | | #include <stdarg.h> |
14 | | #include <libxml/parser.h> |
15 | | #include <libxml/xmlerror.h> |
16 | | #include <libxml/xmlmemory.h> |
17 | | #include <libxml/globals.h> |
18 | | |
19 | | #include "private/error.h" |
20 | | |
21 | 0 | #define XML_MAX_ERRORS 100 |
22 | | |
23 | 2.60k | #define XML_GET_VAR_STR(msg, str) { \ |
24 | 2.60k | int size, prev_size = -1; \ |
25 | 2.60k | int chars; \ |
26 | 2.60k | char *larger; \ |
27 | 2.60k | va_list ap; \ |
28 | 2.60k | \ |
29 | 2.60k | str = (char *) xmlMalloc(150); \ |
30 | 2.60k | if (str != NULL) { \ |
31 | 2.60k | \ |
32 | 2.60k | size = 150; \ |
33 | 2.60k | \ |
34 | 5.20k | while (size < 64000) { \ |
35 | 5.20k | va_start(ap, msg); \ |
36 | 5.20k | chars = vsnprintf(str, size, msg, ap); \ |
37 | 5.20k | va_end(ap); \ |
38 | 5.20k | if ((chars > -1) && (chars < size)) { \ |
39 | 5.20k | if (prev_size == chars) { \ |
40 | 2.60k | break; \ |
41 | 2.60k | } else { \ |
42 | 2.60k | prev_size = chars; \ |
43 | 2.60k | } \ |
44 | 5.20k | } \ |
45 | 5.20k | if (chars > -1) \ |
46 | 2.60k | size += chars + 1; \ |
47 | 2.60k | else \ |
48 | 2.60k | size += 100; \ |
49 | 2.60k | if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\ |
50 | 0 | break; \ |
51 | 0 | } \ |
52 | 2.60k | str = larger; \ |
53 | 2.60k | }} \ |
54 | 2.60k | } |
55 | | |
56 | | /************************************************************************ |
57 | | * * |
58 | | * Handling of out of context errors * |
59 | | * * |
60 | | ************************************************************************/ |
61 | | |
62 | | /** |
63 | | * xmlGenericErrorDefaultFunc: |
64 | | * @ctx: an error context |
65 | | * @msg: the message to display/transmit |
66 | | * @...: extra parameters for the message display |
67 | | * |
68 | | * Default handler for out of context error messages. |
69 | | */ |
70 | | void |
71 | 0 | xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { |
72 | 0 | va_list args; |
73 | |
|
74 | 0 | if (xmlGenericErrorContext == NULL) |
75 | 0 | xmlGenericErrorContext = (void *) stderr; |
76 | |
|
77 | 0 | va_start(args, msg); |
78 | 0 | vfprintf((FILE *)xmlGenericErrorContext, msg, args); |
79 | 0 | va_end(args); |
80 | 0 | } |
81 | | |
82 | | /** |
83 | | * initGenericErrorDefaultFunc: |
84 | | * @handler: the handler |
85 | | * |
86 | | * DEPRECATED: Use xmlSetGenericErrorFunc. |
87 | | * |
88 | | * Set or reset (if NULL) the default handler for generic errors |
89 | | * to the builtin error function. |
90 | | */ |
91 | | void |
92 | | initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler) |
93 | 0 | { |
94 | 0 | if (handler == NULL) |
95 | 0 | xmlGenericError = xmlGenericErrorDefaultFunc; |
96 | 0 | else |
97 | 0 | xmlGenericError = (*handler); |
98 | 0 | } |
99 | | |
100 | | /** |
101 | | * xmlSetGenericErrorFunc: |
102 | | * @ctx: the new error handling context |
103 | | * @handler: the new handler function |
104 | | * |
105 | | * Function to reset the handler and the error context for out of |
106 | | * context error messages. |
107 | | * This simply means that @handler will be called for subsequent |
108 | | * error messages while not parsing nor validating. And @ctx will |
109 | | * be passed as first argument to @handler |
110 | | * One can simply force messages to be emitted to another FILE * than |
111 | | * stderr by setting @ctx to this file handle and @handler to NULL. |
112 | | * For multi-threaded applications, this must be set separately for each thread. |
113 | | */ |
114 | | void |
115 | 1.80k | xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { |
116 | 1.80k | xmlGenericErrorContext = ctx; |
117 | 1.80k | if (handler != NULL) |
118 | 1.80k | xmlGenericError = handler; |
119 | 0 | else |
120 | 0 | xmlGenericError = xmlGenericErrorDefaultFunc; |
121 | 1.80k | } |
122 | | |
123 | | /** |
124 | | * xmlSetStructuredErrorFunc: |
125 | | * @ctx: the new error handling context |
126 | | * @handler: the new handler function |
127 | | * |
128 | | * Function to reset the handler and the error context for out of |
129 | | * context structured error messages. |
130 | | * This simply means that @handler will be called for subsequent |
131 | | * error messages while not parsing nor validating. And @ctx will |
132 | | * be passed as first argument to @handler |
133 | | * For multi-threaded applications, this must be set separately for each thread. |
134 | | */ |
135 | | void |
136 | 0 | xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { |
137 | 0 | xmlStructuredErrorContext = ctx; |
138 | 0 | xmlStructuredError = handler; |
139 | 0 | } |
140 | | |
141 | | /************************************************************************ |
142 | | * * |
143 | | * Handling of parsing errors * |
144 | | * * |
145 | | ************************************************************************/ |
146 | | |
147 | | /** |
148 | | * xmlParserPrintFileInfo: |
149 | | * @input: an xmlParserInputPtr input |
150 | | * |
151 | | * Displays the associated file and line information for the current input |
152 | | */ |
153 | | |
154 | | void |
155 | 0 | xmlParserPrintFileInfo(xmlParserInputPtr input) { |
156 | 0 | if (input != NULL) { |
157 | 0 | if (input->filename) |
158 | 0 | xmlGenericError(xmlGenericErrorContext, |
159 | 0 | "%s:%d: ", input->filename, |
160 | 0 | input->line); |
161 | 0 | else |
162 | 0 | xmlGenericError(xmlGenericErrorContext, |
163 | 0 | "Entity: line %d: ", input->line); |
164 | 0 | } |
165 | 0 | } |
166 | | |
167 | | /** |
168 | | * xmlParserPrintFileContextInternal: |
169 | | * @input: an xmlParserInputPtr input |
170 | | * |
171 | | * Displays current context within the input content for error tracking |
172 | | */ |
173 | | |
174 | | static void |
175 | | xmlParserPrintFileContextInternal(xmlParserInputPtr input , |
176 | 0 | xmlGenericErrorFunc channel, void *data ) { |
177 | 0 | const xmlChar *cur, *base, *start; |
178 | 0 | unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ |
179 | 0 | xmlChar content[81]; /* space for 80 chars + line terminator */ |
180 | 0 | xmlChar *ctnt; |
181 | |
|
182 | 0 | if ((input == NULL) || (input->cur == NULL)) |
183 | 0 | return; |
184 | | |
185 | 0 | cur = input->cur; |
186 | 0 | base = input->base; |
187 | | /* skip backwards over any end-of-lines */ |
188 | 0 | while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { |
189 | 0 | cur--; |
190 | 0 | } |
191 | 0 | n = 0; |
192 | | /* search backwards for beginning-of-line (to max buff size) */ |
193 | 0 | while ((n < sizeof(content) - 1) && (cur > base) && |
194 | 0 | (*cur != '\n') && (*cur != '\r')) { |
195 | 0 | cur--; |
196 | 0 | n++; |
197 | 0 | } |
198 | 0 | if ((n > 0) && ((*cur == '\n') || (*cur == '\r'))) { |
199 | 0 | cur++; |
200 | 0 | } else { |
201 | | /* skip over continuation bytes */ |
202 | 0 | while ((cur < input->cur) && ((*cur & 0xC0) == 0x80)) |
203 | 0 | cur++; |
204 | 0 | } |
205 | | /* calculate the error position in terms of the current position */ |
206 | 0 | col = input->cur - cur; |
207 | | /* search forward for end-of-line (to max buff size) */ |
208 | 0 | n = 0; |
209 | 0 | start = cur; |
210 | | /* copy selected text to our buffer */ |
211 | 0 | while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) { |
212 | 0 | int len = input->end - cur; |
213 | 0 | int c = xmlGetUTF8Char(cur, &len); |
214 | |
|
215 | 0 | if ((c < 0) || (n + len > sizeof(content)-1)) |
216 | 0 | break; |
217 | 0 | cur += len; |
218 | 0 | n += len; |
219 | 0 | } |
220 | 0 | memcpy(content, start, n); |
221 | 0 | content[n] = 0; |
222 | | /* print out the selected text */ |
223 | 0 | channel(data ,"%s\n", content); |
224 | | /* create blank line with problem pointer */ |
225 | 0 | n = 0; |
226 | 0 | ctnt = content; |
227 | | /* (leave buffer space for pointer + line terminator) */ |
228 | 0 | while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) { |
229 | 0 | if (*(ctnt) != '\t') |
230 | 0 | *(ctnt) = ' '; |
231 | 0 | ctnt++; |
232 | 0 | } |
233 | 0 | *ctnt++ = '^'; |
234 | 0 | *ctnt = 0; |
235 | 0 | channel(data ,"%s\n", content); |
236 | 0 | } |
237 | | |
238 | | /** |
239 | | * xmlParserPrintFileContext: |
240 | | * @input: an xmlParserInputPtr input |
241 | | * |
242 | | * Displays current context within the input content for error tracking |
243 | | */ |
244 | | void |
245 | 0 | xmlParserPrintFileContext(xmlParserInputPtr input) { |
246 | 0 | xmlParserPrintFileContextInternal(input, xmlGenericError, |
247 | 0 | xmlGenericErrorContext); |
248 | 0 | } |
249 | | |
250 | | /** |
251 | | * xmlReportError: |
252 | | * @err: the error |
253 | | * @ctx: the parser context or NULL |
254 | | * @str: the formatted error message |
255 | | * |
256 | | * Report an error with its context, replace the 4 old error/warning |
257 | | * routines. |
258 | | */ |
259 | | static void |
260 | | xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, |
261 | | xmlGenericErrorFunc channel, void *data) |
262 | 0 | { |
263 | 0 | char *file = NULL; |
264 | 0 | int line = 0; |
265 | 0 | int code = -1; |
266 | 0 | int domain; |
267 | 0 | const xmlChar *name = NULL; |
268 | 0 | xmlNodePtr node; |
269 | 0 | xmlErrorLevel level; |
270 | 0 | xmlParserInputPtr input = NULL; |
271 | 0 | xmlParserInputPtr cur = NULL; |
272 | |
|
273 | 0 | if (err == NULL) |
274 | 0 | return; |
275 | | |
276 | 0 | if (channel == NULL) { |
277 | 0 | channel = xmlGenericError; |
278 | 0 | data = xmlGenericErrorContext; |
279 | 0 | } |
280 | 0 | file = err->file; |
281 | 0 | line = err->line; |
282 | 0 | code = err->code; |
283 | 0 | domain = err->domain; |
284 | 0 | level = err->level; |
285 | 0 | node = err->node; |
286 | |
|
287 | 0 | if (code == XML_ERR_OK) |
288 | 0 | return; |
289 | | |
290 | 0 | if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) |
291 | 0 | name = node->name; |
292 | | |
293 | | /* |
294 | | * Maintain the compatibility with the legacy error handling |
295 | | */ |
296 | 0 | if (ctxt != NULL) { |
297 | 0 | input = ctxt->input; |
298 | 0 | if ((input != NULL) && (input->filename == NULL) && |
299 | 0 | (ctxt->inputNr > 1)) { |
300 | 0 | cur = input; |
301 | 0 | input = ctxt->inputTab[ctxt->inputNr - 2]; |
302 | 0 | } |
303 | 0 | if (input != NULL) { |
304 | 0 | if (input->filename) |
305 | 0 | channel(data, "%s:%d: ", input->filename, input->line); |
306 | 0 | else if ((line != 0) && (domain == XML_FROM_PARSER)) |
307 | 0 | channel(data, "Entity: line %d: ", input->line); |
308 | 0 | } |
309 | 0 | } else { |
310 | 0 | if (file != NULL) |
311 | 0 | channel(data, "%s:%d: ", file, line); |
312 | 0 | else if ((line != 0) && |
313 | 0 | ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)|| |
314 | 0 | (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) || |
315 | 0 | (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV))) |
316 | 0 | channel(data, "Entity: line %d: ", line); |
317 | 0 | } |
318 | 0 | if (name != NULL) { |
319 | 0 | channel(data, "element %s: ", name); |
320 | 0 | } |
321 | 0 | switch (domain) { |
322 | 0 | case XML_FROM_PARSER: |
323 | 0 | channel(data, "parser "); |
324 | 0 | break; |
325 | 0 | case XML_FROM_NAMESPACE: |
326 | 0 | channel(data, "namespace "); |
327 | 0 | break; |
328 | 0 | case XML_FROM_DTD: |
329 | 0 | case XML_FROM_VALID: |
330 | 0 | channel(data, "validity "); |
331 | 0 | break; |
332 | 0 | case XML_FROM_HTML: |
333 | 0 | channel(data, "HTML parser "); |
334 | 0 | break; |
335 | 0 | case XML_FROM_MEMORY: |
336 | 0 | channel(data, "memory "); |
337 | 0 | break; |
338 | 0 | case XML_FROM_OUTPUT: |
339 | 0 | channel(data, "output "); |
340 | 0 | break; |
341 | 0 | case XML_FROM_IO: |
342 | 0 | channel(data, "I/O "); |
343 | 0 | break; |
344 | 0 | case XML_FROM_XINCLUDE: |
345 | 0 | channel(data, "XInclude "); |
346 | 0 | break; |
347 | 0 | case XML_FROM_XPATH: |
348 | 0 | channel(data, "XPath "); |
349 | 0 | break; |
350 | 0 | case XML_FROM_XPOINTER: |
351 | 0 | channel(data, "parser "); |
352 | 0 | break; |
353 | 0 | case XML_FROM_REGEXP: |
354 | 0 | channel(data, "regexp "); |
355 | 0 | break; |
356 | 0 | case XML_FROM_MODULE: |
357 | 0 | channel(data, "module "); |
358 | 0 | break; |
359 | 0 | case XML_FROM_SCHEMASV: |
360 | 0 | channel(data, "Schemas validity "); |
361 | 0 | break; |
362 | 0 | case XML_FROM_SCHEMASP: |
363 | 0 | channel(data, "Schemas parser "); |
364 | 0 | break; |
365 | 0 | case XML_FROM_RELAXNGP: |
366 | 0 | channel(data, "Relax-NG parser "); |
367 | 0 | break; |
368 | 0 | case XML_FROM_RELAXNGV: |
369 | 0 | channel(data, "Relax-NG validity "); |
370 | 0 | break; |
371 | 0 | case XML_FROM_CATALOG: |
372 | 0 | channel(data, "Catalog "); |
373 | 0 | break; |
374 | 0 | case XML_FROM_C14N: |
375 | 0 | channel(data, "C14N "); |
376 | 0 | break; |
377 | 0 | case XML_FROM_XSLT: |
378 | 0 | channel(data, "XSLT "); |
379 | 0 | break; |
380 | 0 | case XML_FROM_I18N: |
381 | 0 | channel(data, "encoding "); |
382 | 0 | break; |
383 | 0 | case XML_FROM_SCHEMATRONV: |
384 | 0 | channel(data, "schematron "); |
385 | 0 | break; |
386 | 0 | case XML_FROM_BUFFER: |
387 | 0 | channel(data, "internal buffer "); |
388 | 0 | break; |
389 | 0 | case XML_FROM_URI: |
390 | 0 | channel(data, "URI "); |
391 | 0 | break; |
392 | 0 | default: |
393 | 0 | break; |
394 | 0 | } |
395 | 0 | switch (level) { |
396 | 0 | case XML_ERR_NONE: |
397 | 0 | channel(data, ": "); |
398 | 0 | break; |
399 | 0 | case XML_ERR_WARNING: |
400 | 0 | channel(data, "warning : "); |
401 | 0 | break; |
402 | 0 | case XML_ERR_ERROR: |
403 | 0 | channel(data, "error : "); |
404 | 0 | break; |
405 | 0 | case XML_ERR_FATAL: |
406 | 0 | channel(data, "error : "); |
407 | 0 | break; |
408 | 0 | } |
409 | 0 | if (str != NULL) { |
410 | 0 | int len; |
411 | 0 | len = xmlStrlen((const xmlChar *)str); |
412 | 0 | if ((len > 0) && (str[len - 1] != '\n')) |
413 | 0 | channel(data, "%s\n", str); |
414 | 0 | else |
415 | 0 | channel(data, "%s", str); |
416 | 0 | } else { |
417 | 0 | channel(data, "%s\n", "out of memory error"); |
418 | 0 | } |
419 | |
|
420 | 0 | if (ctxt != NULL) { |
421 | 0 | xmlParserPrintFileContextInternal(input, channel, data); |
422 | 0 | if (cur != NULL) { |
423 | 0 | if (cur->filename) |
424 | 0 | channel(data, "%s:%d: \n", cur->filename, cur->line); |
425 | 0 | else if ((line != 0) && (domain == XML_FROM_PARSER)) |
426 | 0 | channel(data, "Entity: line %d: \n", cur->line); |
427 | 0 | xmlParserPrintFileContextInternal(cur, channel, data); |
428 | 0 | } |
429 | 0 | } |
430 | 0 | if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) && |
431 | 0 | (err->int1 < 100) && |
432 | 0 | (err->int1 < xmlStrlen((const xmlChar *)err->str1))) { |
433 | 0 | xmlChar buf[150]; |
434 | 0 | int i; |
435 | |
|
436 | 0 | channel(data, "%s\n", err->str1); |
437 | 0 | for (i=0;i < err->int1;i++) |
438 | 0 | buf[i] = ' '; |
439 | 0 | buf[i++] = '^'; |
440 | 0 | buf[i] = 0; |
441 | 0 | channel(data, "%s\n", buf); |
442 | 0 | } |
443 | 0 | } |
444 | | |
445 | | /** |
446 | | * __xmlRaiseError: |
447 | | * @schannel: the structured callback channel |
448 | | * @channel: the old callback channel |
449 | | * @data: the callback data |
450 | | * @ctx: the parser context or NULL |
451 | | * @ctx: the parser context or NULL |
452 | | * @domain: the domain for the error |
453 | | * @code: the code for the error |
454 | | * @level: the xmlErrorLevel for the error |
455 | | * @file: the file source of the error (or NULL) |
456 | | * @line: the line of the error or 0 if N/A |
457 | | * @str1: extra string info |
458 | | * @str2: extra string info |
459 | | * @str3: extra string info |
460 | | * @int1: extra int info |
461 | | * @col: column number of the error or 0 if N/A |
462 | | * @msg: the message to display/transmit |
463 | | * @...: extra parameters for the message display |
464 | | * |
465 | | * Update the appropriate global or contextual error structure, |
466 | | * then forward the error message down the parser or generic |
467 | | * error callback handler |
468 | | */ |
469 | | void |
470 | | __xmlRaiseError(xmlStructuredErrorFunc schannel, |
471 | | xmlGenericErrorFunc channel, void *data, void *ctx, |
472 | | void *nod, int domain, int code, xmlErrorLevel level, |
473 | | const char *file, int line, const char *str1, |
474 | | const char *str2, const char *str3, int int1, int col, |
475 | | const char *msg, ...) |
476 | 2.60k | { |
477 | 2.60k | xmlParserCtxtPtr ctxt = NULL; |
478 | 2.60k | xmlNodePtr node = (xmlNodePtr) nod; |
479 | 2.60k | char *str = NULL; |
480 | 2.60k | xmlParserInputPtr input = NULL; |
481 | 2.60k | xmlErrorPtr to = &xmlLastError; |
482 | 2.60k | xmlNodePtr baseptr = NULL; |
483 | | |
484 | 2.60k | if (code == XML_ERR_OK) |
485 | 0 | return; |
486 | 2.60k | if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING)) |
487 | 0 | return; |
488 | 2.60k | if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || |
489 | 2.60k | (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || |
490 | 2.60k | (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { |
491 | 0 | ctxt = (xmlParserCtxtPtr) ctx; |
492 | |
|
493 | 0 | if (ctxt != NULL) { |
494 | 0 | if (level == XML_ERR_WARNING) { |
495 | 0 | if (ctxt->nbWarnings >= XML_MAX_ERRORS) |
496 | 0 | return; |
497 | 0 | ctxt->nbWarnings += 1; |
498 | 0 | } else { |
499 | 0 | if (ctxt->nbErrors >= XML_MAX_ERRORS) |
500 | 0 | return; |
501 | 0 | ctxt->nbErrors += 1; |
502 | 0 | } |
503 | | |
504 | 0 | if ((schannel == NULL) && (ctxt->sax != NULL) && |
505 | 0 | (ctxt->sax->initialized == XML_SAX2_MAGIC) && |
506 | 0 | (ctxt->sax->serror != NULL)) { |
507 | 0 | schannel = ctxt->sax->serror; |
508 | 0 | data = ctxt->userData; |
509 | 0 | } |
510 | 0 | } |
511 | 0 | } |
512 | | /* |
513 | | * Check if structured error handler set |
514 | | */ |
515 | 2.60k | if (schannel == NULL) { |
516 | 2.60k | schannel = xmlStructuredError; |
517 | | /* |
518 | | * if user has defined handler, change data ptr to user's choice |
519 | | */ |
520 | 2.60k | if (schannel != NULL) |
521 | 0 | data = xmlStructuredErrorContext; |
522 | 2.60k | } |
523 | | /* |
524 | | * Formatting the message |
525 | | */ |
526 | 2.60k | if (msg == NULL) { |
527 | 0 | str = (char *) xmlStrdup(BAD_CAST "No error message provided"); |
528 | 2.60k | } else { |
529 | 2.60k | XML_GET_VAR_STR(msg, str); |
530 | 2.60k | } |
531 | | |
532 | | /* |
533 | | * specific processing if a parser context is provided |
534 | | */ |
535 | 2.60k | if (ctxt != NULL) { |
536 | 0 | if (file == NULL) { |
537 | 0 | input = ctxt->input; |
538 | 0 | if ((input != NULL) && (input->filename == NULL) && |
539 | 0 | (ctxt->inputNr > 1)) { |
540 | 0 | input = ctxt->inputTab[ctxt->inputNr - 2]; |
541 | 0 | } |
542 | 0 | if (input != NULL) { |
543 | 0 | file = input->filename; |
544 | 0 | line = input->line; |
545 | 0 | col = input->col; |
546 | 0 | } |
547 | 0 | } |
548 | 0 | to = &ctxt->lastError; |
549 | 2.60k | } else if ((node != NULL) && (file == NULL)) { |
550 | 0 | int i; |
551 | |
|
552 | 0 | if ((node->doc != NULL) && (node->doc->URL != NULL)) { |
553 | 0 | baseptr = node; |
554 | | /* file = (const char *) node->doc->URL; */ |
555 | 0 | } |
556 | 0 | for (i = 0; |
557 | 0 | ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE)); |
558 | 0 | i++) |
559 | 0 | node = node->parent; |
560 | 0 | if ((baseptr == NULL) && (node != NULL) && |
561 | 0 | (node->doc != NULL) && (node->doc->URL != NULL)) |
562 | 0 | baseptr = node; |
563 | |
|
564 | 0 | if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) |
565 | 0 | line = node->line; |
566 | 0 | if ((line == 0) || (line == 65535)) |
567 | 0 | line = xmlGetLineNo(node); |
568 | 0 | } |
569 | | |
570 | | /* |
571 | | * Save the information about the error |
572 | | */ |
573 | 2.60k | xmlResetError(to); |
574 | 2.60k | to->domain = domain; |
575 | 2.60k | to->code = code; |
576 | 2.60k | to->message = str; |
577 | 2.60k | to->level = level; |
578 | 2.60k | if (file != NULL) |
579 | 0 | to->file = (char *) xmlStrdup((const xmlChar *) file); |
580 | 2.60k | else if (baseptr != NULL) { |
581 | 0 | #ifdef LIBXML_XINCLUDE_ENABLED |
582 | | /* |
583 | | * We check if the error is within an XInclude section and, |
584 | | * if so, attempt to print out the href of the XInclude instead |
585 | | * of the usual "base" (doc->URL) for the node (bug 152623). |
586 | | */ |
587 | 0 | xmlNodePtr prev = baseptr; |
588 | 0 | char *href = NULL; |
589 | 0 | int inclcount = 0; |
590 | 0 | while (prev != NULL) { |
591 | 0 | if (prev->prev == NULL) |
592 | 0 | prev = prev->parent; |
593 | 0 | else { |
594 | 0 | prev = prev->prev; |
595 | 0 | if (prev->type == XML_XINCLUDE_START) { |
596 | 0 | if (inclcount > 0) { |
597 | 0 | --inclcount; |
598 | 0 | } else { |
599 | 0 | href = (char *) xmlGetProp(prev, BAD_CAST "href"); |
600 | 0 | if (href != NULL) |
601 | 0 | break; |
602 | 0 | } |
603 | 0 | } else if (prev->type == XML_XINCLUDE_END) |
604 | 0 | inclcount++; |
605 | 0 | } |
606 | 0 | } |
607 | 0 | if (href != NULL) |
608 | 0 | to->file = href; |
609 | 0 | else |
610 | 0 | #endif |
611 | 0 | to->file = (char *) xmlStrdup(baseptr->doc->URL); |
612 | 0 | if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) { |
613 | 0 | to->file = (char *) xmlStrdup(node->doc->URL); |
614 | 0 | } |
615 | 0 | } |
616 | 2.60k | to->line = line; |
617 | 2.60k | if (str1 != NULL) |
618 | 2.45k | to->str1 = (char *) xmlStrdup((const xmlChar *) str1); |
619 | 2.60k | if (str2 != NULL) |
620 | 0 | to->str2 = (char *) xmlStrdup((const xmlChar *) str2); |
621 | 2.60k | if (str3 != NULL) |
622 | 0 | to->str3 = (char *) xmlStrdup((const xmlChar *) str3); |
623 | 2.60k | to->int1 = int1; |
624 | 2.60k | to->int2 = col; |
625 | 2.60k | to->node = node; |
626 | 2.60k | to->ctxt = ctx; |
627 | | |
628 | 2.60k | if (to != &xmlLastError) |
629 | 0 | xmlCopyError(to,&xmlLastError); |
630 | | |
631 | 2.60k | if (schannel != NULL) { |
632 | 0 | schannel(data, to); |
633 | 0 | return; |
634 | 0 | } |
635 | | |
636 | | /* |
637 | | * Find the callback channel if channel param is NULL |
638 | | */ |
639 | 2.60k | if ((ctxt != NULL) && (channel == NULL) && |
640 | 2.60k | (xmlStructuredError == NULL) && (ctxt->sax != NULL)) { |
641 | 0 | if (level == XML_ERR_WARNING) |
642 | 0 | channel = ctxt->sax->warning; |
643 | 0 | else |
644 | 0 | channel = ctxt->sax->error; |
645 | 0 | data = ctxt->userData; |
646 | 2.60k | } else if (channel == NULL) { |
647 | 2.60k | channel = xmlGenericError; |
648 | 2.60k | if (ctxt != NULL) { |
649 | 0 | data = ctxt; |
650 | 2.60k | } else { |
651 | 2.60k | data = xmlGenericErrorContext; |
652 | 2.60k | } |
653 | 2.60k | } |
654 | 2.60k | if (channel == NULL) |
655 | 0 | return; |
656 | | |
657 | 2.60k | if ((channel == xmlParserError) || |
658 | 2.60k | (channel == xmlParserWarning) || |
659 | 2.60k | (channel == xmlParserValidityError) || |
660 | 2.60k | (channel == xmlParserValidityWarning)) |
661 | 0 | xmlReportError(to, ctxt, str, NULL, NULL); |
662 | 2.60k | else if (((void(*)(void)) channel == (void(*)(void)) fprintf) || |
663 | 2.60k | (channel == xmlGenericErrorDefaultFunc)) |
664 | 0 | xmlReportError(to, ctxt, str, channel, data); |
665 | 2.60k | else |
666 | 2.60k | channel(data, "%s", str); |
667 | 2.60k | } |
668 | | |
669 | | /** |
670 | | * __xmlSimpleError: |
671 | | * @domain: where the error comes from |
672 | | * @code: the error code |
673 | | * @node: the context node |
674 | | * @extra: extra information |
675 | | * |
676 | | * Handle an out of memory condition |
677 | | */ |
678 | | void |
679 | | __xmlSimpleError(int domain, int code, xmlNodePtr node, |
680 | | const char *msg, const char *extra) |
681 | 0 | { |
682 | |
|
683 | 0 | if (code == XML_ERR_NO_MEMORY) { |
684 | 0 | if (extra) |
685 | 0 | __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, |
686 | 0 | XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, |
687 | 0 | NULL, NULL, 0, 0, |
688 | 0 | "Memory allocation failed : %s\n", extra); |
689 | 0 | else |
690 | 0 | __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, |
691 | 0 | XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, |
692 | 0 | NULL, NULL, 0, 0, "Memory allocation failed\n"); |
693 | 0 | } else { |
694 | 0 | __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, |
695 | 0 | code, XML_ERR_ERROR, NULL, 0, extra, |
696 | 0 | NULL, NULL, 0, 0, msg, extra); |
697 | 0 | } |
698 | 0 | } |
699 | | /** |
700 | | * xmlParserError: |
701 | | * @ctx: an XML parser context |
702 | | * @msg: the message to display/transmit |
703 | | * @...: extra parameters for the message display |
704 | | * |
705 | | * Display and format an error messages, gives file, line, position and |
706 | | * extra parameters. |
707 | | */ |
708 | | void |
709 | | xmlParserError(void *ctx, const char *msg, ...) |
710 | 0 | { |
711 | 0 | xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; |
712 | 0 | xmlParserInputPtr input = NULL; |
713 | 0 | xmlParserInputPtr cur = NULL; |
714 | 0 | char * str; |
715 | |
|
716 | 0 | if (ctxt != NULL) { |
717 | 0 | input = ctxt->input; |
718 | 0 | if ((input != NULL) && (input->filename == NULL) && |
719 | 0 | (ctxt->inputNr > 1)) { |
720 | 0 | cur = input; |
721 | 0 | input = ctxt->inputTab[ctxt->inputNr - 2]; |
722 | 0 | } |
723 | 0 | xmlParserPrintFileInfo(input); |
724 | 0 | } |
725 | |
|
726 | 0 | xmlGenericError(xmlGenericErrorContext, "error: "); |
727 | 0 | XML_GET_VAR_STR(msg, str); |
728 | 0 | xmlGenericError(xmlGenericErrorContext, "%s", str); |
729 | 0 | if (str != NULL) |
730 | 0 | xmlFree(str); |
731 | |
|
732 | 0 | if (ctxt != NULL) { |
733 | 0 | xmlParserPrintFileContext(input); |
734 | 0 | if (cur != NULL) { |
735 | 0 | xmlParserPrintFileInfo(cur); |
736 | 0 | xmlGenericError(xmlGenericErrorContext, "\n"); |
737 | 0 | xmlParserPrintFileContext(cur); |
738 | 0 | } |
739 | 0 | } |
740 | 0 | } |
741 | | |
742 | | /** |
743 | | * xmlParserWarning: |
744 | | * @ctx: an XML parser context |
745 | | * @msg: the message to display/transmit |
746 | | * @...: extra parameters for the message display |
747 | | * |
748 | | * Display and format a warning messages, gives file, line, position and |
749 | | * extra parameters. |
750 | | */ |
751 | | void |
752 | | xmlParserWarning(void *ctx, const char *msg, ...) |
753 | 0 | { |
754 | 0 | xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; |
755 | 0 | xmlParserInputPtr input = NULL; |
756 | 0 | xmlParserInputPtr cur = NULL; |
757 | 0 | char * str; |
758 | |
|
759 | 0 | if (ctxt != NULL) { |
760 | 0 | input = ctxt->input; |
761 | 0 | if ((input != NULL) && (input->filename == NULL) && |
762 | 0 | (ctxt->inputNr > 1)) { |
763 | 0 | cur = input; |
764 | 0 | input = ctxt->inputTab[ctxt->inputNr - 2]; |
765 | 0 | } |
766 | 0 | xmlParserPrintFileInfo(input); |
767 | 0 | } |
768 | |
|
769 | 0 | xmlGenericError(xmlGenericErrorContext, "warning: "); |
770 | 0 | XML_GET_VAR_STR(msg, str); |
771 | 0 | xmlGenericError(xmlGenericErrorContext, "%s", str); |
772 | 0 | if (str != NULL) |
773 | 0 | xmlFree(str); |
774 | |
|
775 | 0 | if (ctxt != NULL) { |
776 | 0 | xmlParserPrintFileContext(input); |
777 | 0 | if (cur != NULL) { |
778 | 0 | xmlParserPrintFileInfo(cur); |
779 | 0 | xmlGenericError(xmlGenericErrorContext, "\n"); |
780 | 0 | xmlParserPrintFileContext(cur); |
781 | 0 | } |
782 | 0 | } |
783 | 0 | } |
784 | | |
785 | | /************************************************************************ |
786 | | * * |
787 | | * Handling of validation errors * |
788 | | * * |
789 | | ************************************************************************/ |
790 | | |
791 | | /** |
792 | | * xmlParserValidityError: |
793 | | * @ctx: an XML parser context |
794 | | * @msg: the message to display/transmit |
795 | | * @...: extra parameters for the message display |
796 | | * |
797 | | * Display and format an validity error messages, gives file, |
798 | | * line, position and extra parameters. |
799 | | */ |
800 | | void |
801 | | xmlParserValidityError(void *ctx, const char *msg, ...) |
802 | 0 | { |
803 | 0 | xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; |
804 | 0 | xmlParserInputPtr input = NULL; |
805 | 0 | char * str; |
806 | 0 | int len = xmlStrlen((const xmlChar *) msg); |
807 | 0 | static int had_info = 0; |
808 | |
|
809 | 0 | if ((len > 1) && (msg[len - 2] != ':')) { |
810 | 0 | if (ctxt != NULL) { |
811 | 0 | input = ctxt->input; |
812 | 0 | if ((input->filename == NULL) && (ctxt->inputNr > 1)) |
813 | 0 | input = ctxt->inputTab[ctxt->inputNr - 2]; |
814 | |
|
815 | 0 | if (had_info == 0) { |
816 | 0 | xmlParserPrintFileInfo(input); |
817 | 0 | } |
818 | 0 | } |
819 | 0 | xmlGenericError(xmlGenericErrorContext, "validity error: "); |
820 | 0 | had_info = 0; |
821 | 0 | } else { |
822 | 0 | had_info = 1; |
823 | 0 | } |
824 | |
|
825 | 0 | XML_GET_VAR_STR(msg, str); |
826 | 0 | xmlGenericError(xmlGenericErrorContext, "%s", str); |
827 | 0 | if (str != NULL) |
828 | 0 | xmlFree(str); |
829 | |
|
830 | 0 | if ((ctxt != NULL) && (input != NULL)) { |
831 | 0 | xmlParserPrintFileContext(input); |
832 | 0 | } |
833 | 0 | } |
834 | | |
835 | | /** |
836 | | * xmlParserValidityWarning: |
837 | | * @ctx: an XML parser context |
838 | | * @msg: the message to display/transmit |
839 | | * @...: extra parameters for the message display |
840 | | * |
841 | | * Display and format a validity warning messages, gives file, line, |
842 | | * position and extra parameters. |
843 | | */ |
844 | | void |
845 | | xmlParserValidityWarning(void *ctx, const char *msg, ...) |
846 | 0 | { |
847 | 0 | xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; |
848 | 0 | xmlParserInputPtr input = NULL; |
849 | 0 | char * str; |
850 | 0 | int len = xmlStrlen((const xmlChar *) msg); |
851 | |
|
852 | 0 | if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) { |
853 | 0 | input = ctxt->input; |
854 | 0 | if ((input->filename == NULL) && (ctxt->inputNr > 1)) |
855 | 0 | input = ctxt->inputTab[ctxt->inputNr - 2]; |
856 | |
|
857 | 0 | xmlParserPrintFileInfo(input); |
858 | 0 | } |
859 | |
|
860 | 0 | xmlGenericError(xmlGenericErrorContext, "validity warning: "); |
861 | 0 | XML_GET_VAR_STR(msg, str); |
862 | 0 | xmlGenericError(xmlGenericErrorContext, "%s", str); |
863 | 0 | if (str != NULL) |
864 | 0 | xmlFree(str); |
865 | |
|
866 | 0 | if (ctxt != NULL) { |
867 | 0 | xmlParserPrintFileContext(input); |
868 | 0 | } |
869 | 0 | } |
870 | | |
871 | | |
872 | | /************************************************************************ |
873 | | * * |
874 | | * Extended Error Handling * |
875 | | * * |
876 | | ************************************************************************/ |
877 | | |
878 | | /** |
879 | | * xmlGetLastError: |
880 | | * |
881 | | * Get the last global error registered. This is per thread if compiled |
882 | | * with thread support. |
883 | | * |
884 | | * Returns NULL if no error occurred or a pointer to the error |
885 | | */ |
886 | | xmlErrorPtr |
887 | | xmlGetLastError(void) |
888 | 0 | { |
889 | 0 | if (xmlLastError.code == XML_ERR_OK) |
890 | 0 | return (NULL); |
891 | 0 | return (&xmlLastError); |
892 | 0 | } |
893 | | |
894 | | /** |
895 | | * xmlResetError: |
896 | | * @err: pointer to the error. |
897 | | * |
898 | | * Cleanup the error. |
899 | | */ |
900 | | void |
901 | | xmlResetError(xmlErrorPtr err) |
902 | 5.20k | { |
903 | 5.20k | if (err == NULL) |
904 | 0 | return; |
905 | 5.20k | if (err->code == XML_ERR_OK) |
906 | 76 | return; |
907 | 5.13k | if (err->message != NULL) |
908 | 2.56k | xmlFree(err->message); |
909 | 5.13k | if (err->file != NULL) |
910 | 0 | xmlFree(err->file); |
911 | 5.13k | if (err->str1 != NULL) |
912 | 4.86k | xmlFree(err->str1); |
913 | 5.13k | if (err->str2 != NULL) |
914 | 0 | xmlFree(err->str2); |
915 | 5.13k | if (err->str3 != NULL) |
916 | 0 | xmlFree(err->str3); |
917 | 5.13k | memset(err, 0, sizeof(xmlError)); |
918 | 5.13k | err->code = XML_ERR_OK; |
919 | 5.13k | } |
920 | | |
921 | | /** |
922 | | * xmlResetLastError: |
923 | | * |
924 | | * Cleanup the last global error registered. For parsing error |
925 | | * this does not change the well-formedness result. |
926 | | */ |
927 | | void |
928 | | xmlResetLastError(void) |
929 | 0 | { |
930 | 0 | if (xmlLastError.code == XML_ERR_OK) |
931 | 0 | return; |
932 | 0 | xmlResetError(&xmlLastError); |
933 | 0 | } |
934 | | |
935 | | /** |
936 | | * xmlCtxtGetLastError: |
937 | | * @ctx: an XML parser context |
938 | | * |
939 | | * Get the last parsing error registered. |
940 | | * |
941 | | * Returns NULL if no error occurred or a pointer to the error |
942 | | */ |
943 | | xmlErrorPtr |
944 | | xmlCtxtGetLastError(void *ctx) |
945 | 0 | { |
946 | 0 | xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; |
947 | |
|
948 | 0 | if (ctxt == NULL) |
949 | 0 | return (NULL); |
950 | 0 | if (ctxt->lastError.code == XML_ERR_OK) |
951 | 0 | return (NULL); |
952 | 0 | return (&ctxt->lastError); |
953 | 0 | } |
954 | | |
955 | | /** |
956 | | * xmlCtxtResetLastError: |
957 | | * @ctx: an XML parser context |
958 | | * |
959 | | * Cleanup the last global error registered. For parsing error |
960 | | * this does not change the well-formedness result. |
961 | | */ |
962 | | void |
963 | | xmlCtxtResetLastError(void *ctx) |
964 | 0 | { |
965 | 0 | xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; |
966 | |
|
967 | 0 | if (ctxt == NULL) |
968 | 0 | return; |
969 | 0 | ctxt->errNo = XML_ERR_OK; |
970 | 0 | if (ctxt->lastError.code == XML_ERR_OK) |
971 | 0 | return; |
972 | 0 | xmlResetError(&ctxt->lastError); |
973 | 0 | } |
974 | | |
975 | | /** |
976 | | * xmlCopyError: |
977 | | * @from: a source error |
978 | | * @to: a target error |
979 | | * |
980 | | * Save the original error to the new place. |
981 | | * |
982 | | * Returns 0 in case of success and -1 in case of error. |
983 | | */ |
984 | | int |
985 | 0 | xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) { |
986 | 0 | char *message, *file, *str1, *str2, *str3; |
987 | |
|
988 | 0 | if ((from == NULL) || (to == NULL)) |
989 | 0 | return(-1); |
990 | | |
991 | 0 | message = (char *) xmlStrdup((xmlChar *) from->message); |
992 | 0 | file = (char *) xmlStrdup ((xmlChar *) from->file); |
993 | 0 | str1 = (char *) xmlStrdup ((xmlChar *) from->str1); |
994 | 0 | str2 = (char *) xmlStrdup ((xmlChar *) from->str2); |
995 | 0 | str3 = (char *) xmlStrdup ((xmlChar *) from->str3); |
996 | |
|
997 | 0 | if (to->message != NULL) |
998 | 0 | xmlFree(to->message); |
999 | 0 | if (to->file != NULL) |
1000 | 0 | xmlFree(to->file); |
1001 | 0 | if (to->str1 != NULL) |
1002 | 0 | xmlFree(to->str1); |
1003 | 0 | if (to->str2 != NULL) |
1004 | 0 | xmlFree(to->str2); |
1005 | 0 | if (to->str3 != NULL) |
1006 | 0 | xmlFree(to->str3); |
1007 | 0 | to->domain = from->domain; |
1008 | 0 | to->code = from->code; |
1009 | 0 | to->level = from->level; |
1010 | 0 | to->line = from->line; |
1011 | 0 | to->node = from->node; |
1012 | 0 | to->int1 = from->int1; |
1013 | 0 | to->int2 = from->int2; |
1014 | 0 | to->node = from->node; |
1015 | 0 | to->ctxt = from->ctxt; |
1016 | 0 | to->message = message; |
1017 | 0 | to->file = file; |
1018 | 0 | to->str1 = str1; |
1019 | 0 | to->str2 = str2; |
1020 | 0 | to->str3 = str3; |
1021 | |
|
1022 | 0 | return 0; |
1023 | 0 | } |
1024 | | |