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
				 ...);
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
    xmlGenericErrorContext = 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) return;
181
    cur = input->cur;
182
    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;
188
    /* search backwards for beginning-of-line (to max buff size) */
189
    while ((n++ < (sizeof(content)-1)) && (cur > base) && 
190
    	   (*(cur) != '\n') && (*(cur) != '\r'))
191
        cur--;
192
    if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
193
    /* calculate the error position in terms of the current position */
194
    col = input->cur - cur;
195
    /* search forward for end-of-line (to max buff size) */
196
    n = 0;
197
    ctnt = content;
198
    /* copy selected text to our buffer */
199
    while ((*cur != 0) && (*(cur) != '\n') && 
200
    	   (*(cur) != '\r') && (n < sizeof(content)-1)) {
201
		*ctnt++ = *cur++;
202
	n++;
203
    }
204
    *ctnt = 0;
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;
210
    /* (leave buffer space for pointer + line terminator) */
211
    while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
212
	if (*(ctnt) != '\t')
213
	    *(ctnt) = ' ';
214
	ctnt++;
215
    }
216
    *ctnt++ = '^';
217
    *ctnt = 0;
218
    channel(data ,"%s\n", content);
219
}
220
221
/**
222
 * xmlParserPrintFileContext:
223
 * @input:  an xmlParserInputPtr input
224
 * 
225
 * Displays current context within the input content for error tracking
226
 */
227
void
228
xmlParserPrintFileContext(xmlParserInputPtr input) {
229
   xmlParserPrintFileContextInternal(input, xmlGenericError,
230
                                     xmlGenericErrorContext);
231
}
232
233
/**
234
 * xmlReportError:
235
 * @err: the error
236
 * @ctx: the parser context or NULL
237
 * @str: the formatted error message
238
 *
239
 * Report an erro with its context, replace the 4 old error/warning
240
 * routines.
241
 */
242
static void
243
xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str,
244
               xmlGenericErrorFunc channel, void *data)
245
{
246
    char *file = NULL;
247
    int line = 0;
248
    int code = -1;
249
    int domain;
250
    const xmlChar *name = NULL;
251
    xmlNodePtr node;
252
    xmlErrorLevel level;
253
    xmlParserInputPtr input = NULL;
254
    xmlParserInputPtr cur = NULL;
255
256
    if (err == NULL)
257
        return;
258
259
    if (channel == NULL) {
260
	channel = xmlGenericError;
261
	data = xmlGenericErrorContext;
262
    }
263
    file = err->file;
264
    line = err->line;
265
    code = err->code;
266
    domain = err->domain;
267
    level = err->level;
268
    node = err->node;
269
270
    if (code == XML_ERR_OK)
271
        return;
272
273
    if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
274
        name = node->name;
275
276
    /*
277
     * Maintain the compatibility with the legacy error handling
278
     */
279
    if (ctxt != NULL) {
280
        input = ctxt->input;
281
        if ((input != NULL) && (input->filename == NULL) &&
282
            (ctxt->inputNr > 1)) {
283
            cur = input;
284
            input = ctxt->inputTab[ctxt->inputNr - 2];
285
        }
286
        if (input != NULL) {
287
            if (input->filename)
288
                channel(data, "%s:%d: ", input->filename, input->line);
289
            else if ((line != 0) && (domain == XML_FROM_PARSER))
290
                channel(data, "Entity: line %d: ", input->line);
291
        }
292
    } else {
293
        if (file != NULL)
294
            channel(data, "%s:%d: ", file, line);
295
        else if ((line != 0) && (domain == XML_FROM_PARSER))
296
            channel(data, "Entity: line %d: ", line);
297
    }
298
    if (name != NULL) {
299
        channel(data, "element %s: ", name);
300
    }
301
    switch (domain) {
302
        case XML_FROM_PARSER:
303
            channel(data, "parser ");
304
            break;
305
        case XML_FROM_NAMESPACE:
306
            channel(data, "namespace ");
307
            break;
308
        case XML_FROM_DTD:
309
        case XML_FROM_VALID:
310
            channel(data, "validity ");
311
            break;
312
        case XML_FROM_HTML:
313
            channel(data, "HTML parser ");
314
            break;
315
        case XML_FROM_MEMORY:
316
            channel(data, "memory ");
317
            break;
318
        case XML_FROM_OUTPUT:
319
            channel(data, "output ");
320
            break;
321
        case XML_FROM_IO:
322
            channel(data, "I/O ");
323
            break;
324
        case XML_FROM_XINCLUDE:
325
            channel(data, "XInclude ");
326
            break;
327
        case XML_FROM_XPATH:
328
            channel(data, "XPath ");
329
            break;
330
        case XML_FROM_XPOINTER:
331
            channel(data, "parser ");
332
            break;
333
        case XML_FROM_REGEXP:
334
            channel(data, "regexp ");
335
            break;
336
        case XML_FROM_MODULE:
337
            channel(data, "module ");
338
            break;
339
        case XML_FROM_SCHEMASV:
340
            channel(data, "Schemas validity ");
341
            break;
342
        case XML_FROM_SCHEMASP:
343
            channel(data, "Schemas parser ");
344
            break;
345
        case XML_FROM_RELAXNGP:
346
            channel(data, "Relax-NG parser ");
347
            break;
348
        case XML_FROM_RELAXNGV:
349
            channel(data, "Relax-NG validity ");
350
            break;
351
        case XML_FROM_CATALOG:
352
            channel(data, "Catalog ");
353
            break;
354
        case XML_FROM_C14N:
355
            channel(data, "C14N ");
356
            break;
357
        case XML_FROM_XSLT:
358
            channel(data, "XSLT ");
359
            break;
360
        case XML_FROM_I18N:
361
            channel(data, "encoding ");
362
            break;
363
        default:
364
            break;
365
    }
366
    switch (level) {
367
        case XML_ERR_NONE:
368
            channel(data, ": ");
369
            break;
370
        case XML_ERR_WARNING:
371
            channel(data, "warning : ");
372
            break;
373
        case XML_ERR_ERROR:
374
            channel(data, "error : ");
375
            break;
376
        case XML_ERR_FATAL:
377
            channel(data, "error : ");
378
            break;
379
    }
380
    if (str != NULL) {
381
        int len;
382
	len = xmlStrlen((const xmlChar *)str);
383
	if ((len > 0) && (str[len - 1] != '\n'))
384
	    channel(data, "%s\n", str);
385
	else
386
	    channel(data, "%s", str);
387
    } else {
388
        channel(data, "%s\n", "out of memory error");
389
    }
390
391
    if (ctxt != NULL) {
392
        xmlParserPrintFileContextInternal(input, channel, data);
393
        if (cur != NULL) {
394
            if (cur->filename)
395
                channel(data, "%s:%d: \n", cur->filename, cur->line);
396
            else if ((line != 0) && (domain == XML_FROM_PARSER))
397
                channel(data, "Entity: line %d: \n", cur->line);
398
            xmlParserPrintFileContextInternal(cur, channel, data);
399
        }
400
    }
401
    if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
402
        (err->int1 < 100) &&
403
	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
404
	xmlChar buf[150];
405
	int i;
406
407
	channel(data, "%s\n", err->str1);
408
	for (i=0;i < err->int1;i++)
409
	     buf[i] = ' ';
410
	buf[i++] = '^';
411
	buf[i] = 0;
412
	channel(data, "%s\n", buf);
413
    }
414
}
415
416
/**
417
 * __xmlRaiseError:
418
 * @schannel: the structured callback channel
419
 * @channel: the old callback channel
420
 * @data: the callback data
421
 * @ctx: the parser context or NULL
422
 * @ctx: the parser context or NULL
423
 * @domain: the domain for the error
424
 * @code: the code for the error
425
 * @level: the xmlErrorLevel for the error
426
 * @file: the file source of the error (or NULL)
427
 * @line: the line of the error or 0 if N/A
428
 * @str1: extra string info
429
 * @str2: extra string info
430
 * @str3: extra string info
431
 * @int1: extra int info
432
 * @col: column number of the error or 0 if N/A 
433
 * @msg:  the message to display/transmit
434
 * @...:  extra parameters for the message display
435
 *
436
 * Update the appropriate global or contextual error structure,
437
 * then forward the error message down the parser or generic
438
 * error callback handler
439
 */
440
void XMLCDECL
441
__xmlRaiseError(xmlStructuredErrorFunc schannel,
442
              xmlGenericErrorFunc channel, void *data, void *ctx,
443
              void *nod, int domain, int code, xmlErrorLevel level,
444
              const char *file, int line, const char *str1,
445
              const char *str2, const char *str3, int int1, int col,
446
	      const char *msg, ...)
447
{
448
    xmlParserCtxtPtr ctxt = NULL;
449
    xmlNodePtr node = (xmlNodePtr) nod;
450
    char *str = NULL;
451
    xmlParserInputPtr input = NULL;
452
    xmlErrorPtr to = &xmlLastError;
453
    xmlNodePtr baseptr = NULL;
454
455
    if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
456
        return;
457
    if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
458
        (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
459
	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
460
	ctxt = (xmlParserCtxtPtr) ctx;
461
	if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
462
	    (ctxt->sax->initialized == XML_SAX2_MAGIC))
463
	    schannel = ctxt->sax->serror;
464
    }
465
    /*
466
     * Check if structured error handler set
467
     */
468
    if (schannel == NULL) {
469
	schannel = xmlStructuredError;
470
	/*
471
	 * if user has defined handler, change data ptr to user's choice
472
	 */
473
	if (schannel != NULL)
474
	    data = xmlGenericErrorContext;
475
    }
476
    if ((domain == XML_FROM_VALID) &&
477
        ((channel == xmlParserValidityError) ||
478
	 (channel == xmlParserValidityWarning))) {
479
	ctxt = (xmlParserCtxtPtr) ctx;
480
	if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
481
	    (ctxt->sax->initialized == XML_SAX2_MAGIC))
482
	    schannel = ctxt->sax->serror;
483
    }
484
    if (code == XML_ERR_OK)
485
        return;
486
    /*
487
     * Formatting the message
488
     */
489
    if (msg == NULL) {
490
        str = (char *) xmlStrdup(BAD_CAST "No error message provided");
491
    } else {
492
        XML_GET_VAR_STR(msg, str);
493
    }
494
495
    /*
496
     * specific processing if a parser context is provided
497
     */
498
    if (ctxt != NULL) {
499
        if (file == NULL) {
500
            input = ctxt->input;
501
            if ((input != NULL) && (input->filename == NULL) &&
502
                (ctxt->inputNr > 1)) {
503
                input = ctxt->inputTab[ctxt->inputNr - 2];
504
            }
505
            if (input != NULL) {
506
                file = input->filename;
507
                line = input->line;
508
                col = input->col;
509
            }
510
        }
511
        to = &ctxt->lastError;
512
    } else if ((node != NULL) && (file == NULL)) {
513
	int i;
514
515
	if ((node->doc != NULL) && (node->doc->URL != NULL)) {
516
	    baseptr = node;
517
/*	    file = (const char *) node->doc->URL; */
518
	}
519
	for (i = 0;
520
	     ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
521
	     i++)
522
	     node = node->parent;
523
        if ((baseptr == NULL) && (node != NULL) &&
524
	    (node->doc != NULL) && (node->doc->URL != NULL))
525
	    baseptr = node;
526
527
	if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
528
	    line = node->line;
529
    }
530
531
    /*
532
     * Save the information about the error
533
     */
534
    xmlResetError(to);
535
    to->domain = domain;
536
    to->code = code;
537
    to->message = str;
538
    to->level = level;
539
    if (file != NULL)
540
        to->file = (char *) xmlStrdup((const xmlChar *) file);
541
    else if (baseptr != NULL) {
542
#ifdef LIBXML_XINCLUDE_ENABLED
543
	/*
544
	 * We check if the error is within an XInclude section and,
545
	 * if so, attempt to print out the href of the XInclude instead
546
	 * of the usual "base" (doc->URL) for the node (bug 152623).
547
	 */
548
        xmlNodePtr prev = baseptr;
549
	int inclcount = 0;
550
	while (prev != NULL) {
551
	    if (prev->prev == NULL)
552
	        prev = prev->parent;
553
	    else {
554
	        prev = prev->prev;
555
		if (prev->type == XML_XINCLUDE_START) {
556
		    if (--inclcount < 0)
557
		        break;
558
		} else if (prev->type == XML_XINCLUDE_END)
559
		    inclcount++;
560
	    }
561
	}
562
	if (prev != NULL) {
563
	    if (prev->type == XML_XINCLUDE_START) {
564
		prev->type = XML_ELEMENT_NODE;
565
		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
566
		prev->type = XML_XINCLUDE_START;
567
	    } else {
568
		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
569
	    }
570
	} else
571
#endif
572
	    to->file = (char *) xmlStrdup(baseptr->doc->URL);
573
	if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) {
574
	    to->file = (char *) xmlStrdup(node->doc->URL);
575
	}
576
	file = to->file;
577
    }
578
    to->line = line;
579
    if (str1 != NULL)
580
        to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
581
    if (str2 != NULL)
582
        to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
583
    if (str3 != NULL)
584
        to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
585
    to->int1 = int1;
586
    to->int2 = col;
587
    to->node = node;
588
    to->ctxt = ctx;
589
590
    if (to != &xmlLastError)
591
        xmlCopyError(to,&xmlLastError);
592
593
    /*
594
     * Find the callback channel if channel param is NULL
595
     */
596
    if ((ctxt != NULL) && (channel == NULL) && (xmlStructuredError == NULL) && (ctxt->sax != NULL)) {
597
        if (level == XML_ERR_WARNING)
598
	    channel = ctxt->sax->warning;
599
        else
600
	    channel = ctxt->sax->error;
601
	data = ctxt->userData;
602
    } else if (channel == NULL) {
603
        if (xmlStructuredError != NULL)
604
	    schannel = xmlStructuredError;
605
	else
606
	    channel = xmlGenericError;
607
	if (!data) {
608
	data = xmlGenericErrorContext;
609
    }
610
    }
611
    if (schannel != NULL) {
612
        schannel(data, to);
613
	return;
614
    }
615
    if (channel == NULL)
616
        return;
617
618
    if ((channel == xmlParserError) ||
619
        (channel == xmlParserWarning) ||
620
	(channel == xmlParserValidityError) ||
621
	(channel == xmlParserValidityWarning))
622
	xmlReportError(to, ctxt, str, NULL, NULL);
623
    else if ((channel == (xmlGenericErrorFunc) fprintf) ||
624
             (channel == xmlGenericErrorDefaultFunc))
625
	xmlReportError(to, ctxt, str, channel, data);
626
    else
627
	channel(data, "%s", str);
628
}
629
630
/**
631
 * __xmlSimpleError:
632
 * @domain: where the error comes from
633
 * @code: the error code
634
 * @node: the context node
635
 * @extra:  extra informations
636
 *
637
 * Handle an out of memory condition
638
 */
639
void
640
__xmlSimpleError(int domain, int code, xmlNodePtr node,
641
                 const char *msg, const char *extra)
642
{
643
644
    if (code == XML_ERR_NO_MEMORY) {
645
	if (extra)
646
	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
647
			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
648
			    NULL, NULL, 0, 0,
649
			    "Memory allocation failed : %s\n", extra);
650
	else
651
	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
652
			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
653
			    NULL, NULL, 0, 0, "Memory allocation failed\n");
654
    } else {
655
	__xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
656
			code, XML_ERR_ERROR, NULL, 0, extra,
657
			NULL, NULL, 0, 0, msg, extra);
658
    }
659
}
660
/**
661
 * xmlParserError:
662
 * @ctx:  an XML parser context
663
 * @msg:  the message to display/transmit
664
 * @...:  extra parameters for the message display
665
 * 
666
 * Display and format an error messages, gives file, line, position and
667
 * extra parameters.
668
 */
669
void XMLCDECL
670
xmlParserError(void *ctx, const char *msg, ...)
671
{
672
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
673
    xmlParserInputPtr input = NULL;
674
    xmlParserInputPtr cur = NULL;
675
    char * str;
676
677
    if (ctxt != NULL) {
678
	input = ctxt->input;
679
	if ((input != NULL) && (input->filename == NULL) &&
680
	    (ctxt->inputNr > 1)) {
681
	    cur = input;
682
	    input = ctxt->inputTab[ctxt->inputNr - 2];
683
	}
684
	xmlParserPrintFileInfo(input);
685
    }
686
687
    xmlGenericError(xmlGenericErrorContext, "error: ");
688
    XML_GET_VAR_STR(msg, str);
689
    xmlGenericError(xmlGenericErrorContext, "%s", str);
690
    if (str != NULL)
691
	xmlFree(str);
692
693
    if (ctxt != NULL) {
694
	xmlParserPrintFileContext(input);
695
	if (cur != NULL) {
696
	    xmlParserPrintFileInfo(cur);
697
	    xmlGenericError(xmlGenericErrorContext, "\n");
698
	    xmlParserPrintFileContext(cur);
699
	}
700
    }
701
}
702
703
/**
704
 * xmlParserWarning:
705
 * @ctx:  an XML parser context
706
 * @msg:  the message to display/transmit
707
 * @...:  extra parameters for the message display
708
 * 
709
 * Display and format a warning messages, gives file, line, position and
710
 * extra parameters.
711
 */
712
void XMLCDECL
713
xmlParserWarning(void *ctx, const char *msg, ...)
714
{
715
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
716
    xmlParserInputPtr input = NULL;
717
    xmlParserInputPtr cur = NULL;
718
    char * str;
719
720
    if (ctxt != NULL) {
721
	input = ctxt->input;
722
	if ((input != NULL) && (input->filename == NULL) &&
723
	    (ctxt->inputNr > 1)) {
724
	    cur = input;
725
	    input = ctxt->inputTab[ctxt->inputNr - 2];
726
	}
727
	xmlParserPrintFileInfo(input);
728
    }
729
        
730
    xmlGenericError(xmlGenericErrorContext, "warning: ");
731
    XML_GET_VAR_STR(msg, str);
732
    xmlGenericError(xmlGenericErrorContext, "%s", str);
733
    if (str != NULL)
734
	xmlFree(str);
735
736
    if (ctxt != NULL) {
737
	xmlParserPrintFileContext(input);
738
	if (cur != NULL) {
739
	    xmlParserPrintFileInfo(cur);
740
	    xmlGenericError(xmlGenericErrorContext, "\n");
741
	    xmlParserPrintFileContext(cur);
742
	}
743
    }
744
}
745
746
/************************************************************************
747
 * 									*
748
 * 			Handling of validation errors			*
749
 * 									*
750
 ************************************************************************/
751
752
/**
753
 * xmlParserValidityError:
754
 * @ctx:  an XML parser context
755
 * @msg:  the message to display/transmit
756
 * @...:  extra parameters for the message display
757
 * 
758
 * Display and format an validity error messages, gives file,
759
 * line, position and extra parameters.
760
 */
761
void XMLCDECL
762
xmlParserValidityError(void *ctx, const char *msg, ...)
763
{
764
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
765
    xmlParserInputPtr input = NULL;
766
    char * str;
767
    int len = xmlStrlen((const xmlChar *) msg);
768
    static int had_info = 0;
769
770
    if ((len > 1) && (msg[len - 2] != ':')) {
771
	if (ctxt != NULL) {
772
	    input = ctxt->input;
773
	    if ((input->filename == NULL) && (ctxt->inputNr > 1))
774
		input = ctxt->inputTab[ctxt->inputNr - 2];
775
		
776
	    if (had_info == 0) {
777
		xmlParserPrintFileInfo(input);
778
	    }
779
	}
780
	xmlGenericError(xmlGenericErrorContext, "validity error: ");
781
	had_info = 0;
782
    } else {
783
	had_info = 1;
784
    }
785
786
    XML_GET_VAR_STR(msg, str);
787
    xmlGenericError(xmlGenericErrorContext, "%s", str);
788
    if (str != NULL)
789
	xmlFree(str);
790
791
    if ((ctxt != NULL) && (input != NULL)) {
792
	xmlParserPrintFileContext(input);
793
    }
794
}
795
796
/**
797
 * xmlParserValidityWarning:
798
 * @ctx:  an XML parser context
799
 * @msg:  the message to display/transmit
800
 * @...:  extra parameters for the message display
801
 * 
802
 * Display and format a validity warning messages, gives file, line,
803
 * position and extra parameters.
804
 */
805
void XMLCDECL
806
xmlParserValidityWarning(void *ctx, const char *msg, ...)
807
{
808
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
809
    xmlParserInputPtr input = NULL;
810
    char * str;
811
    int len = xmlStrlen((const xmlChar *) msg);
812
813
    if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
814
	input = ctxt->input;
815
	if ((input->filename == NULL) && (ctxt->inputNr > 1))
816
	    input = ctxt->inputTab[ctxt->inputNr - 2];
817
818
	xmlParserPrintFileInfo(input);
819
    }
820
        
821
    xmlGenericError(xmlGenericErrorContext, "validity warning: ");
822
    XML_GET_VAR_STR(msg, str);
823
    xmlGenericError(xmlGenericErrorContext, "%s", str);
824
    if (str != NULL)
825
	xmlFree(str);
826
827
    if (ctxt != NULL) {
828
	xmlParserPrintFileContext(input);
829
    }
830
}
831
832
833
/************************************************************************
834
 *									*
835
 *			Extended Error Handling				*
836
 *									*
837
 ************************************************************************/
838
839
/**
840
 * xmlGetLastError:
841
 *
842
 * Get the last global error registered. This is per thread if compiled
843
 * with thread support.
844
 *
845
 * Returns NULL if no error occured or a pointer to the error
846
 */
847
xmlErrorPtr
848
xmlGetLastError(void)
849
{
850
    if (xmlLastError.code == XML_ERR_OK)
851
        return (NULL);
852
    return (&xmlLastError);
853
}
854
855
/**
856
 * xmlResetError:
857
 * @err: pointer to the error.
858
 *
859
 * Cleanup the error.
860
 */
861
void
862
xmlResetError(xmlErrorPtr err)
863
{
864
    if (err == NULL)
865
        return;
866
    if (err->code == XML_ERR_OK)
867
        return;
868
    if (err->message != NULL)
869
        xmlFree(err->message);
870
    if (err->file != NULL)
871
        xmlFree(err->file);
872
    if (err->str1 != NULL)
873
        xmlFree(err->str1);
874
    if (err->str2 != NULL)
875
        xmlFree(err->str2);
876
    if (err->str3 != NULL)
877
        xmlFree(err->str3);
878
    memset(err, 0, sizeof(xmlError));
879
    err->code = XML_ERR_OK;
880
}
881
882
/**
883
 * xmlResetLastError:
884
 *
885
 * Cleanup the last global error registered. For parsing error
886
 * this does not change the well-formedness result.
887
 */
888
void
889
xmlResetLastError(void)
890
{
891
    if (xmlLastError.code == XML_ERR_OK)
892
        return;
893
    xmlResetError(&xmlLastError);
894
}
895
896
/**
897
 * xmlCtxtGetLastError:
898
 * @ctx:  an XML parser context
899
 *
900
 * Get the last parsing error registered.
901
 *
902
 * Returns NULL if no error occured or a pointer to the error
903
 */
904
xmlErrorPtr
905
xmlCtxtGetLastError(void *ctx)
906
{
907
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
908
909
    if (ctxt == NULL)
910
        return (NULL);
911
    if (ctxt->lastError.code == XML_ERR_OK)
912
        return (NULL);
913
    return (&ctxt->lastError);
914
}
915
916
/**
917
 * xmlCtxtResetLastError:
918
 * @ctx:  an XML parser context
919
 *
920
 * Cleanup the last global error registered. For parsing error
921
 * this does not change the well-formedness result.
922
 */
923
void
924
xmlCtxtResetLastError(void *ctx)
925
{
926
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
927
928
    if (ctxt == NULL)
929
        return;
930
    if (ctxt->lastError.code == XML_ERR_OK)
931
        return;
932
    xmlResetError(&ctxt->lastError);
933
}
934
935
/**
936
 * xmlCopyError:
937
 * @from:  a source error
938
 * @to:  a target error
939
 *
940
 * Save the original error to the new place.
941
 *
942
 * Returns 0 in case of success and -1 in case of error.
943
 */
944
int
945
xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
946
    char *message, *file, *str1, *str2, *str3;
947
948
    if ((from == NULL) || (to == NULL))
949
        return(-1);
950
951
    message = (char *) xmlStrdup((xmlChar *) from->message);
952
    file = (char *) xmlStrdup ((xmlChar *) from->file);
953
    str1 = (char *) xmlStrdup ((xmlChar *) from->str1);
954
    str2 = (char *) xmlStrdup ((xmlChar *) from->str2);
955
    str3 = (char *) xmlStrdup ((xmlChar *) from->str3);
956
957
    if (to->message != NULL)
958
        xmlFree(to->message);
959
    if (to->file != NULL)
960
        xmlFree(to->file);
961
    if (to->str1 != NULL)
962
        xmlFree(to->str1);
963
    if (to->str2 != NULL)
964
        xmlFree(to->str2);
965
    if (to->str3 != NULL)
966
        xmlFree(to->str3);
967
    to->domain = from->domain;
968
    to->code = from->code;
969
    to->level = from->level;
970
    to->line = from->line;
971
    to->node = from->node;
972
    to->int1 = from->int1;
973
    to->int2 = from->int2;
974
    to->node = from->node;
975
    to->ctxt = from->ctxt;
976
    to->message = message;
977
    to->file = file;
978
    to->str1 = str1;
979
    to->str2 = str2;
980
    to->str3 = str3;
981
982
    return 0;
983
}
984
985
#define bottom_error
986
#include "elfgcchack.h"