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