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