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