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 (at) 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 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) 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 (code == XML_ERR_OK) 456 return; 457 if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING)) 458 return; 459 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || 460 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || 461 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { 462 ctxt = (xmlParserCtxtPtr) ctx; 463 if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) && 464 (ctxt->sax->initialized == XML_SAX2_MAGIC) && 465 (ctxt->sax->serror != NULL)) { 466 schannel = ctxt->sax->serror; 467 data = ctxt->userData; 468 } 469 } 470 /* 471 * Check if structured error handler set 472 */ 473 if (schannel == NULL) { 474 schannel = xmlStructuredError; 475 /* 476 * if user has defined handler, change data ptr to user's choice 477 */ 478 if (schannel != NULL) 479 data = xmlStructuredErrorContext; 480 } 481 /* 482 * Formatting the message 483 */ 484 if (msg == NULL) { 485 str = (char *) xmlStrdup(BAD_CAST "No error message provided"); 486 } else { 487 XML_GET_VAR_STR(msg, str); 488 } 489 490 /* 491 * specific processing if a parser context is provided 492 */ 493 if (ctxt != NULL) { 494 if (file == NULL) { 495 input = ctxt->input; 496 if ((input != NULL) && (input->filename == NULL) && 497 (ctxt->inputNr > 1)) { 498 input = ctxt->inputTab[ctxt->inputNr - 2]; 499 } 500 if (input != NULL) { 501 file = input->filename; 502 line = input->line; 503 col = input->col; 504 } 505 } 506 to = &ctxt->lastError; 507 } else if ((node != NULL) && (file == NULL)) { 508 int i; 509 510 if ((node->doc != NULL) && (node->doc->URL != NULL)) { 511 baseptr = node; 512 /* file = (const char *) node->doc->URL; */ 513 } 514 for (i = 0; 515 ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE)); 516 i++) 517 node = node->parent; 518 if ((baseptr == NULL) && (node != NULL) && 519 (node->doc != NULL) && (node->doc->URL != NULL)) 520 baseptr = node; 521 522 if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) 523 line = node->line; 524 } 525 526 /* 527 * Save the information about the error 528 */ 529 xmlResetError(to); 530 to->domain = domain; 531 to->code = code; 532 to->message = str; 533 to->level = level; 534 if (file != NULL) 535 to->file = (char *) xmlStrdup((const xmlChar *) file); 536 else if (baseptr != NULL) { 537 #ifdef LIBXML_XINCLUDE_ENABLED 538 /* 539 * We check if the error is within an XInclude section and, 540 * if so, attempt to print out the href of the XInclude instead 541 * of the usual "base" (doc->URL) for the node (bug 152623). 542 */ 543 xmlNodePtr prev = baseptr; 544 int inclcount = 0; 545 while (prev != NULL) { 546 if (prev->prev == NULL) 547 prev = prev->parent; 548 else { 549 prev = prev->prev; 550 if (prev->type == XML_XINCLUDE_START) { 551 if (--inclcount < 0) 552 break; 553 } else if (prev->type == XML_XINCLUDE_END) 554 inclcount++; 555 } 556 } 557 if (prev != NULL) { 558 if (prev->type == XML_XINCLUDE_START) { 559 prev->type = XML_ELEMENT_NODE; 560 to->file = (char *) xmlGetProp(prev, BAD_CAST "href"); 561 prev->type = XML_XINCLUDE_START; 562 } else { 563 to->file = (char *) xmlGetProp(prev, BAD_CAST "href"); 564 } 565 } else 566 #endif 567 to->file = (char *) xmlStrdup(baseptr->doc->URL); 568 if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) { 569 to->file = (char *) xmlStrdup(node->doc->URL); 570 } 571 } 572 to->line = line; 573 if (str1 != NULL) 574 to->str1 = (char *) xmlStrdup((const xmlChar *) str1); 575 if (str2 != NULL) 576 to->str2 = (char *) xmlStrdup((const xmlChar *) str2); 577 if (str3 != NULL) 578 to->str3 = (char *) xmlStrdup((const xmlChar *) str3); 579 to->int1 = int1; 580 to->int2 = col; 581 to->node = node; 582 to->ctxt = ctx; 583 584 if (to != &xmlLastError) 585 xmlCopyError(to,&xmlLastError); 586 587 if (schannel != NULL) { 588 schannel(data, to); 589 return; 590 } 591 592 /* 593 * Find the callback channel if channel param is NULL 594 */ 595 if ((ctxt != NULL) && (channel == NULL) && 596 (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 channel = xmlGenericError; 604 if (!data) 605 data = xmlGenericErrorContext; 606 } 607 if (channel == NULL) 608 return; 609 610 if ((channel == xmlParserError) || 611 (channel == xmlParserWarning) || 612 (channel == xmlParserValidityError) || 613 (channel == xmlParserValidityWarning)) 614 xmlReportError(to, ctxt, str, NULL, NULL); 615 else if ((channel == (xmlGenericErrorFunc) fprintf) || 616 (channel == xmlGenericErrorDefaultFunc)) 617 xmlReportError(to, ctxt, str, channel, data); 618 else 619 channel(data, "%s", str); 620 } 621 622 /** 623 * __xmlSimpleError: 624 * @domain: where the error comes from 625 * @code: the error code 626 * @node: the context node 627 * @extra: extra informations 628 * 629 * Handle an out of memory condition 630 */ 631 void 632 __xmlSimpleError(int domain, int code, xmlNodePtr node, 633 const char *msg, const char *extra) 634 { 635 636 if (code == XML_ERR_NO_MEMORY) { 637 if (extra) 638 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, 639 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, 640 NULL, NULL, 0, 0, 641 "Memory allocation failed : %s\n", extra); 642 else 643 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, 644 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, 645 NULL, NULL, 0, 0, "Memory allocation failed\n"); 646 } else { 647 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, 648 code, XML_ERR_ERROR, NULL, 0, extra, 649 NULL, NULL, 0, 0, msg, extra); 650 } 651 } 652 /** 653 * xmlParserError: 654 * @ctx: an XML parser context 655 * @msg: the message to display/transmit 656 * @...: extra parameters for the message display 657 * 658 * Display and format an error messages, gives file, line, position and 659 * extra parameters. 660 */ 661 void XMLCDECL 662 xmlParserError(void *ctx, const char *msg, ...) 663 { 664 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 665 xmlParserInputPtr input = NULL; 666 xmlParserInputPtr cur = NULL; 667 char * str; 668 669 if (ctxt != NULL) { 670 input = ctxt->input; 671 if ((input != NULL) && (input->filename == NULL) && 672 (ctxt->inputNr > 1)) { 673 cur = input; 674 input = ctxt->inputTab[ctxt->inputNr - 2]; 675 } 676 xmlParserPrintFileInfo(input); 677 } 678 679 xmlGenericError(xmlGenericErrorContext, "error: "); 680 XML_GET_VAR_STR(msg, str); 681 xmlGenericError(xmlGenericErrorContext, "%s", str); 682 if (str != NULL) 683 xmlFree(str); 684 685 if (ctxt != NULL) { 686 xmlParserPrintFileContext(input); 687 if (cur != NULL) { 688 xmlParserPrintFileInfo(cur); 689 xmlGenericError(xmlGenericErrorContext, "\n"); 690 xmlParserPrintFileContext(cur); 691 } 692 } 693 } 694 695 /** 696 * xmlParserWarning: 697 * @ctx: an XML parser context 698 * @msg: the message to display/transmit 699 * @...: extra parameters for the message display 700 * 701 * Display and format a warning messages, gives file, line, position and 702 * extra parameters. 703 */ 704 void XMLCDECL 705 xmlParserWarning(void *ctx, const char *msg, ...) 706 { 707 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 708 xmlParserInputPtr input = NULL; 709 xmlParserInputPtr cur = NULL; 710 char * str; 711 712 if (ctxt != NULL) { 713 input = ctxt->input; 714 if ((input != NULL) && (input->filename == NULL) && 715 (ctxt->inputNr > 1)) { 716 cur = input; 717 input = ctxt->inputTab[ctxt->inputNr - 2]; 718 } 719 xmlParserPrintFileInfo(input); 720 } 721 722 xmlGenericError(xmlGenericErrorContext, "warning: "); 723 XML_GET_VAR_STR(msg, str); 724 xmlGenericError(xmlGenericErrorContext, "%s", str); 725 if (str != NULL) 726 xmlFree(str); 727 728 if (ctxt != NULL) { 729 xmlParserPrintFileContext(input); 730 if (cur != NULL) { 731 xmlParserPrintFileInfo(cur); 732 xmlGenericError(xmlGenericErrorContext, "\n"); 733 xmlParserPrintFileContext(cur); 734 } 735 } 736 } 737 738 /************************************************************************ 739 * * 740 * Handling of validation errors * 741 * * 742 ************************************************************************/ 743 744 /** 745 * xmlParserValidityError: 746 * @ctx: an XML parser context 747 * @msg: the message to display/transmit 748 * @...: extra parameters for the message display 749 * 750 * Display and format an validity error messages, gives file, 751 * line, position and extra parameters. 752 */ 753 void XMLCDECL 754 xmlParserValidityError(void *ctx, const char *msg, ...) 755 { 756 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 757 xmlParserInputPtr input = NULL; 758 char * str; 759 int len = xmlStrlen((const xmlChar *) msg); 760 static int had_info = 0; 761 762 if ((len > 1) && (msg[len - 2] != ':')) { 763 if (ctxt != NULL) { 764 input = ctxt->input; 765 if ((input->filename == NULL) && (ctxt->inputNr > 1)) 766 input = ctxt->inputTab[ctxt->inputNr - 2]; 767 768 if (had_info == 0) { 769 xmlParserPrintFileInfo(input); 770 } 771 } 772 xmlGenericError(xmlGenericErrorContext, "validity error: "); 773 had_info = 0; 774 } else { 775 had_info = 1; 776 } 777 778 XML_GET_VAR_STR(msg, str); 779 xmlGenericError(xmlGenericErrorContext, "%s", str); 780 if (str != NULL) 781 xmlFree(str); 782 783 if ((ctxt != NULL) && (input != NULL)) { 784 xmlParserPrintFileContext(input); 785 } 786 } 787 788 /** 789 * xmlParserValidityWarning: 790 * @ctx: an XML parser context 791 * @msg: the message to display/transmit 792 * @...: extra parameters for the message display 793 * 794 * Display and format a validity warning messages, gives file, line, 795 * position and extra parameters. 796 */ 797 void XMLCDECL 798 xmlParserValidityWarning(void *ctx, const char *msg, ...) 799 { 800 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 801 xmlParserInputPtr input = NULL; 802 char * str; 803 int len = xmlStrlen((const xmlChar *) msg); 804 805 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) { 806 input = ctxt->input; 807 if ((input->filename == NULL) && (ctxt->inputNr > 1)) 808 input = ctxt->inputTab[ctxt->inputNr - 2]; 809 810 xmlParserPrintFileInfo(input); 811 } 812 813 xmlGenericError(xmlGenericErrorContext, "validity warning: "); 814 XML_GET_VAR_STR(msg, str); 815 xmlGenericError(xmlGenericErrorContext, "%s", str); 816 if (str != NULL) 817 xmlFree(str); 818 819 if (ctxt != NULL) { 820 xmlParserPrintFileContext(input); 821 } 822 } 823 824 825 /************************************************************************ 826 * * 827 * Extended Error Handling * 828 * * 829 ************************************************************************/ 830 831 /** 832 * xmlGetLastError: 833 * 834 * Get the last global error registered. This is per thread if compiled 835 * with thread support. 836 * 837 * Returns NULL if no error occured or a pointer to the error 838 */ 839 xmlErrorPtr 840 xmlGetLastError(void) 841 { 842 if (xmlLastError.code == XML_ERR_OK) 843 return (NULL); 844 return (&xmlLastError); 845 } 846 847 /** 848 * xmlResetError: 849 * @err: pointer to the error. 850 * 851 * Cleanup the error. 852 */ 853 void 854 xmlResetError(xmlErrorPtr err) 855 { 856 if (err == NULL) 857 return; 858 if (err->code == XML_ERR_OK) 859 return; 860 if (err->message != NULL) 861 xmlFree(err->message); 862 if (err->file != NULL) 863 xmlFree(err->file); 864 if (err->str1 != NULL) 865 xmlFree(err->str1); 866 if (err->str2 != NULL) 867 xmlFree(err->str2); 868 if (err->str3 != NULL) 869 xmlFree(err->str3); 870 memset(err, 0, sizeof(xmlError)); 871 err->code = XML_ERR_OK; 872 } 873 874 /** 875 * xmlResetLastError: 876 * 877 * Cleanup the last global error registered. For parsing error 878 * this does not change the well-formedness result. 879 */ 880 void 881 xmlResetLastError(void) 882 { 883 if (xmlLastError.code == XML_ERR_OK) 884 return; 885 xmlResetError(&xmlLastError); 886 } 887 888 /** 889 * xmlCtxtGetLastError: 890 * @ctx: an XML parser context 891 * 892 * Get the last parsing error registered. 893 * 894 * Returns NULL if no error occured or a pointer to the error 895 */ 896 xmlErrorPtr 897 xmlCtxtGetLastError(void *ctx) 898 { 899 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 900 901 if (ctxt == NULL) 902 return (NULL); 903 if (ctxt->lastError.code == XML_ERR_OK) 904 return (NULL); 905 return (&ctxt->lastError); 906 } 907 908 /** 909 * xmlCtxtResetLastError: 910 * @ctx: an XML parser context 911 * 912 * Cleanup the last global error registered. For parsing error 913 * this does not change the well-formedness result. 914 */ 915 void 916 xmlCtxtResetLastError(void *ctx) 917 { 918 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 919 920 if (ctxt == NULL) 921 return; 922 ctxt->errNo = XML_ERR_OK; 923 if (ctxt->lastError.code == XML_ERR_OK) 924 return; 925 xmlResetError(&ctxt->lastError); 926 } 927 928 /** 929 * xmlCopyError: 930 * @from: a source error 931 * @to: a target error 932 * 933 * Save the original error to the new place. 934 * 935 * Returns 0 in case of success and -1 in case of error. 936 */ 937 int 938 xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) { 939 char *message, *file, *str1, *str2, *str3; 940 941 if ((from == NULL) || (to == NULL)) 942 return(-1); 943 944 message = (char *) xmlStrdup((xmlChar *) from->message); 945 file = (char *) xmlStrdup ((xmlChar *) from->file); 946 str1 = (char *) xmlStrdup ((xmlChar *) from->str1); 947 str2 = (char *) xmlStrdup ((xmlChar *) from->str2); 948 str3 = (char *) xmlStrdup ((xmlChar *) from->str3); 949 950 if (to->message != NULL) 951 xmlFree(to->message); 952 if (to->file != NULL) 953 xmlFree(to->file); 954 if (to->str1 != NULL) 955 xmlFree(to->str1); 956 if (to->str2 != NULL) 957 xmlFree(to->str2); 958 if (to->str3 != NULL) 959 xmlFree(to->str3); 960 to->domain = from->domain; 961 to->code = from->code; 962 to->level = from->level; 963 to->line = from->line; 964 to->node = from->node; 965 to->int1 = from->int1; 966 to->int2 = from->int2; 967 to->node = from->node; 968 to->ctxt = from->ctxt; 969 to->message = message; 970 to->file = file; 971 to->str1 = str1; 972 to->str2 = str2; 973 to->str3 = str3; 974 975 return 0; 976 } 977 978 #define bottom_error 979 #include "elfgcchack.h" 980