error.c 26.7 KB
Newer Older
1 2 3 4 5
/*
 * error.c: module displaying/handling XML parser errors
 *
 * See Copyright for the status of this software.
 *
6
 * Daniel Veillard <daniel@veillard.com>
7 8
 */

9
#define IN_LIBXML
10
#include "libxml.h"
11

12
#include <string.h>
13 14 15
#include <stdarg.h>
#include <libxml/parser.h>
#include <libxml/xmlerror.h>
16
#include <libxml/xmlmemory.h>
17
#include <libxml/globals.h>
18

19
void XMLCDECL xmlGenericErrorDefaultFunc	(void *ctx ATTRIBUTE_UNUSED,
20 21 22
				 const char *msg,
				 ...);

23
#define XML_GET_VAR_STR(msg, str) {				\
24
    int       size, prev_size = -1;				\
25 26 27 28 29
    int       chars;						\
    char      *larger;						\
    va_list   ap;						\
								\
    str = (char *) xmlMalloc(150);				\
30
    if (str != NULL) {						\
31 32 33
								\
    size = 150;							\
								\
34
    while (size < 64000) {					\
35
	va_start(ap, msg);					\
36
	chars = vsnprintf(str, size, msg, ap);			\
37
	va_end(ap);						\
38 39 40 41 42 43 44
	if ((chars > -1) && (chars < size)) {			\
	    if (prev_size == chars) {				\
		break;						\
	    } else {						\
		prev_size = chars;				\
	    }							\
	}							\
45 46 47 48 49
	if (chars > -1)						\
	    size += chars + 1;					\
	else							\
	    size += 100;					\
	if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
50
	    break;						\
51 52
	}							\
	str = larger;						\
53
    }}								\
54
}
55

56
/************************************************************************
57 58 59
 *									*
 *			Handling of out of context errors		*
 *									*
60 61 62 63 64 65 66
 ************************************************************************/

/**
 * xmlGenericErrorDefaultFunc:
 * @ctx:  an error context
 * @msg:  the message to display/transmit
 * @...:  extra parameters for the message display
67
 *
68 69
 * Default handler for out of context error messages.
 */
70
void XMLCDECL
71
xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
72 73 74 75 76 77 78 79 80 81
    va_list args;

    if (xmlGenericErrorContext == NULL)
	xmlGenericErrorContext = (void *) stderr;

    va_start(args, msg);
    vfprintf((FILE *)xmlGenericErrorContext, msg, args);
    va_end(args);
}

82 83 84
/**
 * initGenericErrorDefaultFunc:
 * @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 93 94
    if (handler == NULL)
        xmlGenericError = xmlGenericErrorDefaultFunc;
    else
95
        xmlGenericError = (*handler);
96
}
97 98 99 100 101 102 103 104 105 106 107 108 109

/**
 * xmlSetGenericErrorFunc:
 * @ctx:  the new error handling context
 * @handler:  the new handler function
 *
 * Function to reset the handler and the error context for out of
 * context error messages.
 * This simply means that @handler will be called for subsequent
 * error messages while not parsing nor validating. And @ctx will
 * be passed as first argument to @handler
 * One can simply force messages to be emitted to another FILE * than
 * 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 113 114 115 116 117 118 119 120
 */
void
xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
    xmlGenericErrorContext = ctx;
    if (handler != NULL)
	xmlGenericError = handler;
    else
	xmlGenericError = xmlGenericErrorDefaultFunc;
}

121 122 123 124 125 126 127 128 129 130
/**
 * xmlSetStructuredErrorFunc:
 * @ctx:  the new error handling context
 * @handler:  the new handler function
 *
 * Function to reset the handler and the error context for out of
 * context structured error messages.
 * This simply means that @handler will be called for subsequent
 * error messages while not parsing nor validating. And @ctx will
 * be passed as first argument to @handler
131
 * For multi-threaded applications, this must be set separately for each thread.
132 133 134
 */
void
xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
135
    xmlStructuredErrorContext = ctx;
136 137 138
    xmlStructuredError = handler;
}

139
/************************************************************************
140 141 142
 *									*
 *			Handling of parsing errors			*
 *									*
143 144 145 146 147
 ************************************************************************/

/**
 * xmlParserPrintFileInfo:
 * @input:  an xmlParserInputPtr input
148
 *
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
 * Displays the associated file and line informations for the current input
 */

void
xmlParserPrintFileInfo(xmlParserInputPtr input) {
    if (input != NULL) {
	if (input->filename)
	    xmlGenericError(xmlGenericErrorContext,
		    "%s:%d: ", input->filename,
		    input->line);
	else
	    xmlGenericError(xmlGenericErrorContext,
		    "Entity: line %d: ", input->line);
    }
}

/**
 * xmlParserPrintFileContext:
 * @input:  an xmlParserInputPtr input
168
 *
169 170 171
 * Displays current context within the input content for error tracking
 */

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() */
William M. Brack's avatar
William M. Brack committed
177
    xmlChar  content[81]; /* space for 80 chars + line terminator */
178
    xmlChar *ctnt;
179

180
    if (input == NULL) return;
181 182
    cur = input->cur;
    base = input->base;
183
    /* skip backwards over any end-of-lines */
184
    while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
185
	cur--;
186 187
    }
    n = 0;
William M. Brack's avatar
William M. Brack committed
188
    /* search backwards for beginning-of-line (to max buff size) */
189 190
    while ((n++ < (sizeof(content)-1)) && (cur > base) &&
	   (*(cur) != '\n') && (*(cur) != '\r'))
191
        cur--;
192
    if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
William M. Brack's avatar
William M. Brack committed
193 194 195
    /* calculate the error position in terms of the current position */
    col = input->cur - cur;
    /* search forward for end-of-line (to max buff size) */
196
    n = 0;
197
    ctnt = content;
William M. Brack's avatar
William M. Brack committed
198
    /* copy selected text to our buffer */
199 200
    while ((*cur != 0) && (*(cur) != '\n') &&
	   (*(cur) != '\r') && (n < sizeof(content)-1)) {
201 202
		*ctnt++ = *cur++;
	n++;
203
    }
204
    *ctnt = 0;
William M. Brack's avatar
William M. Brack committed
205
    /* print out the selected text */
206
    channel(data ,"%s\n", content);
207
    /* create blank line with problem pointer */
208
    n = 0;
209
    ctnt = content;
William M. Brack's avatar
William M. Brack committed
210 211
    /* (leave buffer space for pointer + line terminator) */
    while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
212 213
	if (*(ctnt) != '\t')
	    *(ctnt) = ' ';
214
	ctnt++;
215
    }
William M. Brack's avatar
William M. Brack committed
216 217
    *ctnt++ = '^';
    *ctnt = 0;
218 219 220 221 222 223
    channel(data ,"%s\n", content);
}

/**
 * xmlParserPrintFileContext:
 * @input:  an xmlParserInputPtr input
224
 *
225 226 227 228 229 230
 * Displays current context within the input content for error tracking
 */
void
xmlParserPrintFileContext(xmlParserInputPtr input) {
   xmlParserPrintFileContextInternal(input, xmlGenericError,
                                     xmlGenericErrorContext);
231 232 233
}

/**
234
 * xmlReportError:
235
 * @err: the error
236 237
 * @ctx: the parser context or NULL
 * @str: the formatted error message
238
 *
239 240
 * Report an erro with its context, replace the 4 old error/warning
 * routines.
241
 */
242
static void
243 244
xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str,
               xmlGenericErrorFunc channel, void *data)
245
{
246 247 248 249
    char *file = NULL;
    int line = 0;
    int code = -1;
    int domain;
250 251
    const xmlChar *name = NULL;
    xmlNodePtr node;
252 253 254 255
    xmlErrorLevel level;
    xmlParserInputPtr input = NULL;
    xmlParserInputPtr cur = NULL;

256 257
    if (err == NULL)
        return;
258

259 260 261 262
    if (channel == NULL) {
	channel = xmlGenericError;
	data = xmlGenericErrorContext;
    }
263 264 265 266 267
    file = err->file;
    line = err->line;
    code = err->code;
    domain = err->domain;
    level = err->level;
268
    node = err->node;
269

270 271 272
    if (code == XML_ERR_OK)
        return;

273 274 275
    if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
        name = node->name;

276 277 278
    /*
     * Maintain the compatibility with the legacy error handling
     */
279 280 281 282 283 284 285 286 287 288
    if (ctxt != NULL) {
        input = ctxt->input;
        if ((input != NULL) && (input->filename == NULL) &&
            (ctxt->inputNr > 1)) {
            cur = input;
            input = ctxt->inputTab[ctxt->inputNr - 2];
        }
        if (input != NULL) {
            if (input->filename)
                channel(data, "%s:%d: ", input->filename, input->line);
289
            else if ((line != 0) && (domain == XML_FROM_PARSER))
290 291 292 293 294
                channel(data, "Entity: line %d: ", input->line);
        }
    } else {
        if (file != NULL)
            channel(data, "%s:%d: ", file, line);
295
        else if ((line != 0) &&
296 297 298
	         ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)||
		  (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) ||
		  (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV)))
299
            channel(data, "Entity: line %d: ", line);
300
    }
301 302 303
    if (name != NULL) {
        channel(data, "element %s: ", name);
    }
304 305 306 307 308 309 310 311
    switch (domain) {
        case XML_FROM_PARSER:
            channel(data, "parser ");
            break;
        case XML_FROM_NAMESPACE:
            channel(data, "namespace ");
            break;
        case XML_FROM_DTD:
312
        case XML_FROM_VALID:
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
            channel(data, "validity ");
            break;
        case XML_FROM_HTML:
            channel(data, "HTML parser ");
            break;
        case XML_FROM_MEMORY:
            channel(data, "memory ");
            break;
        case XML_FROM_OUTPUT:
            channel(data, "output ");
            break;
        case XML_FROM_IO:
            channel(data, "I/O ");
            break;
        case XML_FROM_XINCLUDE:
            channel(data, "XInclude ");
            break;
        case XML_FROM_XPATH:
            channel(data, "XPath ");
            break;
        case XML_FROM_XPOINTER:
            channel(data, "parser ");
            break;
        case XML_FROM_REGEXP:
            channel(data, "regexp ");
            break;
339 340 341
        case XML_FROM_MODULE:
            channel(data, "module ");
            break;
342
        case XML_FROM_SCHEMASV:
343
            channel(data, "Schemas validity ");
344 345
            break;
        case XML_FROM_SCHEMASP:
346
            channel(data, "Schemas parser ");
347
            break;
348 349 350 351
        case XML_FROM_RELAXNGP:
            channel(data, "Relax-NG parser ");
            break;
        case XML_FROM_RELAXNGV:
352
            channel(data, "Relax-NG validity ");
353 354 355 356 357 358 359 360 361 362
            break;
        case XML_FROM_CATALOG:
            channel(data, "Catalog ");
            break;
        case XML_FROM_C14N:
            channel(data, "C14N ");
            break;
        case XML_FROM_XSLT:
            channel(data, "XSLT ");
            break;
363 364 365
        case XML_FROM_I18N:
            channel(data, "encoding ");
            break;
366 367 368 369 370 371 372 373 374
        case XML_FROM_SCHEMATRONV:
            channel(data, "schematron ");
            break;
        case XML_FROM_BUFFER:
            channel(data, "internal buffer ");
            break;
        case XML_FROM_URI:
            channel(data, "URI ");
            break;
375 376 377 378 379 380
        default:
            break;
    }
    switch (level) {
        case XML_ERR_NONE:
            channel(data, ": ");
381
            break;
382 383
        case XML_ERR_WARNING:
            channel(data, "warning : ");
384
            break;
385 386
        case XML_ERR_ERROR:
            channel(data, "error : ");
387
            break;
388 389
        case XML_ERR_FATAL:
            channel(data, "error : ");
390
            break;
391 392
    }
    if (str != NULL) {
393 394 395 396
        int len;
	len = xmlStrlen((const xmlChar *)str);
	if ((len > 0) && (str[len - 1] != '\n'))
	    channel(data, "%s\n", str);
Daniel Veillard's avatar
Daniel Veillard committed
397 398
	else
	    channel(data, "%s", str);
399
    } else {
400
        channel(data, "%s\n", "out of memory error");
401
    }
402 403 404 405 406 407

    if (ctxt != NULL) {
        xmlParserPrintFileContextInternal(input, channel, data);
        if (cur != NULL) {
            if (cur->filename)
                channel(data, "%s:%d: \n", cur->filename, cur->line);
408
            else if ((line != 0) && (domain == XML_FROM_PARSER))
409 410 411 412
                channel(data, "Entity: line %d: \n", cur->line);
            xmlParserPrintFileContextInternal(cur, channel, data);
        }
    }
413 414 415 416 417 418 419 420 421 422 423 424 425
    if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
        (err->int1 < 100) &&
	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
	xmlChar buf[150];
	int i;

	channel(data, "%s\n", err->str1);
	for (i=0;i < err->int1;i++)
	     buf[i] = ' ';
	buf[i++] = '^';
	buf[i] = 0;
	channel(data, "%s\n", buf);
    }
426 427 428
}

/**
429
 * __xmlRaiseError:
430
 * @schannel: the structured callback channel
431
 * @channel: the old callback channel
432 433
 * @data: the callback data
 * @ctx: the parser context or NULL
434 435 436 437 438 439 440 441 442 443
 * @ctx: the parser context or NULL
 * @domain: the domain for the error
 * @code: the code for the error
 * @level: the xmlErrorLevel for the error
 * @file: the file source of the error (or NULL)
 * @line: the line of the error or 0 if N/A
 * @str1: extra string info
 * @str2: extra string info
 * @str3: extra string info
 * @int1: extra int info
444
 * @col: column number of the error or 0 if N/A
445 446 447
 * @msg:  the message to display/transmit
 * @...:  extra parameters for the message display
 *
448
 * Update the appropriate global or contextual error structure,
449 450 451
 * then forward the error message down the parser or generic
 * error callback handler
 */
452
void XMLCDECL
453 454
__xmlRaiseError(xmlStructuredErrorFunc schannel,
              xmlGenericErrorFunc channel, void *data, void *ctx,
455
              void *nod, int domain, int code, xmlErrorLevel level,
456
              const char *file, int line, const char *str1,
457
              const char *str2, const char *str3, int int1, int col,
458 459
	      const char *msg, ...)
{
460
    xmlParserCtxtPtr ctxt = NULL;
461
    xmlNodePtr node = (xmlNodePtr) nod;
462 463 464
    char *str = NULL;
    xmlParserInputPtr input = NULL;
    xmlErrorPtr to = &xmlLastError;
465
    xmlNodePtr baseptr = NULL;
466

467 468
    if (code == XML_ERR_OK)
        return;
469 470
    if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
        return;
471 472
    if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
        (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
473
	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
474
	ctxt = (xmlParserCtxtPtr) ctx;
475
	if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
476 477
	    (ctxt->sax->initialized == XML_SAX2_MAGIC) &&
	    (ctxt->sax->serror != NULL)) {
478
	    schannel = ctxt->sax->serror;
479 480
	    data = ctxt->userData;
	}
481
    }
482 483 484 485
    /*
     * Check if structured error handler set
     */
    if (schannel == NULL) {
486
	schannel = xmlStructuredError;
487 488 489 490
	/*
	 * if user has defined handler, change data ptr to user's choice
	 */
	if (schannel != NULL)
491
	    data = xmlStructuredErrorContext;
492
    }
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
    /*
     * Formatting the message
     */
    if (msg == NULL) {
        str = (char *) xmlStrdup(BAD_CAST "No error message provided");
    } else {
        XML_GET_VAR_STR(msg, str);
    }

    /*
     * specific processing if a parser context is provided
     */
    if (ctxt != NULL) {
        if (file == NULL) {
            input = ctxt->input;
            if ((input != NULL) && (input->filename == NULL) &&
                (ctxt->inputNr > 1)) {
                input = ctxt->inputTab[ctxt->inputNr - 2];
            }
            if (input != NULL) {
                file = input->filename;
                line = input->line;
515
                col = input->col;
516 517 518
            }
        }
        to = &ctxt->lastError;
519 520
    } else if ((node != NULL) && (file == NULL)) {
	int i;
521

522
	if ((node->doc != NULL) && (node->doc->URL != NULL)) {
523
	    baseptr = node;
524
/*	    file = (const char *) node->doc->URL; */
525
	}
526 527 528 529
	for (i = 0;
	     ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
	     i++)
	     node = node->parent;
530
        if ((baseptr == NULL) && (node != NULL) &&
531
	    (node->doc != NULL) && (node->doc->URL != NULL))
532
	    baseptr = node;
533

534
	if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
535
	    line = node->line;
536 537
	if ((line == 0) || (line == 65535))
	    line = xmlGetLineNo(node);
538 539 540
    }

    /*
541
     * Save the information about the error
542 543 544 545 546 547 548 549
     */
    xmlResetError(to);
    to->domain = domain;
    to->code = code;
    to->message = str;
    to->level = level;
    if (file != NULL)
        to->file = (char *) xmlStrdup((const xmlChar *) file);
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
    else if (baseptr != NULL) {
#ifdef LIBXML_XINCLUDE_ENABLED
	/*
	 * We check if the error is within an XInclude section and,
	 * if so, attempt to print out the href of the XInclude instead
	 * of the usual "base" (doc->URL) for the node (bug 152623).
	 */
        xmlNodePtr prev = baseptr;
	int inclcount = 0;
	while (prev != NULL) {
	    if (prev->prev == NULL)
	        prev = prev->parent;
	    else {
	        prev = prev->prev;
		if (prev->type == XML_XINCLUDE_START) {
		    if (--inclcount < 0)
		        break;
		} else if (prev->type == XML_XINCLUDE_END)
		    inclcount++;
	    }
	}
	if (prev != NULL) {
572 573 574 575 576 577 578
	    if (prev->type == XML_XINCLUDE_START) {
		prev->type = XML_ELEMENT_NODE;
		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
		prev->type = XML_XINCLUDE_START;
	    } else {
		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
	    }
579 580 581
	} else
#endif
	    to->file = (char *) xmlStrdup(baseptr->doc->URL);
582 583 584
	if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) {
	    to->file = (char *) xmlStrdup(node->doc->URL);
	}
585
    }
586 587 588 589 590 591 592 593
    to->line = line;
    if (str1 != NULL)
        to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
    if (str2 != NULL)
        to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
    if (str3 != NULL)
        to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
    to->int1 = int1;
594
    to->int2 = col;
595
    to->node = node;
596
    to->ctxt = ctx;
597

598 599 600
    if (to != &xmlLastError)
        xmlCopyError(to,&xmlLastError);

601 602 603 604 605
    if (schannel != NULL) {
	schannel(data, to);
	return;
    }

606
    /*
607
     * Find the callback channel if channel param is NULL
608
     */
609 610
    if ((ctxt != NULL) && (channel == NULL) &&
        (xmlStructuredError == NULL) && (ctxt->sax != NULL)) {
611 612 613 614
        if (level == XML_ERR_WARNING)
	    channel = ctxt->sax->warning;
        else
	    channel = ctxt->sax->error;
615
	data = ctxt->userData;
616
    } else if (channel == NULL) {
617
	channel = xmlGenericError;
618 619 620
	if (ctxt != NULL) {
	    data = ctxt;
	} else {
621
	    data = xmlGenericErrorContext;
622
	}
623
    }
624 625 626 627 628 629 630
    if (channel == NULL)
        return;

    if ((channel == xmlParserError) ||
        (channel == xmlParserWarning) ||
	(channel == xmlParserValidityError) ||
	(channel == xmlParserValidityWarning))
631 632 633 634
	xmlReportError(to, ctxt, str, NULL, NULL);
    else if ((channel == (xmlGenericErrorFunc) fprintf) ||
             (channel == xmlGenericErrorDefaultFunc))
	xmlReportError(to, ctxt, str, channel, data);
635 636
    else
	channel(data, "%s", str);
637 638
}

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
/**
 * __xmlSimpleError:
 * @domain: where the error comes from
 * @code: the error code
 * @node: the context node
 * @extra:  extra informations
 *
 * Handle an out of memory condition
 */
void
__xmlSimpleError(int domain, int code, xmlNodePtr node,
                 const char *msg, const char *extra)
{

    if (code == XML_ERR_NO_MEMORY) {
	if (extra)
655
	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
656 657 658 659
			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
			    NULL, NULL, 0, 0,
			    "Memory allocation failed : %s\n", extra);
	else
660
	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
661 662 663
			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
			    NULL, NULL, 0, 0, "Memory allocation failed\n");
    } else {
664
	__xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
665 666 667 668
			code, XML_ERR_ERROR, NULL, 0, extra,
			NULL, NULL, 0, 0, msg, extra);
    }
}
669 670 671 672 673
/**
 * xmlParserError:
 * @ctx:  an XML parser context
 * @msg:  the message to display/transmit
 * @...:  extra parameters for the message display
674
 *
675 676 677
 * Display and format an error messages, gives file, line, position and
 * extra parameters.
 */
678
void XMLCDECL
679 680 681 682 683
xmlParserError(void *ctx, const char *msg, ...)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlParserInputPtr input = NULL;
    xmlParserInputPtr cur = NULL;
684
    char * str;
685 686 687 688 689 690 691 692 693 694 695 696

    if (ctxt != NULL) {
	input = ctxt->input;
	if ((input != NULL) && (input->filename == NULL) &&
	    (ctxt->inputNr > 1)) {
	    cur = input;
	    input = ctxt->inputTab[ctxt->inputNr - 2];
	}
	xmlParserPrintFileInfo(input);
    }

    xmlGenericError(xmlGenericErrorContext, "error: ");
697
    XML_GET_VAR_STR(msg, str);
698
    xmlGenericError(xmlGenericErrorContext, "%s", str);
699 700
    if (str != NULL)
	xmlFree(str);
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716

    if (ctxt != NULL) {
	xmlParserPrintFileContext(input);
	if (cur != NULL) {
	    xmlParserPrintFileInfo(cur);
	    xmlGenericError(xmlGenericErrorContext, "\n");
	    xmlParserPrintFileContext(cur);
	}
    }
}

/**
 * xmlParserWarning:
 * @ctx:  an XML parser context
 * @msg:  the message to display/transmit
 * @...:  extra parameters for the message display
717
 *
718 719 720
 * Display and format a warning messages, gives file, line, position and
 * extra parameters.
 */
721
void XMLCDECL
722 723 724 725 726
xmlParserWarning(void *ctx, const char *msg, ...)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlParserInputPtr input = NULL;
    xmlParserInputPtr cur = NULL;
727
    char * str;
728 729 730 731 732 733 734 735 736 737

    if (ctxt != NULL) {
	input = ctxt->input;
	if ((input != NULL) && (input->filename == NULL) &&
	    (ctxt->inputNr > 1)) {
	    cur = input;
	    input = ctxt->inputTab[ctxt->inputNr - 2];
	}
	xmlParserPrintFileInfo(input);
    }
738

739
    xmlGenericError(xmlGenericErrorContext, "warning: ");
740
    XML_GET_VAR_STR(msg, str);
741
    xmlGenericError(xmlGenericErrorContext, "%s", str);
742 743
    if (str != NULL)
	xmlFree(str);
744 745 746 747 748 749 750 751 752 753 754 755

    if (ctxt != NULL) {
	xmlParserPrintFileContext(input);
	if (cur != NULL) {
	    xmlParserPrintFileInfo(cur);
	    xmlGenericError(xmlGenericErrorContext, "\n");
	    xmlParserPrintFileContext(cur);
	}
    }
}

/************************************************************************
756 757 758
 *									*
 *			Handling of validation errors			*
 *									*
759 760 761 762 763 764 765
 ************************************************************************/

/**
 * xmlParserValidityError:
 * @ctx:  an XML parser context
 * @msg:  the message to display/transmit
 * @...:  extra parameters for the message display
766
 *
767 768 769
 * Display and format an validity error messages, gives file,
 * line, position and extra parameters.
 */
770
void XMLCDECL
771 772 773 774
xmlParserValidityError(void *ctx, const char *msg, ...)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlParserInputPtr input = NULL;
775
    char * str;
776 777 778 779 780 781 782 783
    int len = xmlStrlen((const xmlChar *) msg);
    static int had_info = 0;

    if ((len > 1) && (msg[len - 2] != ':')) {
	if (ctxt != NULL) {
	    input = ctxt->input;
	    if ((input->filename == NULL) && (ctxt->inputNr > 1))
		input = ctxt->inputTab[ctxt->inputNr - 2];
784

785 786 787 788 789 790 791 792
	    if (had_info == 0) {
		xmlParserPrintFileInfo(input);
	    }
	}
	xmlGenericError(xmlGenericErrorContext, "validity error: ");
	had_info = 0;
    } else {
	had_info = 1;
793 794
    }

795
    XML_GET_VAR_STR(msg, str);
796
    xmlGenericError(xmlGenericErrorContext, "%s", str);
797 798
    if (str != NULL)
	xmlFree(str);
799

800
    if ((ctxt != NULL) && (input != NULL)) {
801 802 803 804 805 806 807 808 809
	xmlParserPrintFileContext(input);
    }
}

/**
 * xmlParserValidityWarning:
 * @ctx:  an XML parser context
 * @msg:  the message to display/transmit
 * @...:  extra parameters for the message display
810
 *
811 812 813
 * Display and format a validity warning messages, gives file, line,
 * position and extra parameters.
 */
814
void XMLCDECL
815 816 817 818
xmlParserValidityWarning(void *ctx, const char *msg, ...)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlParserInputPtr input = NULL;
819
    char * str;
820
    int len = xmlStrlen((const xmlChar *) msg);
821

822
    if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
823 824 825 826 827 828
	input = ctxt->input;
	if ((input->filename == NULL) && (ctxt->inputNr > 1))
	    input = ctxt->inputTab[ctxt->inputNr - 2];

	xmlParserPrintFileInfo(input);
    }
829

830
    xmlGenericError(xmlGenericErrorContext, "validity warning: ");
831
    XML_GET_VAR_STR(msg, str);
832
    xmlGenericError(xmlGenericErrorContext, "%s", str);
833 834
    if (str != NULL)
	xmlFree(str);
835 836 837 838 839 840 841

    if (ctxt != NULL) {
	xmlParserPrintFileContext(input);
    }
}


842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
/************************************************************************
 *									*
 *			Extended Error Handling				*
 *									*
 ************************************************************************/

/**
 * xmlGetLastError:
 *
 * Get the last global error registered. This is per thread if compiled
 * with thread support.
 *
 * Returns NULL if no error occured or a pointer to the error
 */
xmlErrorPtr
xmlGetLastError(void)
{
    if (xmlLastError.code == XML_ERR_OK)
        return (NULL);
    return (&xmlLastError);
}

/**
 * xmlResetError:
 * @err: pointer to the error.
 *
 * Cleanup the error.
 */
void
xmlResetError(xmlErrorPtr err)
{
    if (err == NULL)
        return;
    if (err->code == XML_ERR_OK)
        return;
    if (err->message != NULL)
        xmlFree(err->message);
    if (err->file != NULL)
        xmlFree(err->file);
    if (err->str1 != NULL)
        xmlFree(err->str1);
    if (err->str2 != NULL)
        xmlFree(err->str2);
    if (err->str3 != NULL)
        xmlFree(err->str3);
    memset(err, 0, sizeof(xmlError));
    err->code = XML_ERR_OK;
}

/**
 * xmlResetLastError:
 *
 * Cleanup the last global error registered. For parsing error
 * this does not change the well-formedness result.
 */
void
xmlResetLastError(void)
{
    if (xmlLastError.code == XML_ERR_OK)
        return;
    xmlResetError(&xmlLastError);
}

/**
 * xmlCtxtGetLastError:
 * @ctx:  an XML parser context
 *
 * Get the last parsing error registered.
 *
 * Returns NULL if no error occured or a pointer to the error
 */
xmlErrorPtr
xmlCtxtGetLastError(void *ctx)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

    if (ctxt == NULL)
        return (NULL);
    if (ctxt->lastError.code == XML_ERR_OK)
        return (NULL);
    return (&ctxt->lastError);
}

/**
 * xmlCtxtResetLastError:
 * @ctx:  an XML parser context
 *
 * Cleanup the last global error registered. For parsing error
 * this does not change the well-formedness result.
 */
void
xmlCtxtResetLastError(void *ctx)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

    if (ctxt == NULL)
        return;
939
    ctxt->errNo = XML_ERR_OK;
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
    if (ctxt->lastError.code == XML_ERR_OK)
        return;
    xmlResetError(&ctxt->lastError);
}

/**
 * xmlCopyError:
 * @from:  a source error
 * @to:  a target error
 *
 * Save the original error to the new place.
 *
 * Returns 0 in case of success and -1 in case of error.
 */
int
xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
956 957
    char *message, *file, *str1, *str2, *str3;

958 959
    if ((from == NULL) || (to == NULL))
        return(-1);
960 961 962 963 964 965 966

    message = (char *) xmlStrdup((xmlChar *) from->message);
    file = (char *) xmlStrdup ((xmlChar *) from->file);
    str1 = (char *) xmlStrdup ((xmlChar *) from->str1);
    str2 = (char *) xmlStrdup ((xmlChar *) from->str2);
    str3 = (char *) xmlStrdup ((xmlChar *) from->str3);

967 968 969 970 971 972 973 974 975 976 977 978 979 980
    if (to->message != NULL)
        xmlFree(to->message);
    if (to->file != NULL)
        xmlFree(to->file);
    if (to->str1 != NULL)
        xmlFree(to->str1);
    if (to->str2 != NULL)
        xmlFree(to->str2);
    if (to->str3 != NULL)
        xmlFree(to->str3);
    to->domain = from->domain;
    to->code = from->code;
    to->level = from->level;
    to->line = from->line;
981
    to->node = from->node;
982 983
    to->int1 = from->int1;
    to->int2 = from->int2;
984 985
    to->node = from->node;
    to->ctxt = from->ctxt;
986 987 988 989 990 991 992
    to->message = message;
    to->file = file;
    to->str1 = str1;
    to->str2 = str2;
    to->str3 = str3;

    return 0;
993 994
}

995 996
#define bottom_error
#include "elfgcchack.h"