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