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