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