• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
xmlGenericErrorDefaultFunc(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)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
initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)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
xmlSetGenericErrorFunc(void * ctx,xmlGenericErrorFunc handler)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
xmlSetStructuredErrorFunc(void * ctx,xmlStructuredErrorFunc handler)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
xmlParserPrintFileInfo(xmlParserInputPtr input)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
xmlParserPrintFileContextInternal(xmlParserInputPtr input,xmlGenericErrorFunc channel,void * data)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
xmlParserPrintFileContext(xmlParserInputPtr input)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
xmlReportError(xmlErrorPtr err,xmlParserCtxtPtr ctxt,const char * str,xmlGenericErrorFunc channel,void * data)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
__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,...)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
__xmlSimpleError(int domain,int code,xmlNodePtr node,const char * msg,const char * extra)651  __xmlSimpleError(int domain, int code, xmlNodePtr node,
652                   const char *msg, const char *extra)
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
xmlParserError(void * ctx,const char * msg,...)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
xmlParserWarning(void * ctx,const char * msg,...)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
xmlParserValidityError(void * ctx,const char * msg,...)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
xmlParserValidityWarning(void * ctx,const char * msg,...)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 occured or a pointer to the error
857   */
858  xmlErrorPtr
xmlGetLastError(void)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
xmlResetError(xmlErrorPtr err)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
xmlResetLastError(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 occured or a pointer to the error
914   */
915  xmlErrorPtr
xmlCtxtGetLastError(void * ctx)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
xmlCtxtResetLastError(void * ctx)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
xmlCopyError(xmlErrorPtr from,xmlErrorPtr to)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