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