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