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