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 ((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 = xmlStructuredErrorContext; 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 } 577 to->line = line; 578 if (str1 != NULL) 579 to->str1 = (char *) xmlStrdup((const xmlChar *) str1); 580 if (str2 != NULL) 581 to->str2 = (char *) xmlStrdup((const xmlChar *) str2); 582 if (str3 != NULL) 583 to->str3 = (char *) xmlStrdup((const xmlChar *) str3); 584 to->int1 = int1; 585 to->int2 = col; 586 to->node = node; 587 to->ctxt = ctx; 588 589 if (to != &xmlLastError) 590 xmlCopyError(to,&xmlLastError); 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 if ((schannel == NULL) && (xmlStructuredError != NULL)) { 604 schannel = xmlStructuredError; 605 data = xmlStructuredErrorContext; 606 } else { 607 channel = xmlGenericError; 608 if (!data) { 609 data = xmlGenericErrorContext; 610 } 611 } 612 } 613 if (schannel != NULL) { 614 schannel(data, to); 615 return; 616 } 617 if (channel == NULL) 618 return; 619 620 if ((channel == xmlParserError) || 621 (channel == xmlParserWarning) || 622 (channel == xmlParserValidityError) || 623 (channel == xmlParserValidityWarning)) 624 xmlReportError(to, ctxt, str, NULL, NULL); 625 else if ((channel == (xmlGenericErrorFunc) fprintf) || 626 (channel == xmlGenericErrorDefaultFunc)) 627 xmlReportError(to, ctxt, str, channel, data); 628 else 629 channel(data, "%s", str); 630 } 631 632 /** 633 * __xmlSimpleError: 634 * @domain: where the error comes from 635 * @code: the error code 636 * @node: the context node 637 * @extra: extra informations 638 * 639 * Handle an out of memory condition 640 */ 641 void 642 __xmlSimpleError(int domain, int code, xmlNodePtr node, 643 const char *msg, const char *extra) 644 { 645 646 if (code == XML_ERR_NO_MEMORY) { 647 if (extra) 648 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, 649 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, 650 NULL, NULL, 0, 0, 651 "Memory allocation failed : %s\n", extra); 652 else 653 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, 654 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, 655 NULL, NULL, 0, 0, "Memory allocation failed\n"); 656 } else { 657 __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, 658 code, XML_ERR_ERROR, NULL, 0, extra, 659 NULL, NULL, 0, 0, msg, extra); 660 } 661 } 662 /** 663 * xmlParserError: 664 * @ctx: an XML parser context 665 * @msg: the message to display/transmit 666 * @...: extra parameters for the message display 667 * 668 * Display and format an error messages, gives file, line, position and 669 * extra parameters. 670 */ 671 void XMLCDECL 672 xmlParserError(void *ctx, const char *msg, ...) 673 { 674 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 675 xmlParserInputPtr input = NULL; 676 xmlParserInputPtr cur = NULL; 677 char * str; 678 679 if (ctxt != NULL) { 680 input = ctxt->input; 681 if ((input != NULL) && (input->filename == NULL) && 682 (ctxt->inputNr > 1)) { 683 cur = input; 684 input = ctxt->inputTab[ctxt->inputNr - 2]; 685 } 686 xmlParserPrintFileInfo(input); 687 } 688 689 xmlGenericError(xmlGenericErrorContext, "error: "); 690 XML_GET_VAR_STR(msg, str); 691 xmlGenericError(xmlGenericErrorContext, "%s", str); 692 if (str != NULL) 693 xmlFree(str); 694 695 if (ctxt != NULL) { 696 xmlParserPrintFileContext(input); 697 if (cur != NULL) { 698 xmlParserPrintFileInfo(cur); 699 xmlGenericError(xmlGenericErrorContext, "\n"); 700 xmlParserPrintFileContext(cur); 701 } 702 } 703 } 704 705 /** 706 * xmlParserWarning: 707 * @ctx: an XML parser context 708 * @msg: the message to display/transmit 709 * @...: extra parameters for the message display 710 * 711 * Display and format a warning messages, gives file, line, position and 712 * extra parameters. 713 */ 714 void XMLCDECL 715 xmlParserWarning(void *ctx, const char *msg, ...) 716 { 717 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 718 xmlParserInputPtr input = NULL; 719 xmlParserInputPtr cur = NULL; 720 char * str; 721 722 if (ctxt != NULL) { 723 input = ctxt->input; 724 if ((input != NULL) && (input->filename == NULL) && 725 (ctxt->inputNr > 1)) { 726 cur = input; 727 input = ctxt->inputTab[ctxt->inputNr - 2]; 728 } 729 xmlParserPrintFileInfo(input); 730 } 731 732 xmlGenericError(xmlGenericErrorContext, "warning: "); 733 XML_GET_VAR_STR(msg, str); 734 xmlGenericError(xmlGenericErrorContext, "%s", str); 735 if (str != NULL) 736 xmlFree(str); 737 738 if (ctxt != NULL) { 739 xmlParserPrintFileContext(input); 740 if (cur != NULL) { 741 xmlParserPrintFileInfo(cur); 742 xmlGenericError(xmlGenericErrorContext, "\n"); 743 xmlParserPrintFileContext(cur); 744 } 745 } 746 } 747 748 /************************************************************************ 749 * * 750 * Handling of validation errors * 751 * * 752 ************************************************************************/ 753 754 /** 755 * xmlParserValidityError: 756 * @ctx: an XML parser context 757 * @msg: the message to display/transmit 758 * @...: extra parameters for the message display 759 * 760 * Display and format an validity error messages, gives file, 761 * line, position and extra parameters. 762 */ 763 void XMLCDECL 764 xmlParserValidityError(void *ctx, const char *msg, ...) 765 { 766 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 767 xmlParserInputPtr input = NULL; 768 char * str; 769 int len = xmlStrlen((const xmlChar *) msg); 770 static int had_info = 0; 771 772 if ((len > 1) && (msg[len - 2] != ':')) { 773 if (ctxt != NULL) { 774 input = ctxt->input; 775 if ((input->filename == NULL) && (ctxt->inputNr > 1)) 776 input = ctxt->inputTab[ctxt->inputNr - 2]; 777 778 if (had_info == 0) { 779 xmlParserPrintFileInfo(input); 780 } 781 } 782 xmlGenericError(xmlGenericErrorContext, "validity error: "); 783 had_info = 0; 784 } else { 785 had_info = 1; 786 } 787 788 XML_GET_VAR_STR(msg, str); 789 xmlGenericError(xmlGenericErrorContext, "%s", str); 790 if (str != NULL) 791 xmlFree(str); 792 793 if ((ctxt != NULL) && (input != NULL)) { 794 xmlParserPrintFileContext(input); 795 } 796 } 797 798 /** 799 * xmlParserValidityWarning: 800 * @ctx: an XML parser context 801 * @msg: the message to display/transmit 802 * @...: extra parameters for the message display 803 * 804 * Display and format a validity warning messages, gives file, line, 805 * position and extra parameters. 806 */ 807 void XMLCDECL 808 xmlParserValidityWarning(void *ctx, const char *msg, ...) 809 { 810 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 811 xmlParserInputPtr input = NULL; 812 char * str; 813 int len = xmlStrlen((const xmlChar *) msg); 814 815 if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) { 816 input = ctxt->input; 817 if ((input->filename == NULL) && (ctxt->inputNr > 1)) 818 input = ctxt->inputTab[ctxt->inputNr - 2]; 819 820 xmlParserPrintFileInfo(input); 821 } 822 823 xmlGenericError(xmlGenericErrorContext, "validity warning: "); 824 XML_GET_VAR_STR(msg, str); 825 xmlGenericError(xmlGenericErrorContext, "%s", str); 826 if (str != NULL) 827 xmlFree(str); 828 829 if (ctxt != NULL) { 830 xmlParserPrintFileContext(input); 831 } 832 } 833 834 835 /************************************************************************ 836 * * 837 * Extended Error Handling * 838 * * 839 ************************************************************************/ 840 841 /** 842 * xmlGetLastError: 843 * 844 * Get the last global error registered. This is per thread if compiled 845 * with thread support. 846 * 847 * Returns NULL if no error occured or a pointer to the error 848 */ 849 xmlErrorPtr 850 xmlGetLastError(void) 851 { 852 if (xmlLastError.code == XML_ERR_OK) 853 return (NULL); 854 return (&xmlLastError); 855 } 856 857 /** 858 * xmlResetError: 859 * @err: pointer to the error. 860 * 861 * Cleanup the error. 862 */ 863 void 864 xmlResetError(xmlErrorPtr err) 865 { 866 if (err == NULL) 867 return; 868 if (err->code == XML_ERR_OK) 869 return; 870 if (err->message != NULL) 871 xmlFree(err->message); 872 if (err->file != NULL) 873 xmlFree(err->file); 874 if (err->str1 != NULL) 875 xmlFree(err->str1); 876 if (err->str2 != NULL) 877 xmlFree(err->str2); 878 if (err->str3 != NULL) 879 xmlFree(err->str3); 880 memset(err, 0, sizeof(xmlError)); 881 err->code = XML_ERR_OK; 882 } 883 884 /** 885 * xmlResetLastError: 886 * 887 * Cleanup the last global error registered. For parsing error 888 * this does not change the well-formedness result. 889 */ 890 void 891 xmlResetLastError(void) 892 { 893 if (xmlLastError.code == XML_ERR_OK) 894 return; 895 xmlResetError(&xmlLastError); 896 } 897 898 /** 899 * xmlCtxtGetLastError: 900 * @ctx: an XML parser context 901 * 902 * Get the last parsing error registered. 903 * 904 * Returns NULL if no error occured or a pointer to the error 905 */ 906 xmlErrorPtr 907 xmlCtxtGetLastError(void *ctx) 908 { 909 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 910 911 if (ctxt == NULL) 912 return (NULL); 913 if (ctxt->lastError.code == XML_ERR_OK) 914 return (NULL); 915 return (&ctxt->lastError); 916 } 917 918 /** 919 * xmlCtxtResetLastError: 920 * @ctx: an XML parser context 921 * 922 * Cleanup the last global error registered. For parsing error 923 * this does not change the well-formedness result. 924 */ 925 void 926 xmlCtxtResetLastError(void *ctx) 927 { 928 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 929 930 if (ctxt == NULL) 931 return; 932 ctxt->errNo = XML_ERR_OK; 933 if (ctxt->lastError.code == XML_ERR_OK) 934 return; 935 xmlResetError(&ctxt->lastError); 936 } 937 938 /** 939 * xmlCopyError: 940 * @from: a source error 941 * @to: a target error 942 * 943 * Save the original error to the new place. 944 * 945 * Returns 0 in case of success and -1 in case of error. 946 */ 947 int 948 xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) { 949 char *message, *file, *str1, *str2, *str3; 950 951 if ((from == NULL) || (to == NULL)) 952 return(-1); 953 954 message = (char *) xmlStrdup((xmlChar *) from->message); 955 file = (char *) xmlStrdup ((xmlChar *) from->file); 956 str1 = (char *) xmlStrdup ((xmlChar *) from->str1); 957 str2 = (char *) xmlStrdup ((xmlChar *) from->str2); 958 str3 = (char *) xmlStrdup ((xmlChar *) from->str3); 959 960 if (to->message != NULL) 961 xmlFree(to->message); 962 if (to->file != NULL) 963 xmlFree(to->file); 964 if (to->str1 != NULL) 965 xmlFree(to->str1); 966 if (to->str2 != NULL) 967 xmlFree(to->str2); 968 if (to->str3 != NULL) 969 xmlFree(to->str3); 970 to->domain = from->domain; 971 to->code = from->code; 972 to->level = from->level; 973 to->line = from->line; 974 to->node = from->node; 975 to->int1 = from->int1; 976 to->int2 = from->int2; 977 to->node = from->node; 978 to->ctxt = from->ctxt; 979 to->message = message; 980 to->file = file; 981 to->str1 = str1; 982 to->str2 = str2; 983 to->str3 = str3; 984 985 return 0; 986 } 987 988 #define bottom_error 989 #include "elfgcchack.h" 990