1 /* 2 * runtest.c: C program to run libxml2 regression tests without 3 * requiring make or Python, and reducing platform dependancies 4 * to a strict minimum. 5 * 6 * To compile on Unixes: 7 * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread 8 * 9 * See Copyright for the status of this software. 10 * 11 * daniel (at) veillard.com 12 */ 13 14 #ifdef HAVE_CONFIG_H 15 #include "libxml.h" 16 #else 17 #include <stdio.h> 18 #endif 19 20 #if !defined(_WIN32) || defined(__CYGWIN__) 21 #include <unistd.h> 22 #endif 23 #include <string.h> 24 #include <sys/types.h> 25 #include <sys/stat.h> 26 #include <fcntl.h> 27 28 #include <libxml/parser.h> 29 #include <libxml/tree.h> 30 #include <libxml/uri.h> 31 32 #ifdef LIBXML_OUTPUT_ENABLED 33 #ifdef LIBXML_READER_ENABLED 34 #include <libxml/xmlreader.h> 35 #endif 36 37 #ifdef LIBXML_XINCLUDE_ENABLED 38 #include <libxml/xinclude.h> 39 #endif 40 41 #ifdef LIBXML_XPATH_ENABLED 42 #include <libxml/xpath.h> 43 #include <libxml/xpathInternals.h> 44 #ifdef LIBXML_XPTR_ENABLED 45 #include <libxml/xpointer.h> 46 #endif 47 #endif 48 49 #ifdef LIBXML_SCHEMAS_ENABLED 50 #include <libxml/relaxng.h> 51 #include <libxml/xmlschemas.h> 52 #include <libxml/xmlschemastypes.h> 53 #endif 54 55 #ifdef LIBXML_PATTERN_ENABLED 56 #include <libxml/pattern.h> 57 #endif 58 59 #ifdef LIBXML_C14N_ENABLED 60 #include <libxml/c14n.h> 61 #endif 62 63 #ifdef LIBXML_HTML_ENABLED 64 #include <libxml/HTMLparser.h> 65 #include <libxml/HTMLtree.h> 66 67 /* 68 * pseudo flag for the unification of HTML and XML tests 69 */ 70 #define XML_PARSE_HTML 1 << 24 71 #endif 72 73 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) 74 #include <libxml/globals.h> 75 #include <libxml/threads.h> 76 #include <libxml/parser.h> 77 #include <libxml/catalog.h> 78 #include <string.h> 79 #endif 80 81 /* 82 * O_BINARY is just for Windows compatibility - if it isn't defined 83 * on this system, avoid any compilation error 84 */ 85 #ifdef O_BINARY 86 #define RD_FLAGS O_RDONLY | O_BINARY 87 #else 88 #define RD_FLAGS O_RDONLY 89 #endif 90 91 typedef int (*functest) (const char *filename, const char *result, 92 const char *error, int options); 93 94 typedef struct testDesc testDesc; 95 typedef testDesc *testDescPtr; 96 struct testDesc { 97 const char *desc; /* descripton of the test */ 98 functest func; /* function implementing the test */ 99 const char *in; /* glob to path for input files */ 100 const char *out; /* output directory */ 101 const char *suffix;/* suffix for output files */ 102 const char *err; /* suffix for error output files */ 103 int options; /* parser options for the test */ 104 }; 105 106 static int checkTestFile(const char *filename); 107 108 #if defined(_WIN32) && !defined(__CYGWIN__) 109 110 #include <windows.h> 111 #include <io.h> 112 113 typedef struct 114 { 115 size_t gl_pathc; /* Count of paths matched so far */ 116 char **gl_pathv; /* List of matched pathnames. */ 117 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */ 118 } glob_t; 119 120 #define GLOB_DOOFFS 0 121 static int glob(const char *pattern, int flags, 122 int errfunc(const char *epath, int eerrno), 123 glob_t *pglob) { 124 glob_t *ret; 125 WIN32_FIND_DATA FindFileData; 126 HANDLE hFind; 127 unsigned int nb_paths = 0; 128 char directory[500]; 129 int len; 130 131 if ((pattern == NULL) || (pglob == NULL)) return(-1); 132 133 strncpy(directory, pattern, 499); 134 for (len = strlen(directory);len >= 0;len--) { 135 if (directory[len] == '/') { 136 len++; 137 directory[len] = 0; 138 break; 139 } 140 } 141 if (len <= 0) 142 len = 0; 143 144 145 ret = pglob; 146 memset(ret, 0, sizeof(glob_t)); 147 148 hFind = FindFirstFileA(pattern, &FindFileData); 149 if (hFind == INVALID_HANDLE_VALUE) 150 return(0); 151 nb_paths = 20; 152 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *)); 153 if (ret->gl_pathv == NULL) { 154 FindClose(hFind); 155 return(-1); 156 } 157 strncpy(directory + len, FindFileData.cFileName, 499 - len); 158 ret->gl_pathv[ret->gl_pathc] = strdup(directory); 159 if (ret->gl_pathv[ret->gl_pathc] == NULL) 160 goto done; 161 ret->gl_pathc++; 162 while(FindNextFileA(hFind, &FindFileData)) { 163 if (FindFileData.cFileName[0] == '.') 164 continue; 165 if (ret->gl_pathc + 2 > nb_paths) { 166 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *)); 167 if (tmp == NULL) 168 break; 169 ret->gl_pathv = tmp; 170 nb_paths *= 2; 171 } 172 strncpy(directory + len, FindFileData.cFileName, 499 - len); 173 ret->gl_pathv[ret->gl_pathc] = strdup(directory); 174 if (ret->gl_pathv[ret->gl_pathc] == NULL) 175 break; 176 ret->gl_pathc++; 177 } 178 ret->gl_pathv[ret->gl_pathc] = NULL; 179 180 done: 181 FindClose(hFind); 182 return(0); 183 } 184 185 186 187 static void globfree(glob_t *pglob) { 188 unsigned int i; 189 if (pglob == NULL) 190 return; 191 192 for (i = 0;i < pglob->gl_pathc;i++) { 193 if (pglob->gl_pathv[i] != NULL) 194 free(pglob->gl_pathv[i]); 195 } 196 } 197 #define vsnprintf _vsnprintf 198 #define snprintf _snprintf 199 #else 200 #include <glob.h> 201 #endif 202 203 /************************************************************************ 204 * * 205 * Libxml2 specific routines * 206 * * 207 ************************************************************************/ 208 209 static int nb_tests = 0; 210 static int nb_errors = 0; 211 static int nb_leaks = 0; 212 static int extraMemoryFromResolver = 0; 213 214 static int 215 fatalError(void) { 216 fprintf(stderr, "Exitting tests on fatal error\n"); 217 exit(1); 218 } 219 220 /* 221 * We need to trap calls to the resolver to not account memory for the catalog 222 * which is shared to the current running test. We also don't want to have 223 * network downloads modifying tests. 224 */ 225 static xmlParserInputPtr 226 testExternalEntityLoader(const char *URL, const char *ID, 227 xmlParserCtxtPtr ctxt) { 228 xmlParserInputPtr ret; 229 230 if (checkTestFile(URL)) { 231 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); 232 } else { 233 int memused = xmlMemUsed(); 234 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); 235 extraMemoryFromResolver += xmlMemUsed() - memused; 236 } 237 238 return(ret); 239 } 240 241 /* 242 * Trapping the error messages at the generic level to grab the equivalent of 243 * stderr messages on CLI tools. 244 */ 245 static char testErrors[32769]; 246 static int testErrorsSize = 0; 247 248 static void XMLCDECL 249 testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { 250 va_list args; 251 int res; 252 253 if (testErrorsSize >= 32768) 254 return; 255 va_start(args, msg); 256 res = vsnprintf(&testErrors[testErrorsSize], 257 32768 - testErrorsSize, 258 msg, args); 259 va_end(args); 260 if (testErrorsSize + res >= 32768) { 261 /* buffer is full */ 262 testErrorsSize = 32768; 263 testErrors[testErrorsSize] = 0; 264 } else { 265 testErrorsSize += res; 266 } 267 testErrors[testErrorsSize] = 0; 268 } 269 270 static void XMLCDECL 271 channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { 272 va_list args; 273 int res; 274 275 if (testErrorsSize >= 32768) 276 return; 277 va_start(args, msg); 278 res = vsnprintf(&testErrors[testErrorsSize], 279 32768 - testErrorsSize, 280 msg, args); 281 va_end(args); 282 if (testErrorsSize + res >= 32768) { 283 /* buffer is full */ 284 testErrorsSize = 32768; 285 testErrors[testErrorsSize] = 0; 286 } else { 287 testErrorsSize += res; 288 } 289 testErrors[testErrorsSize] = 0; 290 } 291 292 /** 293 * xmlParserPrintFileContext: 294 * @input: an xmlParserInputPtr input 295 * 296 * Displays current context within the input content for error tracking 297 */ 298 299 static void 300 xmlParserPrintFileContextInternal(xmlParserInputPtr input , 301 xmlGenericErrorFunc chanl, void *data ) { 302 const xmlChar *cur, *base; 303 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ 304 xmlChar content[81]; /* space for 80 chars + line terminator */ 305 xmlChar *ctnt; 306 307 if (input == NULL) return; 308 cur = input->cur; 309 base = input->base; 310 /* skip backwards over any end-of-lines */ 311 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { 312 cur--; 313 } 314 n = 0; 315 /* search backwards for beginning-of-line (to max buff size) */ 316 while ((n++ < (sizeof(content)-1)) && (cur > base) && 317 (*(cur) != '\n') && (*(cur) != '\r')) 318 cur--; 319 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; 320 /* calculate the error position in terms of the current position */ 321 col = input->cur - cur; 322 /* search forward for end-of-line (to max buff size) */ 323 n = 0; 324 ctnt = content; 325 /* copy selected text to our buffer */ 326 while ((*cur != 0) && (*(cur) != '\n') && 327 (*(cur) != '\r') && (n < sizeof(content)-1)) { 328 *ctnt++ = *cur++; 329 n++; 330 } 331 *ctnt = 0; 332 /* print out the selected text */ 333 chanl(data ,"%s\n", content); 334 /* create blank line with problem pointer */ 335 n = 0; 336 ctnt = content; 337 /* (leave buffer space for pointer + line terminator) */ 338 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) { 339 if (*(ctnt) != '\t') 340 *(ctnt) = ' '; 341 ctnt++; 342 } 343 *ctnt++ = '^'; 344 *ctnt = 0; 345 chanl(data ,"%s\n", content); 346 } 347 348 static void 349 testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) { 350 char *file = NULL; 351 int line = 0; 352 int code = -1; 353 int domain; 354 void *data = NULL; 355 const char *str; 356 const xmlChar *name = NULL; 357 xmlNodePtr node; 358 xmlErrorLevel level; 359 xmlParserInputPtr input = NULL; 360 xmlParserInputPtr cur = NULL; 361 xmlParserCtxtPtr ctxt = NULL; 362 363 if (err == NULL) 364 return; 365 366 file = err->file; 367 line = err->line; 368 code = err->code; 369 domain = err->domain; 370 level = err->level; 371 node = err->node; 372 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || 373 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || 374 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { 375 ctxt = err->ctxt; 376 } 377 str = err->message; 378 379 if (code == XML_ERR_OK) 380 return; 381 382 if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) 383 name = node->name; 384 385 /* 386 * Maintain the compatibility with the legacy error handling 387 */ 388 if (ctxt != NULL) { 389 input = ctxt->input; 390 if ((input != NULL) && (input->filename == NULL) && 391 (ctxt->inputNr > 1)) { 392 cur = input; 393 input = ctxt->inputTab[ctxt->inputNr - 2]; 394 } 395 if (input != NULL) { 396 if (input->filename) 397 channel(data, "%s:%d: ", input->filename, input->line); 398 else if ((line != 0) && (domain == XML_FROM_PARSER)) 399 channel(data, "Entity: line %d: ", input->line); 400 } 401 } else { 402 if (file != NULL) 403 channel(data, "%s:%d: ", file, line); 404 else if ((line != 0) && (domain == XML_FROM_PARSER)) 405 channel(data, "Entity: line %d: ", line); 406 } 407 if (name != NULL) { 408 channel(data, "element %s: ", name); 409 } 410 if (code == XML_ERR_OK) 411 return; 412 switch (domain) { 413 case XML_FROM_PARSER: 414 channel(data, "parser "); 415 break; 416 case XML_FROM_NAMESPACE: 417 channel(data, "namespace "); 418 break; 419 case XML_FROM_DTD: 420 case XML_FROM_VALID: 421 channel(data, "validity "); 422 break; 423 case XML_FROM_HTML: 424 channel(data, "HTML parser "); 425 break; 426 case XML_FROM_MEMORY: 427 channel(data, "memory "); 428 break; 429 case XML_FROM_OUTPUT: 430 channel(data, "output "); 431 break; 432 case XML_FROM_IO: 433 channel(data, "I/O "); 434 break; 435 case XML_FROM_XINCLUDE: 436 channel(data, "XInclude "); 437 break; 438 case XML_FROM_XPATH: 439 channel(data, "XPath "); 440 break; 441 case XML_FROM_XPOINTER: 442 channel(data, "parser "); 443 break; 444 case XML_FROM_REGEXP: 445 channel(data, "regexp "); 446 break; 447 case XML_FROM_MODULE: 448 channel(data, "module "); 449 break; 450 case XML_FROM_SCHEMASV: 451 channel(data, "Schemas validity "); 452 break; 453 case XML_FROM_SCHEMASP: 454 channel(data, "Schemas parser "); 455 break; 456 case XML_FROM_RELAXNGP: 457 channel(data, "Relax-NG parser "); 458 break; 459 case XML_FROM_RELAXNGV: 460 channel(data, "Relax-NG validity "); 461 break; 462 case XML_FROM_CATALOG: 463 channel(data, "Catalog "); 464 break; 465 case XML_FROM_C14N: 466 channel(data, "C14N "); 467 break; 468 case XML_FROM_XSLT: 469 channel(data, "XSLT "); 470 break; 471 default: 472 break; 473 } 474 if (code == XML_ERR_OK) 475 return; 476 switch (level) { 477 case XML_ERR_NONE: 478 channel(data, ": "); 479 break; 480 case XML_ERR_WARNING: 481 channel(data, "warning : "); 482 break; 483 case XML_ERR_ERROR: 484 channel(data, "error : "); 485 break; 486 case XML_ERR_FATAL: 487 channel(data, "error : "); 488 break; 489 } 490 if (code == XML_ERR_OK) 491 return; 492 if (str != NULL) { 493 int len; 494 len = xmlStrlen((const xmlChar *)str); 495 if ((len > 0) && (str[len - 1] != '\n')) 496 channel(data, "%s\n", str); 497 else 498 channel(data, "%s", str); 499 } else { 500 channel(data, "%s\n", "out of memory error"); 501 } 502 if (code == XML_ERR_OK) 503 return; 504 505 if (ctxt != NULL) { 506 xmlParserPrintFileContextInternal(input, channel, data); 507 if (cur != NULL) { 508 if (cur->filename) 509 channel(data, "%s:%d: \n", cur->filename, cur->line); 510 else if ((line != 0) && (domain == XML_FROM_PARSER)) 511 channel(data, "Entity: line %d: \n", cur->line); 512 xmlParserPrintFileContextInternal(cur, channel, data); 513 } 514 } 515 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) && 516 (err->int1 < 100) && 517 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) { 518 xmlChar buf[150]; 519 int i; 520 521 channel(data, "%s\n", err->str1); 522 for (i=0;i < err->int1;i++) 523 buf[i] = ' '; 524 buf[i++] = '^'; 525 buf[i] = 0; 526 channel(data, "%s\n", buf); 527 } 528 } 529 530 static void 531 initializeLibxml2(void) { 532 xmlGetWarningsDefaultValue = 0; 533 xmlPedanticParserDefault(0); 534 535 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); 536 xmlInitParser(); 537 xmlSetExternalEntityLoader(testExternalEntityLoader); 538 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler); 539 #ifdef LIBXML_SCHEMAS_ENABLED 540 xmlSchemaInitTypes(); 541 xmlRelaxNGInitTypes(); 542 #endif 543 } 544 545 546 /************************************************************************ 547 * * 548 * File name and path utilities * 549 * * 550 ************************************************************************/ 551 552 static const char *baseFilename(const char *filename) { 553 const char *cur; 554 if (filename == NULL) 555 return(NULL); 556 cur = &filename[strlen(filename)]; 557 while ((cur > filename) && (*cur != '/')) 558 cur--; 559 if (*cur == '/') 560 return(cur + 1); 561 return(cur); 562 } 563 564 static char *resultFilename(const char *filename, const char *out, 565 const char *suffix) { 566 const char *base; 567 char res[500]; 568 char suffixbuff[500]; 569 570 /************* 571 if ((filename[0] == 't') && (filename[1] == 'e') && 572 (filename[2] == 's') && (filename[3] == 't') && 573 (filename[4] == '/')) 574 filename = &filename[5]; 575 *************/ 576 577 base = baseFilename(filename); 578 if (suffix == NULL) 579 suffix = ".tmp"; 580 if (out == NULL) 581 out = ""; 582 583 strncpy(suffixbuff,suffix,499); 584 #ifdef VMS 585 if(strstr(base,".") && suffixbuff[0]=='.') 586 suffixbuff[0]='_'; 587 #endif 588 589 snprintf(res, 499, "%s%s%s", out, base, suffixbuff); 590 res[499] = 0; 591 return(strdup(res)); 592 } 593 594 static int checkTestFile(const char *filename) { 595 struct stat buf; 596 597 if (stat(filename, &buf) == -1) 598 return(0); 599 600 #if defined(_WIN32) && !defined(__CYGWIN__) 601 if (!(buf.st_mode & _S_IFREG)) 602 return(0); 603 #else 604 if (!S_ISREG(buf.st_mode)) 605 return(0); 606 #endif 607 608 return(1); 609 } 610 611 static int compareFiles(const char *r1, const char *r2) { 612 int res1, res2; 613 int fd1, fd2; 614 char bytes1[4096]; 615 char bytes2[4096]; 616 617 fd1 = open(r1, RD_FLAGS); 618 if (fd1 < 0) 619 return(-1); 620 fd2 = open(r2, RD_FLAGS); 621 if (fd2 < 0) { 622 close(fd1); 623 return(-1); 624 } 625 while (1) { 626 res1 = read(fd1, bytes1, 4096); 627 res2 = read(fd2, bytes2, 4096); 628 if ((res1 != res2) || (res1 < 0)) { 629 close(fd1); 630 close(fd2); 631 return(1); 632 } 633 if (res1 == 0) 634 break; 635 if (memcmp(bytes1, bytes2, res1) != 0) { 636 close(fd1); 637 close(fd2); 638 return(1); 639 } 640 } 641 close(fd1); 642 close(fd2); 643 return(0); 644 } 645 646 static int compareFileMem(const char *filename, const char *mem, int size) { 647 int res; 648 int fd; 649 char bytes[4096]; 650 int idx = 0; 651 struct stat info; 652 653 if (stat(filename, &info) < 0) 654 return(-1); 655 if (info.st_size != size) 656 return(-1); 657 fd = open(filename, RD_FLAGS); 658 if (fd < 0) 659 return(-1); 660 while (idx < size) { 661 res = read(fd, bytes, 4096); 662 if (res <= 0) 663 break; 664 if (res + idx > size) 665 break; 666 if (memcmp(bytes, &mem[idx], res) != 0) { 667 int ix; 668 for (ix=0; ix<res; ix++) 669 if (bytes[ix] != mem[idx+ix]) 670 break; 671 fprintf(stderr,"Compare error at position %d\n", idx+ix); 672 close(fd); 673 return(1); 674 } 675 idx += res; 676 } 677 close(fd); 678 return(idx != size); 679 } 680 681 static int loadMem(const char *filename, const char **mem, int *size) { 682 int fd, res; 683 struct stat info; 684 char *base; 685 int siz = 0; 686 if (stat(filename, &info) < 0) 687 return(-1); 688 base = malloc(info.st_size + 1); 689 if (base == NULL) 690 return(-1); 691 if ((fd = open(filename, RD_FLAGS)) < 0) { 692 free(base); 693 return(-1); 694 } 695 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) { 696 siz += res; 697 } 698 close(fd); 699 #if !defined(_WIN32) 700 if (siz != info.st_size) { 701 free(base); 702 return(-1); 703 } 704 #endif 705 base[siz] = 0; 706 *mem = base; 707 *size = siz; 708 return(0); 709 } 710 711 static int unloadMem(const char *mem) { 712 free((char *)mem); 713 return(0); 714 } 715 716 /************************************************************************ 717 * * 718 * Tests implementations * 719 * * 720 ************************************************************************/ 721 722 /************************************************************************ 723 * * 724 * Parse to SAX based tests * 725 * * 726 ************************************************************************/ 727 728 static FILE *SAXdebug = NULL; 729 730 /* 731 * empty SAX block 732 */ 733 static xmlSAXHandler emptySAXHandlerStruct = { 734 NULL, /* internalSubset */ 735 NULL, /* isStandalone */ 736 NULL, /* hasInternalSubset */ 737 NULL, /* hasExternalSubset */ 738 NULL, /* resolveEntity */ 739 NULL, /* getEntity */ 740 NULL, /* entityDecl */ 741 NULL, /* notationDecl */ 742 NULL, /* attributeDecl */ 743 NULL, /* elementDecl */ 744 NULL, /* unparsedEntityDecl */ 745 NULL, /* setDocumentLocator */ 746 NULL, /* startDocument */ 747 NULL, /* endDocument */ 748 NULL, /* startElement */ 749 NULL, /* endElement */ 750 NULL, /* reference */ 751 NULL, /* characters */ 752 NULL, /* ignorableWhitespace */ 753 NULL, /* processingInstruction */ 754 NULL, /* comment */ 755 NULL, /* xmlParserWarning */ 756 NULL, /* xmlParserError */ 757 NULL, /* xmlParserError */ 758 NULL, /* getParameterEntity */ 759 NULL, /* cdataBlock; */ 760 NULL, /* externalSubset; */ 761 1, 762 NULL, 763 NULL, /* startElementNs */ 764 NULL, /* endElementNs */ 765 NULL /* xmlStructuredErrorFunc */ 766 }; 767 768 static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct; 769 static int callbacks = 0; 770 static int quiet = 0; 771 772 /** 773 * isStandaloneDebug: 774 * @ctxt: An XML parser context 775 * 776 * Is this document tagged standalone ? 777 * 778 * Returns 1 if true 779 */ 780 static int 781 isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED) 782 { 783 callbacks++; 784 if (quiet) 785 return(0); 786 fprintf(SAXdebug, "SAX.isStandalone()\n"); 787 return(0); 788 } 789 790 /** 791 * hasInternalSubsetDebug: 792 * @ctxt: An XML parser context 793 * 794 * Does this document has an internal subset 795 * 796 * Returns 1 if true 797 */ 798 static int 799 hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) 800 { 801 callbacks++; 802 if (quiet) 803 return(0); 804 fprintf(SAXdebug, "SAX.hasInternalSubset()\n"); 805 return(0); 806 } 807 808 /** 809 * hasExternalSubsetDebug: 810 * @ctxt: An XML parser context 811 * 812 * Does this document has an external subset 813 * 814 * Returns 1 if true 815 */ 816 static int 817 hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) 818 { 819 callbacks++; 820 if (quiet) 821 return(0); 822 fprintf(SAXdebug, "SAX.hasExternalSubset()\n"); 823 return(0); 824 } 825 826 /** 827 * internalSubsetDebug: 828 * @ctxt: An XML parser context 829 * 830 * Does this document has an internal subset 831 */ 832 static void 833 internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, 834 const xmlChar *ExternalID, const xmlChar *SystemID) 835 { 836 callbacks++; 837 if (quiet) 838 return; 839 fprintf(SAXdebug, "SAX.internalSubset(%s,", name); 840 if (ExternalID == NULL) 841 fprintf(SAXdebug, " ,"); 842 else 843 fprintf(SAXdebug, " %s,", ExternalID); 844 if (SystemID == NULL) 845 fprintf(SAXdebug, " )\n"); 846 else 847 fprintf(SAXdebug, " %s)\n", SystemID); 848 } 849 850 /** 851 * externalSubsetDebug: 852 * @ctxt: An XML parser context 853 * 854 * Does this document has an external subset 855 */ 856 static void 857 externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, 858 const xmlChar *ExternalID, const xmlChar *SystemID) 859 { 860 callbacks++; 861 if (quiet) 862 return; 863 fprintf(SAXdebug, "SAX.externalSubset(%s,", name); 864 if (ExternalID == NULL) 865 fprintf(SAXdebug, " ,"); 866 else 867 fprintf(SAXdebug, " %s,", ExternalID); 868 if (SystemID == NULL) 869 fprintf(SAXdebug, " )\n"); 870 else 871 fprintf(SAXdebug, " %s)\n", SystemID); 872 } 873 874 /** 875 * resolveEntityDebug: 876 * @ctxt: An XML parser context 877 * @publicId: The public ID of the entity 878 * @systemId: The system ID of the entity 879 * 880 * Special entity resolver, better left to the parser, it has 881 * more context than the application layer. 882 * The default behaviour is to NOT resolve the entities, in that case 883 * the ENTITY_REF nodes are built in the structure (and the parameter 884 * values). 885 * 886 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. 887 */ 888 static xmlParserInputPtr 889 resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId) 890 { 891 callbacks++; 892 if (quiet) 893 return(NULL); 894 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ 895 896 897 fprintf(SAXdebug, "SAX.resolveEntity("); 898 if (publicId != NULL) 899 fprintf(SAXdebug, "%s", (char *)publicId); 900 else 901 fprintf(SAXdebug, " "); 902 if (systemId != NULL) 903 fprintf(SAXdebug, ", %s)\n", (char *)systemId); 904 else 905 fprintf(SAXdebug, ", )\n"); 906 /********* 907 if (systemId != NULL) { 908 return(xmlNewInputFromFile(ctxt, (char *) systemId)); 909 } 910 *********/ 911 return(NULL); 912 } 913 914 /** 915 * getEntityDebug: 916 * @ctxt: An XML parser context 917 * @name: The entity name 918 * 919 * Get an entity by name 920 * 921 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. 922 */ 923 static xmlEntityPtr 924 getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) 925 { 926 callbacks++; 927 if (quiet) 928 return(NULL); 929 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name); 930 return(NULL); 931 } 932 933 /** 934 * getParameterEntityDebug: 935 * @ctxt: An XML parser context 936 * @name: The entity name 937 * 938 * Get a parameter entity by name 939 * 940 * Returns the xmlParserInputPtr 941 */ 942 static xmlEntityPtr 943 getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) 944 { 945 callbacks++; 946 if (quiet) 947 return(NULL); 948 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name); 949 return(NULL); 950 } 951 952 953 /** 954 * entityDeclDebug: 955 * @ctxt: An XML parser context 956 * @name: the entity name 957 * @type: the entity type 958 * @publicId: The public ID of the entity 959 * @systemId: The system ID of the entity 960 * @content: the entity value (without processing). 961 * 962 * An entity definition has been parsed 963 */ 964 static void 965 entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, 966 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) 967 { 968 const xmlChar *nullstr = BAD_CAST "(null)"; 969 /* not all libraries handle printing null pointers nicely */ 970 if (publicId == NULL) 971 publicId = nullstr; 972 if (systemId == NULL) 973 systemId = nullstr; 974 if (content == NULL) 975 content = (xmlChar *)nullstr; 976 callbacks++; 977 if (quiet) 978 return; 979 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n", 980 name, type, publicId, systemId, content); 981 } 982 983 /** 984 * attributeDeclDebug: 985 * @ctxt: An XML parser context 986 * @name: the attribute name 987 * @type: the attribute type 988 * 989 * An attribute definition has been parsed 990 */ 991 static void 992 attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem, 993 const xmlChar * name, int type, int def, 994 const xmlChar * defaultValue, xmlEnumerationPtr tree) 995 { 996 callbacks++; 997 if (quiet) 998 return; 999 if (defaultValue == NULL) 1000 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n", 1001 elem, name, type, def); 1002 else 1003 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n", 1004 elem, name, type, def, defaultValue); 1005 xmlFreeEnumeration(tree); 1006 } 1007 1008 /** 1009 * elementDeclDebug: 1010 * @ctxt: An XML parser context 1011 * @name: the element name 1012 * @type: the element type 1013 * @content: the element value (without processing). 1014 * 1015 * An element definition has been parsed 1016 */ 1017 static void 1018 elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, 1019 xmlElementContentPtr content ATTRIBUTE_UNUSED) 1020 { 1021 callbacks++; 1022 if (quiet) 1023 return; 1024 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n", 1025 name, type); 1026 } 1027 1028 /** 1029 * notationDeclDebug: 1030 * @ctxt: An XML parser context 1031 * @name: The name of the notation 1032 * @publicId: The public ID of the entity 1033 * @systemId: The system ID of the entity 1034 * 1035 * What to do when a notation declaration has been parsed. 1036 */ 1037 static void 1038 notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, 1039 const xmlChar *publicId, const xmlChar *systemId) 1040 { 1041 callbacks++; 1042 if (quiet) 1043 return; 1044 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n", 1045 (char *) name, (char *) publicId, (char *) systemId); 1046 } 1047 1048 /** 1049 * unparsedEntityDeclDebug: 1050 * @ctxt: An XML parser context 1051 * @name: The name of the entity 1052 * @publicId: The public ID of the entity 1053 * @systemId: The system ID of the entity 1054 * @notationName: the name of the notation 1055 * 1056 * What to do when an unparsed entity declaration is parsed 1057 */ 1058 static void 1059 unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, 1060 const xmlChar *publicId, const xmlChar *systemId, 1061 const xmlChar *notationName) 1062 { 1063 const xmlChar *nullstr = BAD_CAST "(null)"; 1064 1065 if (publicId == NULL) 1066 publicId = nullstr; 1067 if (systemId == NULL) 1068 systemId = nullstr; 1069 if (notationName == NULL) 1070 notationName = nullstr; 1071 callbacks++; 1072 if (quiet) 1073 return; 1074 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n", 1075 (char *) name, (char *) publicId, (char *) systemId, 1076 (char *) notationName); 1077 } 1078 1079 /** 1080 * setDocumentLocatorDebug: 1081 * @ctxt: An XML parser context 1082 * @loc: A SAX Locator 1083 * 1084 * Receive the document locator at startup, actually xmlDefaultSAXLocator 1085 * Everything is available on the context, so this is useless in our case. 1086 */ 1087 static void 1088 setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED) 1089 { 1090 callbacks++; 1091 if (quiet) 1092 return; 1093 fprintf(SAXdebug, "SAX.setDocumentLocator()\n"); 1094 } 1095 1096 /** 1097 * startDocumentDebug: 1098 * @ctxt: An XML parser context 1099 * 1100 * called when the document start being processed. 1101 */ 1102 static void 1103 startDocumentDebug(void *ctx ATTRIBUTE_UNUSED) 1104 { 1105 callbacks++; 1106 if (quiet) 1107 return; 1108 fprintf(SAXdebug, "SAX.startDocument()\n"); 1109 } 1110 1111 /** 1112 * endDocumentDebug: 1113 * @ctxt: An XML parser context 1114 * 1115 * called when the document end has been detected. 1116 */ 1117 static void 1118 endDocumentDebug(void *ctx ATTRIBUTE_UNUSED) 1119 { 1120 callbacks++; 1121 if (quiet) 1122 return; 1123 fprintf(SAXdebug, "SAX.endDocument()\n"); 1124 } 1125 1126 /** 1127 * startElementDebug: 1128 * @ctxt: An XML parser context 1129 * @name: The element name 1130 * 1131 * called when an opening tag has been processed. 1132 */ 1133 static void 1134 startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts) 1135 { 1136 int i; 1137 1138 callbacks++; 1139 if (quiet) 1140 return; 1141 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name); 1142 if (atts != NULL) { 1143 for (i = 0;(atts[i] != NULL);i++) { 1144 fprintf(SAXdebug, ", %s='", atts[i++]); 1145 if (atts[i] != NULL) 1146 fprintf(SAXdebug, "%s'", atts[i]); 1147 } 1148 } 1149 fprintf(SAXdebug, ")\n"); 1150 } 1151 1152 /** 1153 * endElementDebug: 1154 * @ctxt: An XML parser context 1155 * @name: The element name 1156 * 1157 * called when the end of an element has been detected. 1158 */ 1159 static void 1160 endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) 1161 { 1162 callbacks++; 1163 if (quiet) 1164 return; 1165 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name); 1166 } 1167 1168 /** 1169 * charactersDebug: 1170 * @ctxt: An XML parser context 1171 * @ch: a xmlChar string 1172 * @len: the number of xmlChar 1173 * 1174 * receiving some chars from the parser. 1175 * Question: how much at a time ??? 1176 */ 1177 static void 1178 charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) 1179 { 1180 char output[40]; 1181 int i; 1182 1183 callbacks++; 1184 if (quiet) 1185 return; 1186 for (i = 0;(i<len) && (i < 30);i++) 1187 output[i] = ch[i]; 1188 output[i] = 0; 1189 1190 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len); 1191 } 1192 1193 /** 1194 * referenceDebug: 1195 * @ctxt: An XML parser context 1196 * @name: The entity name 1197 * 1198 * called when an entity reference is detected. 1199 */ 1200 static void 1201 referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) 1202 { 1203 callbacks++; 1204 if (quiet) 1205 return; 1206 fprintf(SAXdebug, "SAX.reference(%s)\n", name); 1207 } 1208 1209 /** 1210 * ignorableWhitespaceDebug: 1211 * @ctxt: An XML parser context 1212 * @ch: a xmlChar string 1213 * @start: the first char in the string 1214 * @len: the number of xmlChar 1215 * 1216 * receiving some ignorable whitespaces from the parser. 1217 * Question: how much at a time ??? 1218 */ 1219 static void 1220 ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) 1221 { 1222 char output[40]; 1223 int i; 1224 1225 callbacks++; 1226 if (quiet) 1227 return; 1228 for (i = 0;(i<len) && (i < 30);i++) 1229 output[i] = ch[i]; 1230 output[i] = 0; 1231 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len); 1232 } 1233 1234 /** 1235 * processingInstructionDebug: 1236 * @ctxt: An XML parser context 1237 * @target: the target name 1238 * @data: the PI data's 1239 * @len: the number of xmlChar 1240 * 1241 * A processing instruction has been parsed. 1242 */ 1243 static void 1244 processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target, 1245 const xmlChar *data) 1246 { 1247 callbacks++; 1248 if (quiet) 1249 return; 1250 if (data != NULL) 1251 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n", 1252 (char *) target, (char *) data); 1253 else 1254 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n", 1255 (char *) target); 1256 } 1257 1258 /** 1259 * cdataBlockDebug: 1260 * @ctx: the user data (XML parser context) 1261 * @value: The pcdata content 1262 * @len: the block length 1263 * 1264 * called when a pcdata block has been parsed 1265 */ 1266 static void 1267 cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len) 1268 { 1269 callbacks++; 1270 if (quiet) 1271 return; 1272 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n", 1273 (char *) value, len); 1274 } 1275 1276 /** 1277 * commentDebug: 1278 * @ctxt: An XML parser context 1279 * @value: the comment content 1280 * 1281 * A comment has been parsed. 1282 */ 1283 static void 1284 commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value) 1285 { 1286 callbacks++; 1287 if (quiet) 1288 return; 1289 fprintf(SAXdebug, "SAX.comment(%s)\n", value); 1290 } 1291 1292 /** 1293 * warningDebug: 1294 * @ctxt: An XML parser context 1295 * @msg: the message to display/transmit 1296 * @...: extra parameters for the message display 1297 * 1298 * Display and format a warning messages, gives file, line, position and 1299 * extra parameters. 1300 */ 1301 static void XMLCDECL 1302 warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) 1303 { 1304 va_list args; 1305 1306 callbacks++; 1307 if (quiet) 1308 return; 1309 va_start(args, msg); 1310 fprintf(SAXdebug, "SAX.warning: "); 1311 vfprintf(SAXdebug, msg, args); 1312 va_end(args); 1313 } 1314 1315 /** 1316 * errorDebug: 1317 * @ctxt: An XML parser context 1318 * @msg: the message to display/transmit 1319 * @...: extra parameters for the message display 1320 * 1321 * Display and format a error messages, gives file, line, position and 1322 * extra parameters. 1323 */ 1324 static void XMLCDECL 1325 errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) 1326 { 1327 va_list args; 1328 1329 callbacks++; 1330 if (quiet) 1331 return; 1332 va_start(args, msg); 1333 fprintf(SAXdebug, "SAX.error: "); 1334 vfprintf(SAXdebug, msg, args); 1335 va_end(args); 1336 } 1337 1338 /** 1339 * fatalErrorDebug: 1340 * @ctxt: An XML parser context 1341 * @msg: the message to display/transmit 1342 * @...: extra parameters for the message display 1343 * 1344 * Display and format a fatalError messages, gives file, line, position and 1345 * extra parameters. 1346 */ 1347 static void XMLCDECL 1348 fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) 1349 { 1350 va_list args; 1351 1352 callbacks++; 1353 if (quiet) 1354 return; 1355 va_start(args, msg); 1356 fprintf(SAXdebug, "SAX.fatalError: "); 1357 vfprintf(SAXdebug, msg, args); 1358 va_end(args); 1359 } 1360 1361 static xmlSAXHandler debugSAXHandlerStruct = { 1362 internalSubsetDebug, 1363 isStandaloneDebug, 1364 hasInternalSubsetDebug, 1365 hasExternalSubsetDebug, 1366 resolveEntityDebug, 1367 getEntityDebug, 1368 entityDeclDebug, 1369 notationDeclDebug, 1370 attributeDeclDebug, 1371 elementDeclDebug, 1372 unparsedEntityDeclDebug, 1373 setDocumentLocatorDebug, 1374 startDocumentDebug, 1375 endDocumentDebug, 1376 startElementDebug, 1377 endElementDebug, 1378 referenceDebug, 1379 charactersDebug, 1380 ignorableWhitespaceDebug, 1381 processingInstructionDebug, 1382 commentDebug, 1383 warningDebug, 1384 errorDebug, 1385 fatalErrorDebug, 1386 getParameterEntityDebug, 1387 cdataBlockDebug, 1388 externalSubsetDebug, 1389 1, 1390 NULL, 1391 NULL, 1392 NULL, 1393 NULL 1394 }; 1395 1396 static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct; 1397 1398 /* 1399 * SAX2 specific callbacks 1400 */ 1401 /** 1402 * startElementNsDebug: 1403 * @ctxt: An XML parser context 1404 * @name: The element name 1405 * 1406 * called when an opening tag has been processed. 1407 */ 1408 static void 1409 startElementNsDebug(void *ctx ATTRIBUTE_UNUSED, 1410 const xmlChar *localname, 1411 const xmlChar *prefix, 1412 const xmlChar *URI, 1413 int nb_namespaces, 1414 const xmlChar **namespaces, 1415 int nb_attributes, 1416 int nb_defaulted, 1417 const xmlChar **attributes) 1418 { 1419 int i; 1420 1421 callbacks++; 1422 if (quiet) 1423 return; 1424 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname); 1425 if (prefix == NULL) 1426 fprintf(SAXdebug, ", NULL"); 1427 else 1428 fprintf(SAXdebug, ", %s", (char *) prefix); 1429 if (URI == NULL) 1430 fprintf(SAXdebug, ", NULL"); 1431 else 1432 fprintf(SAXdebug, ", '%s'", (char *) URI); 1433 fprintf(SAXdebug, ", %d", nb_namespaces); 1434 1435 if (namespaces != NULL) { 1436 for (i = 0;i < nb_namespaces * 2;i++) { 1437 fprintf(SAXdebug, ", xmlns"); 1438 if (namespaces[i] != NULL) 1439 fprintf(SAXdebug, ":%s", namespaces[i]); 1440 i++; 1441 fprintf(SAXdebug, "='%s'", namespaces[i]); 1442 } 1443 } 1444 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted); 1445 if (attributes != NULL) { 1446 for (i = 0;i < nb_attributes * 5;i += 5) { 1447 if (attributes[i + 1] != NULL) 1448 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]); 1449 else 1450 fprintf(SAXdebug, ", %s='", attributes[i]); 1451 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3], 1452 (int)(attributes[i + 4] - attributes[i + 3])); 1453 } 1454 } 1455 fprintf(SAXdebug, ")\n"); 1456 } 1457 1458 /** 1459 * endElementDebug: 1460 * @ctxt: An XML parser context 1461 * @name: The element name 1462 * 1463 * called when the end of an element has been detected. 1464 */ 1465 static void 1466 endElementNsDebug(void *ctx ATTRIBUTE_UNUSED, 1467 const xmlChar *localname, 1468 const xmlChar *prefix, 1469 const xmlChar *URI) 1470 { 1471 callbacks++; 1472 if (quiet) 1473 return; 1474 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname); 1475 if (prefix == NULL) 1476 fprintf(SAXdebug, ", NULL"); 1477 else 1478 fprintf(SAXdebug, ", %s", (char *) prefix); 1479 if (URI == NULL) 1480 fprintf(SAXdebug, ", NULL)\n"); 1481 else 1482 fprintf(SAXdebug, ", '%s')\n", (char *) URI); 1483 } 1484 1485 static xmlSAXHandler debugSAX2HandlerStruct = { 1486 internalSubsetDebug, 1487 isStandaloneDebug, 1488 hasInternalSubsetDebug, 1489 hasExternalSubsetDebug, 1490 resolveEntityDebug, 1491 getEntityDebug, 1492 entityDeclDebug, 1493 notationDeclDebug, 1494 attributeDeclDebug, 1495 elementDeclDebug, 1496 unparsedEntityDeclDebug, 1497 setDocumentLocatorDebug, 1498 startDocumentDebug, 1499 endDocumentDebug, 1500 NULL, 1501 NULL, 1502 referenceDebug, 1503 charactersDebug, 1504 ignorableWhitespaceDebug, 1505 processingInstructionDebug, 1506 commentDebug, 1507 warningDebug, 1508 errorDebug, 1509 fatalErrorDebug, 1510 getParameterEntityDebug, 1511 cdataBlockDebug, 1512 externalSubsetDebug, 1513 XML_SAX2_MAGIC, 1514 NULL, 1515 startElementNsDebug, 1516 endElementNsDebug, 1517 NULL 1518 }; 1519 1520 static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct; 1521 1522 #ifdef LIBXML_HTML_ENABLED 1523 /** 1524 * htmlstartElementDebug: 1525 * @ctxt: An XML parser context 1526 * @name: The element name 1527 * 1528 * called when an opening tag has been processed. 1529 */ 1530 static void 1531 htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts) 1532 { 1533 int i; 1534 1535 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name); 1536 if (atts != NULL) { 1537 for (i = 0;(atts[i] != NULL);i++) { 1538 fprintf(SAXdebug, ", %s", atts[i++]); 1539 if (atts[i] != NULL) { 1540 unsigned char output[40]; 1541 const unsigned char *att = atts[i]; 1542 int outlen, attlen; 1543 fprintf(SAXdebug, "='"); 1544 while ((attlen = strlen((char*)att)) > 0) { 1545 outlen = sizeof output - 1; 1546 htmlEncodeEntities(output, &outlen, att, &attlen, '\''); 1547 output[outlen] = 0; 1548 fprintf(SAXdebug, "%s", (char *) output); 1549 att += attlen; 1550 } 1551 fprintf(SAXdebug, "'"); 1552 } 1553 } 1554 } 1555 fprintf(SAXdebug, ")\n"); 1556 } 1557 1558 /** 1559 * htmlcharactersDebug: 1560 * @ctxt: An XML parser context 1561 * @ch: a xmlChar string 1562 * @len: the number of xmlChar 1563 * 1564 * receiving some chars from the parser. 1565 * Question: how much at a time ??? 1566 */ 1567 static void 1568 htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) 1569 { 1570 unsigned char output[40]; 1571 int inlen = len, outlen = 30; 1572 1573 htmlEncodeEntities(output, &outlen, ch, &inlen, 0); 1574 output[outlen] = 0; 1575 1576 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len); 1577 } 1578 1579 /** 1580 * htmlcdataDebug: 1581 * @ctxt: An XML parser context 1582 * @ch: a xmlChar string 1583 * @len: the number of xmlChar 1584 * 1585 * receiving some cdata chars from the parser. 1586 * Question: how much at a time ??? 1587 */ 1588 static void 1589 htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) 1590 { 1591 unsigned char output[40]; 1592 int inlen = len, outlen = 30; 1593 1594 htmlEncodeEntities(output, &outlen, ch, &inlen, 0); 1595 output[outlen] = 0; 1596 1597 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len); 1598 } 1599 1600 static xmlSAXHandler debugHTMLSAXHandlerStruct = { 1601 internalSubsetDebug, 1602 isStandaloneDebug, 1603 hasInternalSubsetDebug, 1604 hasExternalSubsetDebug, 1605 resolveEntityDebug, 1606 getEntityDebug, 1607 entityDeclDebug, 1608 notationDeclDebug, 1609 attributeDeclDebug, 1610 elementDeclDebug, 1611 unparsedEntityDeclDebug, 1612 setDocumentLocatorDebug, 1613 startDocumentDebug, 1614 endDocumentDebug, 1615 htmlstartElementDebug, 1616 endElementDebug, 1617 referenceDebug, 1618 htmlcharactersDebug, 1619 ignorableWhitespaceDebug, 1620 processingInstructionDebug, 1621 commentDebug, 1622 warningDebug, 1623 errorDebug, 1624 fatalErrorDebug, 1625 getParameterEntityDebug, 1626 htmlcdataDebug, 1627 externalSubsetDebug, 1628 1, 1629 NULL, 1630 NULL, 1631 NULL, 1632 NULL 1633 }; 1634 1635 static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct; 1636 #endif /* LIBXML_HTML_ENABLED */ 1637 1638 #ifdef LIBXML_SAX1_ENABLED 1639 /** 1640 * saxParseTest: 1641 * @filename: the file to parse 1642 * @result: the file with expected result 1643 * @err: the file with error messages 1644 * 1645 * Parse a file using the SAX API and check for errors. 1646 * 1647 * Returns 0 in case of success, an error code otherwise 1648 */ 1649 static int 1650 saxParseTest(const char *filename, const char *result, 1651 const char *err ATTRIBUTE_UNUSED, 1652 int options) { 1653 int ret; 1654 char *temp; 1655 1656 nb_tests++; 1657 temp = resultFilename(filename, "", ".res"); 1658 if (temp == NULL) { 1659 fprintf(stderr, "out of memory\n"); 1660 fatalError(); 1661 } 1662 SAXdebug = fopen(temp, "wb"); 1663 if (SAXdebug == NULL) { 1664 fprintf(stderr, "Failed to write to %s\n", temp); 1665 free(temp); 1666 return(-1); 1667 } 1668 1669 /* for SAX we really want the callbacks though the context handlers */ 1670 xmlSetStructuredErrorFunc(NULL, NULL); 1671 xmlSetGenericErrorFunc(NULL, testErrorHandler); 1672 1673 #ifdef LIBXML_HTML_ENABLED 1674 if (options & XML_PARSE_HTML) { 1675 htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL); 1676 ret = 0; 1677 } else 1678 #endif 1679 ret = xmlSAXUserParseFile(emptySAXHandler, NULL, filename); 1680 if (ret == XML_WAR_UNDECLARED_ENTITY) { 1681 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret); 1682 ret = 0; 1683 } 1684 if (ret != 0) { 1685 fprintf(stderr, "Failed to parse %s\n", filename); 1686 return(1); 1687 } 1688 #ifdef LIBXML_HTML_ENABLED 1689 if (options & XML_PARSE_HTML) { 1690 htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL); 1691 ret = 0; 1692 } else 1693 #endif 1694 if (options & XML_PARSE_SAX1) { 1695 ret = xmlSAXUserParseFile(debugSAXHandler, NULL, filename); 1696 } else { 1697 ret = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename); 1698 } 1699 if (ret == XML_WAR_UNDECLARED_ENTITY) { 1700 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret); 1701 ret = 0; 1702 } 1703 fclose(SAXdebug); 1704 if (compareFiles(temp, result)) { 1705 fprintf(stderr, "Got a difference for %s\n", filename); 1706 ret = 1; 1707 } 1708 if (temp != NULL) { 1709 unlink(temp); 1710 free(temp); 1711 } 1712 1713 /* switch back to structured error handling */ 1714 xmlSetGenericErrorFunc(NULL, NULL); 1715 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler); 1716 1717 return(ret); 1718 } 1719 #endif 1720 1721 /************************************************************************ 1722 * * 1723 * Parse to tree based tests * 1724 * * 1725 ************************************************************************/ 1726 /** 1727 * oldParseTest: 1728 * @filename: the file to parse 1729 * @result: the file with expected result 1730 * @err: the file with error messages: unused 1731 * 1732 * Parse a file using the old xmlParseFile API, then serialize back 1733 * reparse the result and serialize again, then check for deviation 1734 * in serialization. 1735 * 1736 * Returns 0 in case of success, an error code otherwise 1737 */ 1738 static int 1739 oldParseTest(const char *filename, const char *result, 1740 const char *err ATTRIBUTE_UNUSED, 1741 int options ATTRIBUTE_UNUSED) { 1742 xmlDocPtr doc; 1743 char *temp; 1744 int res = 0; 1745 1746 nb_tests++; 1747 /* 1748 * base of the test, parse with the old API 1749 */ 1750 #ifdef LIBXML_SAX1_ENABLED 1751 doc = xmlParseFile(filename); 1752 #else 1753 doc = xmlReadFile(filename, NULL, 0); 1754 #endif 1755 if (doc == NULL) 1756 return(1); 1757 temp = resultFilename(filename, "", ".res"); 1758 if (temp == NULL) { 1759 fprintf(stderr, "out of memory\n"); 1760 fatalError(); 1761 } 1762 xmlSaveFile(temp, doc); 1763 if (compareFiles(temp, result)) { 1764 res = 1; 1765 } 1766 xmlFreeDoc(doc); 1767 1768 /* 1769 * Parse the saved result to make sure the round trip is okay 1770 */ 1771 #ifdef LIBXML_SAX1_ENABLED 1772 doc = xmlParseFile(temp); 1773 #else 1774 doc = xmlReadFile(temp, NULL, 0); 1775 #endif 1776 if (doc == NULL) 1777 return(1); 1778 xmlSaveFile(temp, doc); 1779 if (compareFiles(temp, result)) { 1780 res = 1; 1781 } 1782 xmlFreeDoc(doc); 1783 1784 if (temp != NULL) { 1785 unlink(temp); 1786 free(temp); 1787 } 1788 return(res); 1789 } 1790 1791 #ifdef LIBXML_PUSH_ENABLED 1792 /** 1793 * pushParseTest: 1794 * @filename: the file to parse 1795 * @result: the file with expected result 1796 * @err: the file with error messages: unused 1797 * 1798 * Parse a file using the Push API, then serialize back 1799 * to check for content. 1800 * 1801 * Returns 0 in case of success, an error code otherwise 1802 */ 1803 static int 1804 pushParseTest(const char *filename, const char *result, 1805 const char *err ATTRIBUTE_UNUSED, 1806 int options) { 1807 xmlParserCtxtPtr ctxt; 1808 xmlDocPtr doc; 1809 const char *base; 1810 int size, res; 1811 int cur = 0; 1812 1813 nb_tests++; 1814 /* 1815 * load the document in memory and work from there. 1816 */ 1817 if (loadMem(filename, &base, &size) != 0) { 1818 fprintf(stderr, "Failed to load %s\n", filename); 1819 return(-1); 1820 } 1821 1822 #ifdef LIBXML_HTML_ENABLED 1823 if (options & XML_PARSE_HTML) 1824 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename, 1825 XML_CHAR_ENCODING_NONE); 1826 else 1827 #endif 1828 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename); 1829 xmlCtxtUseOptions(ctxt, options); 1830 cur += 4; 1831 while (cur < size) { 1832 if (cur + 1024 >= size) { 1833 #ifdef LIBXML_HTML_ENABLED 1834 if (options & XML_PARSE_HTML) 1835 htmlParseChunk(ctxt, base + cur, size - cur, 1); 1836 else 1837 #endif 1838 xmlParseChunk(ctxt, base + cur, size - cur, 1); 1839 break; 1840 } else { 1841 #ifdef LIBXML_HTML_ENABLED 1842 if (options & XML_PARSE_HTML) 1843 htmlParseChunk(ctxt, base + cur, 1024, 0); 1844 else 1845 #endif 1846 xmlParseChunk(ctxt, base + cur, 1024, 0); 1847 cur += 1024; 1848 } 1849 } 1850 doc = ctxt->myDoc; 1851 #ifdef LIBXML_HTML_ENABLED 1852 if (options & XML_PARSE_HTML) 1853 res = 1; 1854 else 1855 #endif 1856 res = ctxt->wellFormed; 1857 xmlFreeParserCtxt(ctxt); 1858 free((char *)base); 1859 if (!res) { 1860 xmlFreeDoc(doc); 1861 fprintf(stderr, "Failed to parse %s\n", filename); 1862 return(-1); 1863 } 1864 #ifdef LIBXML_HTML_ENABLED 1865 if (options & XML_PARSE_HTML) 1866 htmlDocDumpMemory(doc, (xmlChar **) &base, &size); 1867 else 1868 #endif 1869 xmlDocDumpMemory(doc, (xmlChar **) &base, &size); 1870 xmlFreeDoc(doc); 1871 res = compareFileMem(result, base, size); 1872 if ((base == NULL) || (res != 0)) { 1873 if (base != NULL) 1874 xmlFree((char *)base); 1875 fprintf(stderr, "Result for %s failed\n", filename); 1876 return(-1); 1877 } 1878 xmlFree((char *)base); 1879 if (err != NULL) { 1880 res = compareFileMem(err, testErrors, testErrorsSize); 1881 if (res != 0) { 1882 fprintf(stderr, "Error for %s failed\n", filename); 1883 return(-1); 1884 } 1885 } 1886 return(0); 1887 } 1888 #endif 1889 1890 /** 1891 * memParseTest: 1892 * @filename: the file to parse 1893 * @result: the file with expected result 1894 * @err: the file with error messages: unused 1895 * 1896 * Parse a file using the old xmlReadMemory API, then serialize back 1897 * reparse the result and serialize again, then check for deviation 1898 * in serialization. 1899 * 1900 * Returns 0 in case of success, an error code otherwise 1901 */ 1902 static int 1903 memParseTest(const char *filename, const char *result, 1904 const char *err ATTRIBUTE_UNUSED, 1905 int options ATTRIBUTE_UNUSED) { 1906 xmlDocPtr doc; 1907 const char *base; 1908 int size, res; 1909 1910 nb_tests++; 1911 /* 1912 * load and parse the memory 1913 */ 1914 if (loadMem(filename, &base, &size) != 0) { 1915 fprintf(stderr, "Failed to load %s\n", filename); 1916 return(-1); 1917 } 1918 1919 doc = xmlReadMemory(base, size, filename, NULL, 0); 1920 unloadMem(base); 1921 if (doc == NULL) { 1922 return(1); 1923 } 1924 xmlDocDumpMemory(doc, (xmlChar **) &base, &size); 1925 xmlFreeDoc(doc); 1926 res = compareFileMem(result, base, size); 1927 if ((base == NULL) || (res != 0)) { 1928 if (base != NULL) 1929 xmlFree((char *)base); 1930 fprintf(stderr, "Result for %s failed\n", filename); 1931 return(-1); 1932 } 1933 xmlFree((char *)base); 1934 return(0); 1935 } 1936 1937 /** 1938 * noentParseTest: 1939 * @filename: the file to parse 1940 * @result: the file with expected result 1941 * @err: the file with error messages: unused 1942 * 1943 * Parse a file with entity resolution, then serialize back 1944 * reparse the result and serialize again, then check for deviation 1945 * in serialization. 1946 * 1947 * Returns 0 in case of success, an error code otherwise 1948 */ 1949 static int 1950 noentParseTest(const char *filename, const char *result, 1951 const char *err ATTRIBUTE_UNUSED, 1952 int options) { 1953 xmlDocPtr doc; 1954 char *temp; 1955 int res = 0; 1956 1957 nb_tests++; 1958 /* 1959 * base of the test, parse with the old API 1960 */ 1961 doc = xmlReadFile(filename, NULL, options); 1962 if (doc == NULL) 1963 return(1); 1964 temp = resultFilename(filename, "", ".res"); 1965 if (temp == NULL) { 1966 fprintf(stderr, "Out of memory\n"); 1967 fatalError(); 1968 } 1969 xmlSaveFile(temp, doc); 1970 if (compareFiles(temp, result)) { 1971 res = 1; 1972 } 1973 xmlFreeDoc(doc); 1974 1975 /* 1976 * Parse the saved result to make sure the round trip is okay 1977 */ 1978 doc = xmlReadFile(filename, NULL, options); 1979 if (doc == NULL) 1980 return(1); 1981 xmlSaveFile(temp, doc); 1982 if (compareFiles(temp, result)) { 1983 res = 1; 1984 } 1985 xmlFreeDoc(doc); 1986 1987 if (temp != NULL) { 1988 unlink(temp); 1989 free(temp); 1990 } 1991 return(res); 1992 } 1993 1994 /** 1995 * errParseTest: 1996 * @filename: the file to parse 1997 * @result: the file with expected result 1998 * @err: the file with error messages 1999 * 2000 * Parse a file using the xmlReadFile API and check for errors. 2001 * 2002 * Returns 0 in case of success, an error code otherwise 2003 */ 2004 static int 2005 errParseTest(const char *filename, const char *result, const char *err, 2006 int options) { 2007 xmlDocPtr doc; 2008 const char *base = NULL; 2009 int size, res = 0; 2010 2011 nb_tests++; 2012 #ifdef LIBXML_HTML_ENABLED 2013 if (options & XML_PARSE_HTML) { 2014 doc = htmlReadFile(filename, NULL, options); 2015 } else 2016 #endif 2017 #ifdef LIBXML_XINCLUDE_ENABLED 2018 if (options & XML_PARSE_XINCLUDE) { 2019 doc = xmlReadFile(filename, NULL, options); 2020 xmlXIncludeProcessFlags(doc, options); 2021 } else 2022 #endif 2023 { 2024 xmlGetWarningsDefaultValue = 1; 2025 doc = xmlReadFile(filename, NULL, options); 2026 } 2027 xmlGetWarningsDefaultValue = 0; 2028 if (result) { 2029 if (doc == NULL) { 2030 base = ""; 2031 size = 0; 2032 } else { 2033 #ifdef LIBXML_HTML_ENABLED 2034 if (options & XML_PARSE_HTML) { 2035 htmlDocDumpMemory(doc, (xmlChar **) &base, &size); 2036 } else 2037 #endif 2038 xmlDocDumpMemory(doc, (xmlChar **) &base, &size); 2039 } 2040 res = compareFileMem(result, base, size); 2041 } 2042 if (doc != NULL) { 2043 if (base != NULL) 2044 xmlFree((char *)base); 2045 xmlFreeDoc(doc); 2046 } 2047 if (res != 0) { 2048 fprintf(stderr, "Result for %s failed\n", filename); 2049 return(-1); 2050 } 2051 if (err != NULL) { 2052 res = compareFileMem(err, testErrors, testErrorsSize); 2053 if (res != 0) { 2054 fprintf(stderr, "Error for %s failed\n", filename); 2055 return(-1); 2056 } 2057 } else if (options & XML_PARSE_DTDVALID) { 2058 if (testErrorsSize != 0) 2059 fprintf(stderr, "Validation for %s failed\n", filename); 2060 } 2061 2062 return(0); 2063 } 2064 2065 #ifdef LIBXML_READER_ENABLED 2066 /************************************************************************ 2067 * * 2068 * Reader based tests * 2069 * * 2070 ************************************************************************/ 2071 2072 static void processNode(FILE *out, xmlTextReaderPtr reader) { 2073 const xmlChar *name, *value; 2074 int type, empty; 2075 2076 type = xmlTextReaderNodeType(reader); 2077 empty = xmlTextReaderIsEmptyElement(reader); 2078 2079 name = xmlTextReaderConstName(reader); 2080 if (name == NULL) 2081 name = BAD_CAST "--"; 2082 2083 value = xmlTextReaderConstValue(reader); 2084 2085 2086 fprintf(out, "%d %d %s %d %d", 2087 xmlTextReaderDepth(reader), 2088 type, 2089 name, 2090 empty, 2091 xmlTextReaderHasValue(reader)); 2092 if (value == NULL) 2093 fprintf(out, "\n"); 2094 else { 2095 fprintf(out, " %s\n", value); 2096 } 2097 } 2098 static int 2099 streamProcessTest(const char *filename, const char *result, const char *err, 2100 xmlTextReaderPtr reader, const char *rng) { 2101 int ret; 2102 char *temp = NULL; 2103 FILE *t = NULL; 2104 2105 if (reader == NULL) 2106 return(-1); 2107 2108 nb_tests++; 2109 if (result != NULL) { 2110 temp = resultFilename(filename, "", ".res"); 2111 if (temp == NULL) { 2112 fprintf(stderr, "Out of memory\n"); 2113 fatalError(); 2114 } 2115 t = fopen(temp, "wb"); 2116 if (t == NULL) { 2117 fprintf(stderr, "Can't open temp file %s\n", temp); 2118 free(temp); 2119 return(-1); 2120 } 2121 } 2122 #ifdef LIBXML_SCHEMAS_ENABLED 2123 if (rng != NULL) { 2124 ret = xmlTextReaderRelaxNGValidate(reader, rng); 2125 if (ret < 0) { 2126 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n", 2127 rng); 2128 fclose(t); 2129 if (temp != NULL) { 2130 unlink(temp); 2131 free(temp); 2132 } 2133 return(0); 2134 } 2135 } 2136 #endif 2137 xmlGetWarningsDefaultValue = 1; 2138 ret = xmlTextReaderRead(reader); 2139 while (ret == 1) { 2140 if ((t != NULL) && (rng == NULL)) 2141 processNode(t, reader); 2142 ret = xmlTextReaderRead(reader); 2143 } 2144 if (ret != 0) { 2145 testErrorHandler(NULL, "%s : failed to parse\n", filename); 2146 } 2147 if (rng != NULL) { 2148 if (xmlTextReaderIsValid(reader) != 1) { 2149 testErrorHandler(NULL, "%s fails to validate\n", filename); 2150 } else { 2151 testErrorHandler(NULL, "%s validates\n", filename); 2152 } 2153 } 2154 xmlGetWarningsDefaultValue = 0; 2155 if (t != NULL) { 2156 fclose(t); 2157 ret = compareFiles(temp, result); 2158 if (temp != NULL) { 2159 unlink(temp); 2160 free(temp); 2161 } 2162 if (ret) { 2163 fprintf(stderr, "Result for %s failed\n", filename); 2164 return(-1); 2165 } 2166 } 2167 if (err != NULL) { 2168 ret = compareFileMem(err, testErrors, testErrorsSize); 2169 if (ret != 0) { 2170 fprintf(stderr, "Error for %s failed\n", filename); 2171 printf("%s", testErrors); 2172 return(-1); 2173 } 2174 } 2175 2176 return(0); 2177 } 2178 2179 /** 2180 * streamParseTest: 2181 * @filename: the file to parse 2182 * @result: the file with expected result 2183 * @err: the file with error messages 2184 * 2185 * Parse a file using the reader API and check for errors. 2186 * 2187 * Returns 0 in case of success, an error code otherwise 2188 */ 2189 static int 2190 streamParseTest(const char *filename, const char *result, const char *err, 2191 int options) { 2192 xmlTextReaderPtr reader; 2193 int ret; 2194 2195 reader = xmlReaderForFile(filename, NULL, options); 2196 ret = streamProcessTest(filename, result, err, reader, NULL); 2197 xmlFreeTextReader(reader); 2198 return(ret); 2199 } 2200 2201 /** 2202 * walkerParseTest: 2203 * @filename: the file to parse 2204 * @result: the file with expected result 2205 * @err: the file with error messages 2206 * 2207 * Parse a file using the walker, i.e. a reader built from a atree. 2208 * 2209 * Returns 0 in case of success, an error code otherwise 2210 */ 2211 static int 2212 walkerParseTest(const char *filename, const char *result, const char *err, 2213 int options) { 2214 xmlDocPtr doc; 2215 xmlTextReaderPtr reader; 2216 int ret; 2217 2218 doc = xmlReadFile(filename, NULL, options); 2219 if (doc == NULL) { 2220 fprintf(stderr, "Failed to parse %s\n", filename); 2221 return(-1); 2222 } 2223 reader = xmlReaderWalker(doc); 2224 ret = streamProcessTest(filename, result, err, reader, NULL); 2225 xmlFreeTextReader(reader); 2226 xmlFreeDoc(doc); 2227 return(ret); 2228 } 2229 2230 /** 2231 * streamMemParseTest: 2232 * @filename: the file to parse 2233 * @result: the file with expected result 2234 * @err: the file with error messages 2235 * 2236 * Parse a file using the reader API from memory and check for errors. 2237 * 2238 * Returns 0 in case of success, an error code otherwise 2239 */ 2240 static int 2241 streamMemParseTest(const char *filename, const char *result, const char *err, 2242 int options) { 2243 xmlTextReaderPtr reader; 2244 int ret; 2245 const char *base; 2246 int size; 2247 2248 /* 2249 * load and parse the memory 2250 */ 2251 if (loadMem(filename, &base, &size) != 0) { 2252 fprintf(stderr, "Failed to load %s\n", filename); 2253 return(-1); 2254 } 2255 reader = xmlReaderForMemory(base, size, filename, NULL, options); 2256 ret = streamProcessTest(filename, result, err, reader, NULL); 2257 free((char *)base); 2258 xmlFreeTextReader(reader); 2259 return(ret); 2260 } 2261 #endif 2262 2263 #ifdef LIBXML_XPATH_ENABLED 2264 #ifdef LIBXML_DEBUG_ENABLED 2265 /************************************************************************ 2266 * * 2267 * XPath and XPointer based tests * 2268 * * 2269 ************************************************************************/ 2270 2271 static FILE *xpathOutput; 2272 static xmlDocPtr xpathDocument; 2273 2274 static void 2275 testXPath(const char *str, int xptr, int expr) { 2276 xmlXPathObjectPtr res; 2277 xmlXPathContextPtr ctxt; 2278 2279 nb_tests++; 2280 #if defined(LIBXML_XPTR_ENABLED) 2281 if (xptr) { 2282 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL); 2283 res = xmlXPtrEval(BAD_CAST str, ctxt); 2284 } else { 2285 #endif 2286 ctxt = xmlXPathNewContext(xpathDocument); 2287 ctxt->node = xmlDocGetRootElement(xpathDocument); 2288 if (expr) 2289 res = xmlXPathEvalExpression(BAD_CAST str, ctxt); 2290 else { 2291 /* res = xmlXPathEval(BAD_CAST str, ctxt); */ 2292 xmlXPathCompExprPtr comp; 2293 2294 comp = xmlXPathCompile(BAD_CAST str); 2295 if (comp != NULL) { 2296 res = xmlXPathCompiledEval(comp, ctxt); 2297 xmlXPathFreeCompExpr(comp); 2298 } else 2299 res = NULL; 2300 } 2301 #if defined(LIBXML_XPTR_ENABLED) 2302 } 2303 #endif 2304 xmlXPathDebugDumpObject(xpathOutput, res, 0); 2305 xmlXPathFreeObject(res); 2306 xmlXPathFreeContext(ctxt); 2307 } 2308 2309 /** 2310 * xpathExprTest: 2311 * @filename: the file to parse 2312 * @result: the file with expected result 2313 * @err: the file with error messages 2314 * 2315 * Parse a file containing XPath standalone expressions and evaluate them 2316 * 2317 * Returns 0 in case of success, an error code otherwise 2318 */ 2319 static int 2320 xpathCommonTest(const char *filename, const char *result, 2321 int xptr, int expr) { 2322 FILE *input; 2323 char expression[5000]; 2324 int len, ret = 0; 2325 char *temp; 2326 2327 temp = resultFilename(filename, "", ".res"); 2328 if (temp == NULL) { 2329 fprintf(stderr, "Out of memory\n"); 2330 fatalError(); 2331 } 2332 xpathOutput = fopen(temp, "wb"); 2333 if (xpathOutput == NULL) { 2334 fprintf(stderr, "failed to open output file %s\n", temp); 2335 free(temp); 2336 return(-1); 2337 } 2338 2339 input = fopen(filename, "rb"); 2340 if (input == NULL) { 2341 xmlGenericError(xmlGenericErrorContext, 2342 "Cannot open %s for reading\n", filename); 2343 free(temp); 2344 return(-1); 2345 } 2346 while (fgets(expression, 4500, input) != NULL) { 2347 len = strlen(expression); 2348 len--; 2349 while ((len >= 0) && 2350 ((expression[len] == '\n') || (expression[len] == '\t') || 2351 (expression[len] == '\r') || (expression[len] == ' '))) len--; 2352 expression[len + 1] = 0; 2353 if (len >= 0) { 2354 fprintf(xpathOutput, 2355 "\n========================\nExpression: %s\n", 2356 expression) ; 2357 testXPath(expression, xptr, expr); 2358 } 2359 } 2360 2361 fclose(input); 2362 fclose(xpathOutput); 2363 if (result != NULL) { 2364 ret = compareFiles(temp, result); 2365 if (ret) { 2366 fprintf(stderr, "Result for %s failed\n", filename); 2367 } 2368 } 2369 2370 if (temp != NULL) { 2371 unlink(temp); 2372 free(temp); 2373 } 2374 return(ret); 2375 } 2376 2377 /** 2378 * xpathExprTest: 2379 * @filename: the file to parse 2380 * @result: the file with expected result 2381 * @err: the file with error messages 2382 * 2383 * Parse a file containing XPath standalone expressions and evaluate them 2384 * 2385 * Returns 0 in case of success, an error code otherwise 2386 */ 2387 static int 2388 xpathExprTest(const char *filename, const char *result, 2389 const char *err ATTRIBUTE_UNUSED, 2390 int options ATTRIBUTE_UNUSED) { 2391 return(xpathCommonTest(filename, result, 0, 1)); 2392 } 2393 2394 /** 2395 * xpathDocTest: 2396 * @filename: the file to parse 2397 * @result: the file with expected result 2398 * @err: the file with error messages 2399 * 2400 * Parse a file containing XPath expressions and evaluate them against 2401 * a set of corresponding documents. 2402 * 2403 * Returns 0 in case of success, an error code otherwise 2404 */ 2405 static int 2406 xpathDocTest(const char *filename, 2407 const char *resul ATTRIBUTE_UNUSED, 2408 const char *err ATTRIBUTE_UNUSED, 2409 int options) { 2410 2411 char pattern[500]; 2412 char result[500]; 2413 glob_t globbuf; 2414 size_t i; 2415 int ret = 0, res; 2416 2417 xpathDocument = xmlReadFile(filename, NULL, 2418 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); 2419 if (xpathDocument == NULL) { 2420 fprintf(stderr, "Failed to load %s\n", filename); 2421 return(-1); 2422 } 2423 2424 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename)); 2425 pattern[499] = 0; 2426 globbuf.gl_offs = 0; 2427 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 2428 for (i = 0;i < globbuf.gl_pathc;i++) { 2429 snprintf(result, 499, "result/XPath/tests/%s", 2430 baseFilename(globbuf.gl_pathv[i])); 2431 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0); 2432 if (res != 0) 2433 ret = res; 2434 } 2435 globfree(&globbuf); 2436 2437 xmlFreeDoc(xpathDocument); 2438 return(ret); 2439 } 2440 2441 #ifdef LIBXML_XPTR_ENABLED 2442 /** 2443 * xptrDocTest: 2444 * @filename: the file to parse 2445 * @result: the file with expected result 2446 * @err: the file with error messages 2447 * 2448 * Parse a file containing XPath expressions and evaluate them against 2449 * a set of corresponding documents. 2450 * 2451 * Returns 0 in case of success, an error code otherwise 2452 */ 2453 static int 2454 xptrDocTest(const char *filename, 2455 const char *resul ATTRIBUTE_UNUSED, 2456 const char *err ATTRIBUTE_UNUSED, 2457 int options) { 2458 2459 char pattern[500]; 2460 char result[500]; 2461 glob_t globbuf; 2462 size_t i; 2463 int ret = 0, res; 2464 2465 xpathDocument = xmlReadFile(filename, NULL, 2466 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); 2467 if (xpathDocument == NULL) { 2468 fprintf(stderr, "Failed to load %s\n", filename); 2469 return(-1); 2470 } 2471 2472 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename)); 2473 pattern[499] = 0; 2474 globbuf.gl_offs = 0; 2475 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 2476 for (i = 0;i < globbuf.gl_pathc;i++) { 2477 snprintf(result, 499, "result/XPath/xptr/%s", 2478 baseFilename(globbuf.gl_pathv[i])); 2479 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0); 2480 if (res != 0) 2481 ret = res; 2482 } 2483 globfree(&globbuf); 2484 2485 xmlFreeDoc(xpathDocument); 2486 return(ret); 2487 } 2488 #endif /* LIBXML_XPTR_ENABLED */ 2489 2490 /** 2491 * xmlidDocTest: 2492 * @filename: the file to parse 2493 * @result: the file with expected result 2494 * @err: the file with error messages 2495 * 2496 * Parse a file containing xml:id and check for errors and verify 2497 * that XPath queries will work on them as expected. 2498 * 2499 * Returns 0 in case of success, an error code otherwise 2500 */ 2501 static int 2502 xmlidDocTest(const char *filename, 2503 const char *result, 2504 const char *err, 2505 int options) { 2506 2507 int res = 0; 2508 int ret = 0; 2509 char *temp; 2510 2511 xpathDocument = xmlReadFile(filename, NULL, 2512 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); 2513 if (xpathDocument == NULL) { 2514 fprintf(stderr, "Failed to load %s\n", filename); 2515 return(-1); 2516 } 2517 2518 temp = resultFilename(filename, "", ".res"); 2519 if (temp == NULL) { 2520 fprintf(stderr, "Out of memory\n"); 2521 fatalError(); 2522 } 2523 xpathOutput = fopen(temp, "wb"); 2524 if (xpathOutput == NULL) { 2525 fprintf(stderr, "failed to open output file %s\n", temp); 2526 xmlFreeDoc(xpathDocument); 2527 free(temp); 2528 return(-1); 2529 } 2530 2531 testXPath("id('bar')", 0, 0); 2532 2533 fclose(xpathOutput); 2534 if (result != NULL) { 2535 ret = compareFiles(temp, result); 2536 if (ret) { 2537 fprintf(stderr, "Result for %s failed\n", filename); 2538 res = 1; 2539 } 2540 } 2541 2542 if (temp != NULL) { 2543 unlink(temp); 2544 free(temp); 2545 } 2546 xmlFreeDoc(xpathDocument); 2547 2548 if (err != NULL) { 2549 ret = compareFileMem(err, testErrors, testErrorsSize); 2550 if (ret != 0) { 2551 fprintf(stderr, "Error for %s failed\n", filename); 2552 res = 1; 2553 } 2554 } 2555 return(res); 2556 } 2557 2558 #endif /* LIBXML_DEBUG_ENABLED */ 2559 #endif /* XPATH */ 2560 /************************************************************************ 2561 * * 2562 * URI based tests * 2563 * * 2564 ************************************************************************/ 2565 2566 static void 2567 handleURI(const char *str, const char *base, FILE *o) { 2568 int ret; 2569 xmlURIPtr uri; 2570 xmlChar *res = NULL; 2571 2572 uri = xmlCreateURI(); 2573 2574 if (base == NULL) { 2575 ret = xmlParseURIReference(uri, str); 2576 if (ret != 0) 2577 fprintf(o, "%s : error %d\n", str, ret); 2578 else { 2579 xmlNormalizeURIPath(uri->path); 2580 xmlPrintURI(o, uri); 2581 fprintf(o, "\n"); 2582 } 2583 } else { 2584 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base); 2585 if (res != NULL) { 2586 fprintf(o, "%s\n", (char *) res); 2587 } 2588 else 2589 fprintf(o, "::ERROR::\n"); 2590 } 2591 if (res != NULL) 2592 xmlFree(res); 2593 xmlFreeURI(uri); 2594 } 2595 2596 /** 2597 * uriCommonTest: 2598 * @filename: the file to parse 2599 * @result: the file with expected result 2600 * @err: the file with error messages 2601 * 2602 * Parse a file containing URI and check for errors 2603 * 2604 * Returns 0 in case of success, an error code otherwise 2605 */ 2606 static int 2607 uriCommonTest(const char *filename, 2608 const char *result, 2609 const char *err, 2610 const char *base) { 2611 char *temp; 2612 FILE *o, *f; 2613 char str[1024]; 2614 int res = 0, i, ret; 2615 2616 temp = resultFilename(filename, "", ".res"); 2617 if (temp == NULL) { 2618 fprintf(stderr, "Out of memory\n"); 2619 fatalError(); 2620 } 2621 o = fopen(temp, "wb"); 2622 if (o == NULL) { 2623 fprintf(stderr, "failed to open output file %s\n", temp); 2624 free(temp); 2625 return(-1); 2626 } 2627 f = fopen(filename, "rb"); 2628 if (f == NULL) { 2629 fprintf(stderr, "failed to open input file %s\n", filename); 2630 fclose(o); 2631 if (temp != NULL) { 2632 unlink(temp); 2633 free(temp); 2634 } 2635 return(-1); 2636 } 2637 2638 while (1) { 2639 /* 2640 * read one line in string buffer. 2641 */ 2642 if (fgets (&str[0], sizeof (str) - 1, f) == NULL) 2643 break; 2644 2645 /* 2646 * remove the ending spaces 2647 */ 2648 i = strlen(str); 2649 while ((i > 0) && 2650 ((str[i - 1] == '\n') || (str[i - 1] == '\r') || 2651 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { 2652 i--; 2653 str[i] = 0; 2654 } 2655 nb_tests++; 2656 handleURI(str, base, o); 2657 } 2658 2659 fclose(f); 2660 fclose(o); 2661 2662 if (result != NULL) { 2663 ret = compareFiles(temp, result); 2664 if (ret) { 2665 fprintf(stderr, "Result for %s failed\n", filename); 2666 res = 1; 2667 } 2668 } 2669 if (err != NULL) { 2670 ret = compareFileMem(err, testErrors, testErrorsSize); 2671 if (ret != 0) { 2672 fprintf(stderr, "Error for %s failed\n", filename); 2673 res = 1; 2674 } 2675 } 2676 2677 if (temp != NULL) { 2678 unlink(temp); 2679 free(temp); 2680 } 2681 return(res); 2682 } 2683 2684 /** 2685 * uriParseTest: 2686 * @filename: the file to parse 2687 * @result: the file with expected result 2688 * @err: the file with error messages 2689 * 2690 * Parse a file containing URI and check for errors 2691 * 2692 * Returns 0 in case of success, an error code otherwise 2693 */ 2694 static int 2695 uriParseTest(const char *filename, 2696 const char *result, 2697 const char *err, 2698 int options ATTRIBUTE_UNUSED) { 2699 return(uriCommonTest(filename, result, err, NULL)); 2700 } 2701 2702 /** 2703 * uriBaseTest: 2704 * @filename: the file to parse 2705 * @result: the file with expected result 2706 * @err: the file with error messages 2707 * 2708 * Parse a file containing URI, compose them against a fixed base and 2709 * check for errors 2710 * 2711 * Returns 0 in case of success, an error code otherwise 2712 */ 2713 static int 2714 uriBaseTest(const char *filename, 2715 const char *result, 2716 const char *err, 2717 int options ATTRIBUTE_UNUSED) { 2718 return(uriCommonTest(filename, result, err, 2719 "http://foo.com/path/to/index.html?orig#help")); 2720 } 2721 2722 static int urip_success = 1; 2723 static int urip_current = 0; 2724 static const char *urip_testURLs[] = { 2725 "urip://example.com/a b.html", 2726 "urip://example.com/a%20b.html", 2727 "file:///path/to/a b.html", 2728 "file:///path/to/a%20b.html", 2729 "/path/to/a b.html", 2730 "/path/to/a%20b.html", 2731 "urip://example.com/rsum.html", 2732 "urip://example.com/test?a=1&b=2%263&c=4#foo", 2733 NULL 2734 }; 2735 static const char *urip_rcvsURLs[] = { 2736 /* it is an URI the strings must be escaped */ 2737 "urip://example.com/a%20b.html", 2738 /* check that % escaping is not broken */ 2739 "urip://example.com/a%20b.html", 2740 /* it's an URI path the strings must be escaped */ 2741 "file:///path/to/a%20b.html", 2742 /* check that % escaping is not broken */ 2743 "file:///path/to/a%20b.html", 2744 /* this is not an URI, this is a path, so this should not be escaped */ 2745 "/path/to/a b.html", 2746 /* check that paths with % are not broken */ 2747 "/path/to/a%20b.html", 2748 /* out of context the encoding can't be guessed byte by byte conversion */ 2749 "urip://example.com/r%E9sum%E9.html", 2750 /* verify we don't destroy URIs especially the query part */ 2751 "urip://example.com/test?a=1&b=2%263&c=4#foo", 2752 NULL 2753 }; 2754 static const char *urip_res = "<list/>"; 2755 static const char *urip_cur = NULL; 2756 static int urip_rlen; 2757 2758 /** 2759 * uripMatch: 2760 * @URI: an URI to test 2761 * 2762 * Check for an urip: query 2763 * 2764 * Returns 1 if yes and 0 if another Input module should be used 2765 */ 2766 static int 2767 uripMatch(const char * URI) { 2768 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog"))) 2769 return(0); 2770 /* Verify we received the escaped URL */ 2771 if (strcmp(urip_rcvsURLs[urip_current], URI)) 2772 urip_success = 0; 2773 return(1); 2774 } 2775 2776 /** 2777 * uripOpen: 2778 * @URI: an URI to test 2779 * 2780 * Return a pointer to the urip: query handler, in this example simply 2781 * the urip_current pointer... 2782 * 2783 * Returns an Input context or NULL in case or error 2784 */ 2785 static void * 2786 uripOpen(const char * URI) { 2787 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog"))) 2788 return(NULL); 2789 /* Verify we received the escaped URL */ 2790 if (strcmp(urip_rcvsURLs[urip_current], URI)) 2791 urip_success = 0; 2792 urip_cur = urip_res; 2793 urip_rlen = strlen(urip_res); 2794 return((void *) urip_cur); 2795 } 2796 2797 /** 2798 * uripClose: 2799 * @context: the read context 2800 * 2801 * Close the urip: query handler 2802 * 2803 * Returns 0 or -1 in case of error 2804 */ 2805 static int 2806 uripClose(void * context) { 2807 if (context == NULL) return(-1); 2808 urip_cur = NULL; 2809 urip_rlen = 0; 2810 return(0); 2811 } 2812 2813 /** 2814 * uripRead: 2815 * @context: the read context 2816 * @buffer: where to store data 2817 * @len: number of bytes to read 2818 * 2819 * Implement an urip: query read. 2820 * 2821 * Returns the number of bytes read or -1 in case of error 2822 */ 2823 static int 2824 uripRead(void * context, char * buffer, int len) { 2825 const char *ptr = (const char *) context; 2826 2827 if ((context == NULL) || (buffer == NULL) || (len < 0)) 2828 return(-1); 2829 2830 if (len > urip_rlen) len = urip_rlen; 2831 memcpy(buffer, ptr, len); 2832 urip_rlen -= len; 2833 return(len); 2834 } 2835 2836 static int 2837 urip_checkURL(const char *URL) { 2838 xmlDocPtr doc; 2839 2840 doc = xmlReadFile(URL, NULL, 0); 2841 if (doc == NULL) 2842 return(-1); 2843 xmlFreeDoc(doc); 2844 return(1); 2845 } 2846 2847 /** 2848 * uriPathTest: 2849 * @filename: ignored 2850 * @result: ignored 2851 * @err: ignored 2852 * 2853 * Run a set of tests to check how Path and URI are handled before 2854 * being passed to the I/O layer 2855 * 2856 * Returns 0 in case of success, an error code otherwise 2857 */ 2858 static int 2859 uriPathTest(const char *filename ATTRIBUTE_UNUSED, 2860 const char *result ATTRIBUTE_UNUSED, 2861 const char *err ATTRIBUTE_UNUSED, 2862 int options ATTRIBUTE_UNUSED) { 2863 int parsed; 2864 int failures = 0; 2865 2866 /* 2867 * register the new I/O handlers 2868 */ 2869 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0) 2870 { 2871 fprintf(stderr, "failed to register HTTP handler\n"); 2872 return(-1); 2873 } 2874 2875 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) { 2876 urip_success = 1; 2877 parsed = urip_checkURL(urip_testURLs[urip_current]); 2878 if (urip_success != 1) { 2879 fprintf(stderr, "failed the URL passing test for %s", 2880 urip_testURLs[urip_current]); 2881 failures++; 2882 } else if (parsed != 1) { 2883 fprintf(stderr, "failed the parsing test for %s", 2884 urip_testURLs[urip_current]); 2885 failures++; 2886 } 2887 nb_tests++; 2888 } 2889 2890 xmlPopInputCallbacks(); 2891 return(failures); 2892 } 2893 2894 #ifdef LIBXML_SCHEMAS_ENABLED 2895 /************************************************************************ 2896 * * 2897 * Schemas tests * 2898 * * 2899 ************************************************************************/ 2900 static int 2901 schemasOneTest(const char *sch, 2902 const char *filename, 2903 const char *result, 2904 const char *err, 2905 int options, 2906 xmlSchemaPtr schemas) { 2907 xmlDocPtr doc; 2908 xmlSchemaValidCtxtPtr ctxt; 2909 int ret = 0; 2910 int validResult = 0; 2911 char *temp; 2912 FILE *schemasOutput; 2913 2914 doc = xmlReadFile(filename, NULL, options); 2915 if (doc == NULL) { 2916 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); 2917 return(-1); 2918 } 2919 2920 temp = resultFilename(result, "", ".res"); 2921 if (temp == NULL) { 2922 fprintf(stderr, "Out of memory\n"); 2923 fatalError(); 2924 } 2925 schemasOutput = fopen(temp, "wb"); 2926 if (schemasOutput == NULL) { 2927 fprintf(stderr, "failed to open output file %s\n", temp); 2928 xmlFreeDoc(doc); 2929 free(temp); 2930 return(-1); 2931 } 2932 2933 ctxt = xmlSchemaNewValidCtxt(schemas); 2934 xmlSchemaSetValidErrors(ctxt, 2935 (xmlSchemaValidityErrorFunc) testErrorHandler, 2936 (xmlSchemaValidityWarningFunc) testErrorHandler, 2937 ctxt); 2938 validResult = xmlSchemaValidateDoc(ctxt, doc); 2939 if (validResult == 0) { 2940 fprintf(schemasOutput, "%s validates\n", filename); 2941 } else if (validResult > 0) { 2942 fprintf(schemasOutput, "%s fails to validate\n", filename); 2943 } else { 2944 fprintf(schemasOutput, "%s validation generated an internal error\n", 2945 filename); 2946 } 2947 fclose(schemasOutput); 2948 if (result) { 2949 if (compareFiles(temp, result)) { 2950 fprintf(stderr, "Result for %s on %s failed\n", filename, sch); 2951 ret = 1; 2952 } 2953 } 2954 if (temp != NULL) { 2955 unlink(temp); 2956 free(temp); 2957 } 2958 2959 if ((validResult != 0) && (err != NULL)) { 2960 if (compareFileMem(err, testErrors, testErrorsSize)) { 2961 fprintf(stderr, "Error for %s on %s failed\n", filename, sch); 2962 ret = 1; 2963 } 2964 } 2965 2966 xmlSchemaFreeValidCtxt(ctxt); 2967 xmlFreeDoc(doc); 2968 return(ret); 2969 } 2970 /** 2971 * schemasTest: 2972 * @filename: the schemas file 2973 * @result: the file with expected result 2974 * @err: the file with error messages 2975 * 2976 * Parse a file containing URI, compose them against a fixed base and 2977 * check for errors 2978 * 2979 * Returns 0 in case of success, an error code otherwise 2980 */ 2981 static int 2982 schemasTest(const char *filename, 2983 const char *resul ATTRIBUTE_UNUSED, 2984 const char *errr ATTRIBUTE_UNUSED, 2985 int options) { 2986 const char *base = baseFilename(filename); 2987 const char *base2; 2988 const char *instance; 2989 xmlSchemaParserCtxtPtr ctxt; 2990 xmlSchemaPtr schemas; 2991 int res = 0, len, ret; 2992 char pattern[500]; 2993 char prefix[500]; 2994 char result[500]; 2995 char err[500]; 2996 glob_t globbuf; 2997 size_t i; 2998 char count = 0; 2999 3000 /* first compile the schemas if possible */ 3001 ctxt = xmlSchemaNewParserCtxt(filename); 3002 xmlSchemaSetParserErrors(ctxt, 3003 (xmlSchemaValidityErrorFunc) testErrorHandler, 3004 (xmlSchemaValidityWarningFunc) testErrorHandler, 3005 ctxt); 3006 schemas = xmlSchemaParse(ctxt); 3007 xmlSchemaFreeParserCtxt(ctxt); 3008 3009 /* 3010 * most of the mess is about the output filenames generated by the Makefile 3011 */ 3012 len = strlen(base); 3013 if ((len > 499) || (len < 5)) { 3014 xmlSchemaFree(schemas); 3015 return(-1); 3016 } 3017 len -= 4; /* remove trailing .xsd */ 3018 if (base[len - 2] == '_') { 3019 len -= 2; /* remove subtest number */ 3020 } 3021 if (base[len - 2] == '_') { 3022 len -= 2; /* remove subtest number */ 3023 } 3024 memcpy(prefix, base, len); 3025 prefix[len] = 0; 3026 3027 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix); 3028 pattern[499] = 0; 3029 3030 if (base[len] == '_') { 3031 len += 2; 3032 memcpy(prefix, base, len); 3033 prefix[len] = 0; 3034 } 3035 3036 globbuf.gl_offs = 0; 3037 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 3038 for (i = 0;i < globbuf.gl_pathc;i++) { 3039 testErrorsSize = 0; 3040 testErrors[0] = 0; 3041 instance = globbuf.gl_pathv[i]; 3042 base2 = baseFilename(instance); 3043 len = strlen(base2); 3044 if ((len > 6) && (base2[len - 6] == '_')) { 3045 count = base2[len - 5]; 3046 snprintf(result, 499, "result/schemas/%s_%c", 3047 prefix, count); 3048 result[499] = 0; 3049 snprintf(err, 499, "result/schemas/%s_%c.err", 3050 prefix, count); 3051 err[499] = 0; 3052 } else { 3053 fprintf(stderr, "don't know how to process %s\n", instance); 3054 continue; 3055 } 3056 if (schemas == NULL) { 3057 } else { 3058 nb_tests++; 3059 ret = schemasOneTest(filename, instance, result, err, 3060 options, schemas); 3061 if (ret != 0) 3062 res = ret; 3063 } 3064 } 3065 globfree(&globbuf); 3066 xmlSchemaFree(schemas); 3067 3068 return(res); 3069 } 3070 3071 /************************************************************************ 3072 * * 3073 * Schemas tests * 3074 * * 3075 ************************************************************************/ 3076 static int 3077 rngOneTest(const char *sch, 3078 const char *filename, 3079 const char *result, 3080 const char *err, 3081 int options, 3082 xmlRelaxNGPtr schemas) { 3083 xmlDocPtr doc; 3084 xmlRelaxNGValidCtxtPtr ctxt; 3085 int ret = 0; 3086 char *temp; 3087 FILE *schemasOutput; 3088 3089 doc = xmlReadFile(filename, NULL, options); 3090 if (doc == NULL) { 3091 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); 3092 return(-1); 3093 } 3094 3095 temp = resultFilename(result, "", ".res"); 3096 if (temp == NULL) { 3097 fprintf(stderr, "Out of memory\n"); 3098 fatalError(); 3099 } 3100 schemasOutput = fopen(temp, "wb"); 3101 if (schemasOutput == NULL) { 3102 fprintf(stderr, "failed to open output file %s\n", temp); 3103 xmlFreeDoc(doc); 3104 free(temp); 3105 return(-1); 3106 } 3107 3108 ctxt = xmlRelaxNGNewValidCtxt(schemas); 3109 xmlRelaxNGSetValidErrors(ctxt, 3110 (xmlRelaxNGValidityErrorFunc) testErrorHandler, 3111 (xmlRelaxNGValidityWarningFunc) testErrorHandler, 3112 ctxt); 3113 ret = xmlRelaxNGValidateDoc(ctxt, doc); 3114 if (ret == 0) { 3115 testErrorHandler(NULL, "%s validates\n", filename); 3116 } else if (ret > 0) { 3117 testErrorHandler(NULL, "%s fails to validate\n", filename); 3118 } else { 3119 testErrorHandler(NULL, "%s validation generated an internal error\n", 3120 filename); 3121 } 3122 fclose(schemasOutput); 3123 ret = 0; 3124 if (result) { 3125 if (compareFiles(temp, result)) { 3126 fprintf(stderr, "Result for %s on %s failed\n", filename, sch); 3127 ret = 1; 3128 } 3129 } 3130 if (temp != NULL) { 3131 unlink(temp); 3132 free(temp); 3133 } 3134 3135 if (err != NULL) { 3136 if (compareFileMem(err, testErrors, testErrorsSize)) { 3137 fprintf(stderr, "Error for %s on %s failed\n", filename, sch); 3138 ret = 1; 3139 printf("%s", testErrors); 3140 } 3141 } 3142 3143 3144 xmlRelaxNGFreeValidCtxt(ctxt); 3145 xmlFreeDoc(doc); 3146 return(ret); 3147 } 3148 /** 3149 * rngTest: 3150 * @filename: the schemas file 3151 * @result: the file with expected result 3152 * @err: the file with error messages 3153 * 3154 * Parse an RNG schemas and then apply it to the related .xml 3155 * 3156 * Returns 0 in case of success, an error code otherwise 3157 */ 3158 static int 3159 rngTest(const char *filename, 3160 const char *resul ATTRIBUTE_UNUSED, 3161 const char *errr ATTRIBUTE_UNUSED, 3162 int options) { 3163 const char *base = baseFilename(filename); 3164 const char *base2; 3165 const char *instance; 3166 xmlRelaxNGParserCtxtPtr ctxt; 3167 xmlRelaxNGPtr schemas; 3168 int res = 0, len, ret = 0; 3169 char pattern[500]; 3170 char prefix[500]; 3171 char result[500]; 3172 char err[500]; 3173 glob_t globbuf; 3174 size_t i; 3175 char count = 0; 3176 3177 /* first compile the schemas if possible */ 3178 ctxt = xmlRelaxNGNewParserCtxt(filename); 3179 xmlRelaxNGSetParserErrors(ctxt, 3180 (xmlRelaxNGValidityErrorFunc) testErrorHandler, 3181 (xmlRelaxNGValidityWarningFunc) testErrorHandler, 3182 ctxt); 3183 schemas = xmlRelaxNGParse(ctxt); 3184 xmlRelaxNGFreeParserCtxt(ctxt); 3185 3186 /* 3187 * most of the mess is about the output filenames generated by the Makefile 3188 */ 3189 len = strlen(base); 3190 if ((len > 499) || (len < 5)) { 3191 xmlRelaxNGFree(schemas); 3192 return(-1); 3193 } 3194 len -= 4; /* remove trailing .rng */ 3195 memcpy(prefix, base, len); 3196 prefix[len] = 0; 3197 3198 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); 3199 pattern[499] = 0; 3200 3201 globbuf.gl_offs = 0; 3202 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 3203 for (i = 0;i < globbuf.gl_pathc;i++) { 3204 testErrorsSize = 0; 3205 testErrors[0] = 0; 3206 instance = globbuf.gl_pathv[i]; 3207 base2 = baseFilename(instance); 3208 len = strlen(base2); 3209 if ((len > 6) && (base2[len - 6] == '_')) { 3210 count = base2[len - 5]; 3211 snprintf(result, 499, "result/relaxng/%s_%c", 3212 prefix, count); 3213 result[499] = 0; 3214 snprintf(err, 499, "result/relaxng/%s_%c.err", 3215 prefix, count); 3216 err[499] = 0; 3217 } else { 3218 fprintf(stderr, "don't know how to process %s\n", instance); 3219 continue; 3220 } 3221 if (schemas == NULL) { 3222 } else { 3223 nb_tests++; 3224 ret = rngOneTest(filename, instance, result, err, 3225 options, schemas); 3226 if (res != 0) 3227 ret = res; 3228 } 3229 } 3230 globfree(&globbuf); 3231 xmlRelaxNGFree(schemas); 3232 3233 return(ret); 3234 } 3235 3236 #ifdef LIBXML_READER_ENABLED 3237 /** 3238 * rngStreamTest: 3239 * @filename: the schemas file 3240 * @result: the file with expected result 3241 * @err: the file with error messages 3242 * 3243 * Parse a set of files with streaming, applying an RNG schemas 3244 * 3245 * Returns 0 in case of success, an error code otherwise 3246 */ 3247 static int 3248 rngStreamTest(const char *filename, 3249 const char *resul ATTRIBUTE_UNUSED, 3250 const char *errr ATTRIBUTE_UNUSED, 3251 int options) { 3252 const char *base = baseFilename(filename); 3253 const char *base2; 3254 const char *instance; 3255 int res = 0, len, ret; 3256 char pattern[500]; 3257 char prefix[500]; 3258 char result[500]; 3259 char err[500]; 3260 glob_t globbuf; 3261 size_t i; 3262 char count = 0; 3263 xmlTextReaderPtr reader; 3264 int disable_err = 0; 3265 3266 /* 3267 * most of the mess is about the output filenames generated by the Makefile 3268 */ 3269 len = strlen(base); 3270 if ((len > 499) || (len < 5)) { 3271 fprintf(stderr, "len(base) == %d !\n", len); 3272 return(-1); 3273 } 3274 len -= 4; /* remove trailing .rng */ 3275 memcpy(prefix, base, len); 3276 prefix[len] = 0; 3277 3278 /* 3279 * strictly unifying the error messages is nearly impossible this 3280 * hack is also done in the Makefile 3281 */ 3282 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) || 3283 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) || 3284 (!strcmp(prefix, "tutor8_2"))) 3285 disable_err = 1; 3286 3287 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); 3288 pattern[499] = 0; 3289 3290 globbuf.gl_offs = 0; 3291 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 3292 for (i = 0;i < globbuf.gl_pathc;i++) { 3293 testErrorsSize = 0; 3294 testErrors[0] = 0; 3295 instance = globbuf.gl_pathv[i]; 3296 base2 = baseFilename(instance); 3297 len = strlen(base2); 3298 if ((len > 6) && (base2[len - 6] == '_')) { 3299 count = base2[len - 5]; 3300 snprintf(result, 499, "result/relaxng/%s_%c", 3301 prefix, count); 3302 result[499] = 0; 3303 snprintf(err, 499, "result/relaxng/%s_%c.err", 3304 prefix, count); 3305 err[499] = 0; 3306 } else { 3307 fprintf(stderr, "don't know how to process %s\n", instance); 3308 continue; 3309 } 3310 reader = xmlReaderForFile(instance, NULL, options); 3311 if (reader == NULL) { 3312 fprintf(stderr, "Failed to build reder for %s\n", instance); 3313 } 3314 if (disable_err == 1) 3315 ret = streamProcessTest(instance, result, NULL, reader, filename); 3316 else 3317 ret = streamProcessTest(instance, result, err, reader, filename); 3318 xmlFreeTextReader(reader); 3319 if (ret != 0) { 3320 fprintf(stderr, "instance %s failed\n", instance); 3321 res = ret; 3322 } 3323 } 3324 globfree(&globbuf); 3325 3326 return(res); 3327 } 3328 #endif /* READER */ 3329 3330 #endif 3331 3332 #ifdef LIBXML_PATTERN_ENABLED 3333 #ifdef LIBXML_READER_ENABLED 3334 /************************************************************************ 3335 * * 3336 * Patterns tests * 3337 * * 3338 ************************************************************************/ 3339 static void patternNode(FILE *out, xmlTextReaderPtr reader, 3340 const char *pattern, xmlPatternPtr patternc, 3341 xmlStreamCtxtPtr patstream) { 3342 xmlChar *path = NULL; 3343 int match = -1; 3344 int type, empty; 3345 3346 type = xmlTextReaderNodeType(reader); 3347 empty = xmlTextReaderIsEmptyElement(reader); 3348 3349 if (type == XML_READER_TYPE_ELEMENT) { 3350 /* do the check only on element start */ 3351 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader)); 3352 3353 if (match) { 3354 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader)); 3355 fprintf(out, "Node %s matches pattern %s\n", path, pattern); 3356 } 3357 } 3358 if (patstream != NULL) { 3359 int ret; 3360 3361 if (type == XML_READER_TYPE_ELEMENT) { 3362 ret = xmlStreamPush(patstream, 3363 xmlTextReaderConstLocalName(reader), 3364 xmlTextReaderConstNamespaceUri(reader)); 3365 if (ret < 0) { 3366 fprintf(out, "xmlStreamPush() failure\n"); 3367 xmlFreeStreamCtxt(patstream); 3368 patstream = NULL; 3369 } else if (ret != match) { 3370 if (path == NULL) { 3371 path = xmlGetNodePath( 3372 xmlTextReaderCurrentNode(reader)); 3373 } 3374 fprintf(out, 3375 "xmlPatternMatch and xmlStreamPush disagree\n"); 3376 fprintf(out, 3377 " pattern %s node %s\n", 3378 pattern, path); 3379 } 3380 3381 3382 } 3383 if ((type == XML_READER_TYPE_END_ELEMENT) || 3384 ((type == XML_READER_TYPE_ELEMENT) && (empty))) { 3385 ret = xmlStreamPop(patstream); 3386 if (ret < 0) { 3387 fprintf(out, "xmlStreamPop() failure\n"); 3388 xmlFreeStreamCtxt(patstream); 3389 patstream = NULL; 3390 } 3391 } 3392 } 3393 if (path != NULL) 3394 xmlFree(path); 3395 } 3396 3397 /** 3398 * patternTest: 3399 * @filename: the schemas file 3400 * @result: the file with expected result 3401 * @err: the file with error messages 3402 * 3403 * Parse a set of files with streaming, applying an RNG schemas 3404 * 3405 * Returns 0 in case of success, an error code otherwise 3406 */ 3407 static int 3408 patternTest(const char *filename, 3409 const char *resul ATTRIBUTE_UNUSED, 3410 const char *err ATTRIBUTE_UNUSED, 3411 int options) { 3412 xmlPatternPtr patternc = NULL; 3413 xmlStreamCtxtPtr patstream = NULL; 3414 FILE *o, *f; 3415 char str[1024]; 3416 char xml[500]; 3417 char result[500]; 3418 int len, i; 3419 int ret = 0, res; 3420 char *temp; 3421 xmlTextReaderPtr reader; 3422 xmlDocPtr doc; 3423 3424 len = strlen(filename); 3425 len -= 4; 3426 memcpy(xml, filename, len); 3427 xml[len] = 0; 3428 snprintf(result, 499, "result/pattern/%s", baseFilename(xml)); 3429 result[499] = 0; 3430 memcpy(xml + len, ".xml", 5); 3431 3432 if (!checkTestFile(xml)) { 3433 fprintf(stderr, "Missing xml file %s\n", xml); 3434 return(-1); 3435 } 3436 if (!checkTestFile(result)) { 3437 fprintf(stderr, "Missing result file %s\n", result); 3438 return(-1); 3439 } 3440 f = fopen(filename, "rb"); 3441 if (f == NULL) { 3442 fprintf(stderr, "Failed to open %s\n", filename); 3443 return(-1); 3444 } 3445 temp = resultFilename(filename, "", ".res"); 3446 if (temp == NULL) { 3447 fprintf(stderr, "Out of memory\n"); 3448 fatalError(); 3449 } 3450 o = fopen(temp, "wb"); 3451 if (o == NULL) { 3452 fprintf(stderr, "failed to open output file %s\n", temp); 3453 fclose(f); 3454 free(temp); 3455 return(-1); 3456 } 3457 while (1) { 3458 /* 3459 * read one line in string buffer. 3460 */ 3461 if (fgets (&str[0], sizeof (str) - 1, f) == NULL) 3462 break; 3463 3464 /* 3465 * remove the ending spaces 3466 */ 3467 i = strlen(str); 3468 while ((i > 0) && 3469 ((str[i - 1] == '\n') || (str[i - 1] == '\r') || 3470 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { 3471 i--; 3472 str[i] = 0; 3473 } 3474 doc = xmlReadFile(xml, NULL, options); 3475 if (doc == NULL) { 3476 fprintf(stderr, "Failed to parse %s\n", xml); 3477 ret = 1; 3478 } else { 3479 xmlNodePtr root; 3480 const xmlChar *namespaces[22]; 3481 int j; 3482 xmlNsPtr ns; 3483 3484 root = xmlDocGetRootElement(doc); 3485 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) { 3486 namespaces[j++] = ns->href; 3487 namespaces[j++] = ns->prefix; 3488 } 3489 namespaces[j++] = NULL; 3490 namespaces[j] = NULL; 3491 3492 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict, 3493 0, &namespaces[0]); 3494 if (patternc == NULL) { 3495 testErrorHandler(NULL, 3496 "Pattern %s failed to compile\n", str); 3497 xmlFreeDoc(doc); 3498 ret = 1; 3499 continue; 3500 } 3501 patstream = xmlPatternGetStreamCtxt(patternc); 3502 if (patstream != NULL) { 3503 ret = xmlStreamPush(patstream, NULL, NULL); 3504 if (ret < 0) { 3505 fprintf(stderr, "xmlStreamPush() failure\n"); 3506 xmlFreeStreamCtxt(patstream); 3507 patstream = NULL; 3508 } 3509 } 3510 nb_tests++; 3511 3512 reader = xmlReaderWalker(doc); 3513 res = xmlTextReaderRead(reader); 3514 while (res == 1) { 3515 patternNode(o, reader, str, patternc, patstream); 3516 res = xmlTextReaderRead(reader); 3517 } 3518 if (res != 0) { 3519 fprintf(o, "%s : failed to parse\n", filename); 3520 } 3521 xmlFreeTextReader(reader); 3522 xmlFreeDoc(doc); 3523 xmlFreeStreamCtxt(patstream); 3524 patstream = NULL; 3525 xmlFreePattern(patternc); 3526 3527 } 3528 } 3529 3530 fclose(f); 3531 fclose(o); 3532 3533 ret = compareFiles(temp, result); 3534 if (ret) { 3535 fprintf(stderr, "Result for %s failed\n", filename); 3536 ret = 1; 3537 } 3538 if (temp != NULL) { 3539 unlink(temp); 3540 free(temp); 3541 } 3542 return(ret); 3543 } 3544 #endif /* READER */ 3545 #endif /* PATTERN */ 3546 #ifdef LIBXML_C14N_ENABLED 3547 /************************************************************************ 3548 * * 3549 * Canonicalization tests * 3550 * * 3551 ************************************************************************/ 3552 static xmlXPathObjectPtr 3553 load_xpath_expr (xmlDocPtr parent_doc, const char* filename) { 3554 xmlXPathObjectPtr xpath; 3555 xmlDocPtr doc; 3556 xmlChar *expr; 3557 xmlXPathContextPtr ctx; 3558 xmlNodePtr node; 3559 xmlNsPtr ns; 3560 3561 /* 3562 * load XPath expr as a file 3563 */ 3564 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; 3565 xmlSubstituteEntitiesDefault(1); 3566 3567 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT); 3568 if (doc == NULL) { 3569 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename); 3570 return(NULL); 3571 } 3572 3573 /* 3574 * Check the document is of the right kind 3575 */ 3576 if(xmlDocGetRootElement(doc) == NULL) { 3577 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename); 3578 xmlFreeDoc(doc); 3579 return(NULL); 3580 } 3581 3582 node = doc->children; 3583 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) { 3584 node = node->next; 3585 } 3586 3587 if(node == NULL) { 3588 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename); 3589 xmlFreeDoc(doc); 3590 return(NULL); 3591 } 3592 3593 expr = xmlNodeGetContent(node); 3594 if(expr == NULL) { 3595 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename); 3596 xmlFreeDoc(doc); 3597 return(NULL); 3598 } 3599 3600 ctx = xmlXPathNewContext(parent_doc); 3601 if(ctx == NULL) { 3602 fprintf(stderr,"Error: unable to create new context\n"); 3603 xmlFree(expr); 3604 xmlFreeDoc(doc); 3605 return(NULL); 3606 } 3607 3608 /* 3609 * Register namespaces 3610 */ 3611 ns = node->nsDef; 3612 while(ns != NULL) { 3613 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) { 3614 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href); 3615 xmlFree(expr); 3616 xmlXPathFreeContext(ctx); 3617 xmlFreeDoc(doc); 3618 return(NULL); 3619 } 3620 ns = ns->next; 3621 } 3622 3623 /* 3624 * Evaluate xpath 3625 */ 3626 xpath = xmlXPathEvalExpression(expr, ctx); 3627 if(xpath == NULL) { 3628 fprintf(stderr,"Error: unable to evaluate xpath expression\n"); 3629 xmlFree(expr); 3630 xmlXPathFreeContext(ctx); 3631 xmlFreeDoc(doc); 3632 return(NULL); 3633 } 3634 3635 /* print_xpath_nodes(xpath->nodesetval); */ 3636 3637 xmlFree(expr); 3638 xmlXPathFreeContext(ctx); 3639 xmlFreeDoc(doc); 3640 return(xpath); 3641 } 3642 3643 /* 3644 * Macro used to grow the current buffer. 3645 */ 3646 #define xxx_growBufferReentrant() { \ 3647 buffer_size *= 2; \ 3648 buffer = (xmlChar **) \ 3649 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \ 3650 if (buffer == NULL) { \ 3651 perror("realloc failed"); \ 3652 return(NULL); \ 3653 } \ 3654 } 3655 3656 static xmlChar ** 3657 parse_list(xmlChar *str) { 3658 xmlChar **buffer; 3659 xmlChar **out = NULL; 3660 int buffer_size = 0; 3661 int len; 3662 3663 if(str == NULL) { 3664 return(NULL); 3665 } 3666 3667 len = xmlStrlen(str); 3668 if((str[0] == '\'') && (str[len - 1] == '\'')) { 3669 str[len - 1] = '\0'; 3670 str++; 3671 } 3672 /* 3673 * allocate an translation buffer. 3674 */ 3675 buffer_size = 1000; 3676 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*)); 3677 if (buffer == NULL) { 3678 perror("malloc failed"); 3679 return(NULL); 3680 } 3681 out = buffer; 3682 3683 while(*str != '\0') { 3684 if (out - buffer > buffer_size - 10) { 3685 int indx = out - buffer; 3686 3687 xxx_growBufferReentrant(); 3688 out = &buffer[indx]; 3689 } 3690 (*out++) = str; 3691 while(*str != ',' && *str != '\0') ++str; 3692 if(*str == ',') *(str++) = '\0'; 3693 } 3694 (*out) = NULL; 3695 return buffer; 3696 } 3697 3698 static int 3699 c14nRunTest(const char* xml_filename, int with_comments, int mode, 3700 const char* xpath_filename, const char *ns_filename, 3701 const char* result_file) { 3702 xmlDocPtr doc; 3703 xmlXPathObjectPtr xpath = NULL; 3704 xmlChar *result = NULL; 3705 int ret; 3706 xmlChar **inclusive_namespaces = NULL; 3707 const char *nslist = NULL; 3708 int nssize; 3709 3710 3711 /* 3712 * build an XML tree from a the file; we need to add default 3713 * attributes and resolve all character and entities references 3714 */ 3715 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; 3716 xmlSubstituteEntitiesDefault(1); 3717 3718 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT); 3719 if (doc == NULL) { 3720 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename); 3721 return(-1); 3722 } 3723 3724 /* 3725 * Check the document is of the right kind 3726 */ 3727 if(xmlDocGetRootElement(doc) == NULL) { 3728 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename); 3729 xmlFreeDoc(doc); 3730 return(-1); 3731 } 3732 3733 /* 3734 * load xpath file if specified 3735 */ 3736 if(xpath_filename) { 3737 xpath = load_xpath_expr(doc, xpath_filename); 3738 if(xpath == NULL) { 3739 fprintf(stderr,"Error: unable to evaluate xpath expression\n"); 3740 xmlFreeDoc(doc); 3741 return(-1); 3742 } 3743 } 3744 3745 if (ns_filename != NULL) { 3746 if (loadMem(ns_filename, &nslist, &nssize)) { 3747 fprintf(stderr,"Error: unable to evaluate xpath expression\n"); 3748 if(xpath != NULL) xmlXPathFreeObject(xpath); 3749 xmlFreeDoc(doc); 3750 return(-1); 3751 } 3752 inclusive_namespaces = parse_list((xmlChar *) nslist); 3753 } 3754 3755 /* 3756 * Canonical form 3757 */ 3758 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */ 3759 ret = xmlC14NDocDumpMemory(doc, 3760 (xpath) ? xpath->nodesetval : NULL, 3761 mode, inclusive_namespaces, 3762 with_comments, &result); 3763 if (ret >= 0) { 3764 if(result != NULL) { 3765 if (compareFileMem(result_file, (const char *) result, ret)) { 3766 fprintf(stderr, "Result mismatch for %s\n", xml_filename); 3767 fprintf(stderr, "RESULT:\n%s\n", (const char*)result); 3768 ret = -1; 3769 } 3770 } 3771 } else { 3772 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret); 3773 ret = -1; 3774 } 3775 3776 /* 3777 * Cleanup 3778 */ 3779 if (result != NULL) xmlFree(result); 3780 if(xpath != NULL) xmlXPathFreeObject(xpath); 3781 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces); 3782 if (nslist != NULL) free((char *) nslist); 3783 xmlFreeDoc(doc); 3784 3785 return(ret); 3786 } 3787 3788 static int 3789 c14nCommonTest(const char *filename, int with_comments, int mode, 3790 const char *subdir) { 3791 char buf[500]; 3792 char prefix[500]; 3793 const char *base; 3794 int len; 3795 char *result = NULL; 3796 char *xpath = NULL; 3797 char *ns = NULL; 3798 int ret = 0; 3799 3800 base = baseFilename(filename); 3801 len = strlen(base); 3802 len -= 4; 3803 memcpy(prefix, base, len); 3804 prefix[len] = 0; 3805 3806 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix); 3807 if (!checkTestFile(buf)) { 3808 fprintf(stderr, "Missing result file %s", buf); 3809 return(-1); 3810 } 3811 result = strdup(buf); 3812 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix); 3813 if (checkTestFile(buf)) { 3814 xpath = strdup(buf); 3815 } 3816 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix); 3817 if (checkTestFile(buf)) { 3818 ns = strdup(buf); 3819 } 3820 3821 nb_tests++; 3822 if (c14nRunTest(filename, with_comments, mode, 3823 xpath, ns, result) < 0) 3824 ret = 1; 3825 3826 if (result != NULL) free(result); 3827 if (xpath != NULL) free(xpath); 3828 if (ns != NULL) free(ns); 3829 return(ret); 3830 } 3831 3832 static int 3833 c14nWithCommentTest(const char *filename, 3834 const char *resul ATTRIBUTE_UNUSED, 3835 const char *err ATTRIBUTE_UNUSED, 3836 int options ATTRIBUTE_UNUSED) { 3837 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments")); 3838 } 3839 static int 3840 c14nWithoutCommentTest(const char *filename, 3841 const char *resul ATTRIBUTE_UNUSED, 3842 const char *err ATTRIBUTE_UNUSED, 3843 int options ATTRIBUTE_UNUSED) { 3844 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments")); 3845 } 3846 static int 3847 c14nExcWithoutCommentTest(const char *filename, 3848 const char *resul ATTRIBUTE_UNUSED, 3849 const char *err ATTRIBUTE_UNUSED, 3850 int options ATTRIBUTE_UNUSED) { 3851 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments")); 3852 } 3853 static int 3854 c14n11WithoutCommentTest(const char *filename, 3855 const char *resul ATTRIBUTE_UNUSED, 3856 const char *err ATTRIBUTE_UNUSED, 3857 int options ATTRIBUTE_UNUSED) { 3858 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments")); 3859 } 3860 #endif 3861 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED) 3862 /************************************************************************ 3863 * * 3864 * Catalog and threads test * 3865 * * 3866 ************************************************************************/ 3867 3868 /* 3869 * mostly a cut and paste from testThreads.c 3870 */ 3871 #define MAX_ARGC 20 3872 3873 static const char *catalog = "test/threads/complex.xml"; 3874 static const char *testfiles[] = { 3875 "test/threads/abc.xml", 3876 "test/threads/acb.xml", 3877 "test/threads/bac.xml", 3878 "test/threads/bca.xml", 3879 "test/threads/cab.xml", 3880 "test/threads/cba.xml", 3881 "test/threads/invalid.xml", 3882 }; 3883 3884 static const char *Okay = "OK"; 3885 static const char *Failed = "Failed"; 3886 3887 #ifndef xmlDoValidityCheckingDefaultValue 3888 #error xmlDoValidityCheckingDefaultValue is not a macro 3889 #endif 3890 #ifndef xmlGenericErrorContext 3891 #error xmlGenericErrorContext is not a macro 3892 #endif 3893 3894 static void * 3895 thread_specific_data(void *private_data) 3896 { 3897 xmlDocPtr myDoc; 3898 const char *filename = (const char *) private_data; 3899 int okay = 1; 3900 3901 if (!strcmp(filename, "test/threads/invalid.xml")) { 3902 xmlDoValidityCheckingDefaultValue = 0; 3903 xmlGenericErrorContext = stdout; 3904 } else { 3905 xmlDoValidityCheckingDefaultValue = 1; 3906 xmlGenericErrorContext = stderr; 3907 } 3908 myDoc = xmlParseFile(filename); 3909 if (myDoc) { 3910 xmlFreeDoc(myDoc); 3911 } else { 3912 printf("parse failed\n"); 3913 okay = 0; 3914 } 3915 if (!strcmp(filename, "test/threads/invalid.xml")) { 3916 if (xmlDoValidityCheckingDefaultValue != 0) { 3917 printf("ValidityCheckingDefaultValue override failed\n"); 3918 okay = 0; 3919 } 3920 if (xmlGenericErrorContext != stdout) { 3921 printf("xmlGenericErrorContext override failed\n"); 3922 okay = 0; 3923 } 3924 } else { 3925 if (xmlDoValidityCheckingDefaultValue != 1) { 3926 printf("ValidityCheckingDefaultValue override failed\n"); 3927 okay = 0; 3928 } 3929 if (xmlGenericErrorContext != stderr) { 3930 printf("xmlGenericErrorContext override failed\n"); 3931 okay = 0; 3932 } 3933 } 3934 if (okay == 0) 3935 return ((void *) Failed); 3936 return ((void *) Okay); 3937 } 3938 3939 #if defined(linux) || defined(__sun) || defined(__APPLE_CC__) 3940 3941 #include <pthread.h> 3942 3943 static pthread_t tid[MAX_ARGC]; 3944 3945 static int 3946 testThread(void) 3947 { 3948 unsigned int i, repeat; 3949 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); 3950 void *results[MAX_ARGC]; 3951 int ret; 3952 int res = 0; 3953 3954 xmlInitParser(); 3955 3956 for (repeat = 0; repeat < 500; repeat++) { 3957 xmlLoadCatalog(catalog); 3958 nb_tests++; 3959 3960 for (i = 0; i < num_threads; i++) { 3961 results[i] = NULL; 3962 tid[i] = (pthread_t) - 1; 3963 } 3964 3965 for (i = 0; i < num_threads; i++) { 3966 ret = pthread_create(&tid[i], 0, thread_specific_data, 3967 (void *) testfiles[i]); 3968 if (ret != 0) { 3969 fprintf(stderr, "pthread_create failed\n"); 3970 return (1); 3971 } 3972 } 3973 for (i = 0; i < num_threads; i++) { 3974 ret = pthread_join(tid[i], &results[i]); 3975 if (ret != 0) { 3976 fprintf(stderr, "pthread_join failed\n"); 3977 return (1); 3978 } 3979 } 3980 3981 xmlCatalogCleanup(); 3982 for (i = 0; i < num_threads; i++) 3983 if (results[i] != (void *) Okay) { 3984 fprintf(stderr, "Thread %d handling %s failed\n", 3985 i, testfiles[i]); 3986 res = 1; 3987 } 3988 } 3989 return (res); 3990 } 3991 3992 #elif defined WIN32 3993 #include <windows.h> 3994 #include <string.h> 3995 3996 #define TEST_REPEAT_COUNT 500 3997 3998 static HANDLE tid[MAX_ARGC]; 3999 4000 static DWORD WINAPI 4001 win32_thread_specific_data(void *private_data) 4002 { 4003 return((DWORD) thread_specific_data(private_data)); 4004 } 4005 4006 static int 4007 testThread(void) 4008 { 4009 unsigned int i, repeat; 4010 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); 4011 DWORD results[MAX_ARGC]; 4012 BOOL ret; 4013 int res = 0; 4014 4015 xmlInitParser(); 4016 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) { 4017 xmlLoadCatalog(catalog); 4018 nb_tests++; 4019 4020 for (i = 0; i < num_threads; i++) { 4021 results[i] = 0; 4022 tid[i] = (HANDLE) - 1; 4023 } 4024 4025 for (i = 0; i < num_threads; i++) { 4026 DWORD useless; 4027 4028 tid[i] = CreateThread(NULL, 0, 4029 win32_thread_specific_data, 4030 (void *) testfiles[i], 0, 4031 &useless); 4032 if (tid[i] == NULL) { 4033 fprintf(stderr, "CreateThread failed\n"); 4034 return(1); 4035 } 4036 } 4037 4038 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) == 4039 WAIT_FAILED) { 4040 fprintf(stderr, "WaitForMultipleObjects failed\n"); 4041 return(1); 4042 } 4043 4044 for (i = 0; i < num_threads; i++) { 4045 ret = GetExitCodeThread(tid[i], &results[i]); 4046 if (ret == 0) { 4047 fprintf(stderr, "GetExitCodeThread failed\n"); 4048 return(1); 4049 } 4050 CloseHandle(tid[i]); 4051 } 4052 4053 xmlCatalogCleanup(); 4054 for (i = 0; i < num_threads; i++) { 4055 if (results[i] != (DWORD) Okay) { 4056 fprintf(stderr, "Thread %d handling %s failed\n", 4057 i, testfiles[i]); 4058 res = 1; 4059 } 4060 } 4061 } 4062 4063 return (res); 4064 } 4065 4066 #elif defined __BEOS__ 4067 #include <OS.h> 4068 4069 static thread_id tid[MAX_ARGC]; 4070 4071 static int 4072 testThread(void) 4073 { 4074 unsigned int i, repeat; 4075 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); 4076 void *results[MAX_ARGC]; 4077 status_t ret; 4078 int res = 0; 4079 4080 xmlInitParser(); 4081 for (repeat = 0; repeat < 500; repeat++) { 4082 xmlLoadCatalog(catalog); 4083 for (i = 0; i < num_threads; i++) { 4084 results[i] = NULL; 4085 tid[i] = (thread_id) - 1; 4086 } 4087 for (i = 0; i < num_threads; i++) { 4088 tid[i] = 4089 spawn_thread(thread_specific_data, "xmlTestThread", 4090 B_NORMAL_PRIORITY, (void *) testfiles[i]); 4091 if (tid[i] < B_OK) { 4092 fprintf(stderr, "beos_thread_create failed\n"); 4093 return (1); 4094 } 4095 printf("beos_thread_create %d -> %d\n", i, tid[i]); 4096 } 4097 for (i = 0; i < num_threads; i++) { 4098 ret = wait_for_thread(tid[i], &results[i]); 4099 printf("beos_thread_wait %d -> %d\n", i, ret); 4100 if (ret != B_OK) { 4101 fprintf(stderr, "beos_thread_wait failed\n"); 4102 return (1); 4103 } 4104 } 4105 4106 xmlCatalogCleanup(); 4107 ret = B_OK; 4108 for (i = 0; i < num_threads; i++) 4109 if (results[i] != (void *) Okay) { 4110 printf("Thread %d handling %s failed\n", i, testfiles[i]); 4111 ret = B_ERROR; 4112 } 4113 } 4114 if (ret != B_OK) 4115 return(1); 4116 return (0); 4117 } 4118 #else 4119 static int 4120 testThread(void) 4121 { 4122 fprintf(stderr, 4123 "Specific platform thread support not detected\n"); 4124 return (-1); 4125 } 4126 #endif 4127 static int 4128 threadsTest(const char *filename ATTRIBUTE_UNUSED, 4129 const char *resul ATTRIBUTE_UNUSED, 4130 const char *err ATTRIBUTE_UNUSED, 4131 int options ATTRIBUTE_UNUSED) { 4132 return(testThread()); 4133 } 4134 #endif 4135 /************************************************************************ 4136 * * 4137 * Tests Descriptions * 4138 * * 4139 ************************************************************************/ 4140 4141 static 4142 testDesc testDescriptions[] = { 4143 { "XML regression tests" , 4144 oldParseTest, "./test/*", "result/", "", NULL, 4145 0 }, 4146 { "XML regression tests on memory" , 4147 memParseTest, "./test/*", "result/", "", NULL, 4148 0 }, 4149 { "XML entity subst regression tests" , 4150 noentParseTest, "./test/*", "result/noent/", "", NULL, 4151 XML_PARSE_NOENT }, 4152 { "XML Namespaces regression tests", 4153 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err", 4154 0 }, 4155 { "Error cases regression tests", 4156 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err", 4157 0 }, 4158 #ifdef LIBXML_READER_ENABLED 4159 { "Error cases stream regression tests", 4160 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str", 4161 0 }, 4162 { "Reader regression tests", 4163 streamParseTest, "./test/*", "result/", ".rdr", NULL, 4164 0 }, 4165 { "Reader entities substitution regression tests", 4166 streamParseTest, "./test/*", "result/", ".rde", NULL, 4167 XML_PARSE_NOENT }, 4168 { "Reader on memory regression tests", 4169 streamMemParseTest, "./test/*", "result/", ".rdr", NULL, 4170 0 }, 4171 { "Walker regression tests", 4172 walkerParseTest, "./test/*", "result/", ".rdr", NULL, 4173 0 }, 4174 #endif 4175 #ifdef LIBXML_SAX1_ENABLED 4176 { "SAX1 callbacks regression tests" , 4177 saxParseTest, "./test/*", "result/", ".sax", NULL, 4178 XML_PARSE_SAX1 }, 4179 { "SAX2 callbacks regression tests" , 4180 saxParseTest, "./test/*", "result/", ".sax2", NULL, 4181 0 }, 4182 #endif 4183 #ifdef LIBXML_PUSH_ENABLED 4184 { "XML push regression tests" , 4185 pushParseTest, "./test/*", "result/", "", NULL, 4186 0 }, 4187 #endif 4188 #ifdef LIBXML_HTML_ENABLED 4189 { "HTML regression tests" , 4190 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err", 4191 XML_PARSE_HTML }, 4192 #ifdef LIBXML_PUSH_ENABLED 4193 { "Push HTML regression tests" , 4194 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err", 4195 XML_PARSE_HTML }, 4196 #endif 4197 #ifdef LIBXML_SAX1_ENABLED 4198 { "HTML SAX regression tests" , 4199 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL, 4200 XML_PARSE_HTML }, 4201 #endif 4202 #endif 4203 #ifdef LIBXML_VALID_ENABLED 4204 { "Valid documents regression tests" , 4205 errParseTest, "./test/VCM/*", NULL, NULL, NULL, 4206 XML_PARSE_DTDVALID }, 4207 { "Validity checking regression tests" , 4208 errParseTest, "./test/VC/*", "result/VC/", NULL, "", 4209 XML_PARSE_DTDVALID }, 4210 { "General documents valid regression tests" , 4211 errParseTest, "./test/valid/*", "result/valid/", "", ".err", 4212 XML_PARSE_DTDVALID }, 4213 #endif 4214 #ifdef LIBXML_XINCLUDE_ENABLED 4215 { "XInclude regression tests" , 4216 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, 4217 /* Ignore errors at this point ".err", */ 4218 XML_PARSE_XINCLUDE }, 4219 #ifdef LIBXML_READER_ENABLED 4220 { "XInclude xmlReader regression tests", 4221 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", 4222 /* Ignore errors at this point ".err", */ 4223 NULL, XML_PARSE_XINCLUDE }, 4224 #endif 4225 { "XInclude regression tests stripping include nodes" , 4226 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, 4227 /* Ignore errors at this point ".err", */ 4228 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, 4229 #ifdef LIBXML_READER_ENABLED 4230 { "XInclude xmlReader regression tests stripping include nodes", 4231 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", 4232 /* Ignore errors at this point ".err", */ 4233 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, 4234 #endif 4235 #endif 4236 #ifdef LIBXML_XPATH_ENABLED 4237 #ifdef LIBXML_DEBUG_ENABLED 4238 { "XPath expressions regression tests" , 4239 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL, 4240 0 }, 4241 { "XPath document queries regression tests" , 4242 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, 4243 0 }, 4244 #ifdef LIBXML_XPTR_ENABLED 4245 { "XPointer document queries regression tests" , 4246 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, 4247 0 }, 4248 #endif 4249 { "xml:id regression tests" , 4250 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err", 4251 0 }, 4252 #endif 4253 #endif 4254 { "URI parsing tests" , 4255 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL, 4256 0 }, 4257 { "URI base composition tests" , 4258 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL, 4259 0 }, 4260 { "Path URI conversion tests" , 4261 uriPathTest, NULL, NULL, NULL, NULL, 4262 0 }, 4263 #ifdef LIBXML_SCHEMAS_ENABLED 4264 { "Schemas regression tests" , 4265 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL, 4266 0 }, 4267 { "Relax-NG regression tests" , 4268 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL, 4269 XML_PARSE_DTDATTR | XML_PARSE_NOENT }, 4270 #ifdef LIBXML_READER_ENABLED 4271 { "Relax-NG streaming regression tests" , 4272 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL, 4273 XML_PARSE_DTDATTR | XML_PARSE_NOENT }, 4274 #endif 4275 #endif 4276 #ifdef LIBXML_PATTERN_ENABLED 4277 #ifdef LIBXML_READER_ENABLED 4278 { "Pattern regression tests" , 4279 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL, 4280 0 }, 4281 #endif 4282 #endif 4283 #ifdef LIBXML_C14N_ENABLED 4284 { "C14N with comments regression tests" , 4285 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL, 4286 0 }, 4287 { "C14N without comments regression tests" , 4288 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL, 4289 0 }, 4290 { "C14N exclusive without comments regression tests" , 4291 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL, 4292 0 }, 4293 { "C14N 1.1 without comments regression tests" , 4294 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL, 4295 0 }, 4296 #endif 4297 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED) 4298 { "Catalog and Threads regression tests" , 4299 threadsTest, NULL, NULL, NULL, NULL, 4300 0 }, 4301 #endif 4302 {NULL, NULL, NULL, NULL, NULL, NULL, 0} 4303 }; 4304 4305 /************************************************************************ 4306 * * 4307 * The main code driving the tests * 4308 * * 4309 ************************************************************************/ 4310 4311 static int 4312 launchTests(testDescPtr tst) { 4313 int res = 0, err = 0; 4314 size_t i; 4315 char *result; 4316 char *error; 4317 int mem; 4318 4319 if (tst == NULL) return(-1); 4320 if (tst->in != NULL) { 4321 glob_t globbuf; 4322 4323 globbuf.gl_offs = 0; 4324 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf); 4325 for (i = 0;i < globbuf.gl_pathc;i++) { 4326 if (!checkTestFile(globbuf.gl_pathv[i])) 4327 continue; 4328 if (tst->suffix != NULL) { 4329 result = resultFilename(globbuf.gl_pathv[i], tst->out, 4330 tst->suffix); 4331 if (result == NULL) { 4332 fprintf(stderr, "Out of memory !\n"); 4333 fatalError(); 4334 } 4335 } else { 4336 result = NULL; 4337 } 4338 if (tst->err != NULL) { 4339 error = resultFilename(globbuf.gl_pathv[i], tst->out, 4340 tst->err); 4341 if (error == NULL) { 4342 fprintf(stderr, "Out of memory !\n"); 4343 fatalError(); 4344 } 4345 } else { 4346 error = NULL; 4347 } 4348 if ((result) &&(!checkTestFile(result))) { 4349 fprintf(stderr, "Missing result file %s\n", result); 4350 } else if ((error) &&(!checkTestFile(error))) { 4351 fprintf(stderr, "Missing error file %s\n", error); 4352 } else { 4353 mem = xmlMemUsed(); 4354 extraMemoryFromResolver = 0; 4355 testErrorsSize = 0; 4356 testErrors[0] = 0; 4357 res = tst->func(globbuf.gl_pathv[i], result, error, 4358 tst->options | XML_PARSE_COMPACT); 4359 xmlResetLastError(); 4360 if (res != 0) { 4361 fprintf(stderr, "File %s generated an error\n", 4362 globbuf.gl_pathv[i]); 4363 nb_errors++; 4364 err++; 4365 } 4366 else if (xmlMemUsed() != mem) { 4367 if ((xmlMemUsed() != mem) && 4368 (extraMemoryFromResolver == 0)) { 4369 fprintf(stderr, "File %s leaked %d bytes\n", 4370 globbuf.gl_pathv[i], xmlMemUsed() - mem); 4371 nb_leaks++; 4372 err++; 4373 } 4374 } 4375 testErrorsSize = 0; 4376 } 4377 if (result) 4378 free(result); 4379 if (error) 4380 free(error); 4381 } 4382 globfree(&globbuf); 4383 } else { 4384 testErrorsSize = 0; 4385 testErrors[0] = 0; 4386 extraMemoryFromResolver = 0; 4387 res = tst->func(NULL, NULL, NULL, tst->options); 4388 if (res != 0) { 4389 nb_errors++; 4390 err++; 4391 } 4392 } 4393 return(err); 4394 } 4395 4396 static int verbose = 0; 4397 static int tests_quiet = 0; 4398 4399 static int 4400 runtest(int i) { 4401 int ret = 0, res; 4402 int old_errors, old_tests, old_leaks; 4403 4404 old_errors = nb_errors; 4405 old_tests = nb_tests; 4406 old_leaks = nb_leaks; 4407 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL)) 4408 printf("## %s\n", testDescriptions[i].desc); 4409 res = launchTests(&testDescriptions[i]); 4410 if (res != 0) 4411 ret++; 4412 if (verbose) { 4413 if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) 4414 printf("Ran %d tests, no errors\n", nb_tests - old_tests); 4415 else 4416 printf("Ran %d tests, %d errors, %d leaks\n", 4417 nb_tests - old_tests, 4418 nb_errors - old_errors, 4419 nb_leaks - old_leaks); 4420 } 4421 return(ret); 4422 } 4423 4424 int 4425 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { 4426 int i, a, ret = 0; 4427 int subset = 0; 4428 4429 initializeLibxml2(); 4430 4431 for (a = 1; a < argc;a++) { 4432 if (!strcmp(argv[a], "-v")) 4433 verbose = 1; 4434 else if (!strcmp(argv[a], "-quiet")) 4435 tests_quiet = 1; 4436 else { 4437 for (i = 0; testDescriptions[i].func != NULL; i++) { 4438 if (strstr(testDescriptions[i].desc, argv[a])) { 4439 ret += runtest(i); 4440 subset++; 4441 } 4442 } 4443 } 4444 } 4445 if (subset == 0) { 4446 for (i = 0; testDescriptions[i].func != NULL; i++) { 4447 ret += runtest(i); 4448 } 4449 } 4450 if ((nb_errors == 0) && (nb_leaks == 0)) { 4451 ret = 0; 4452 printf("Total %d tests, no errors\n", 4453 nb_tests); 4454 } else { 4455 ret = 1; 4456 printf("Total %d tests, %d errors, %d leaks\n", 4457 nb_tests, nb_errors, nb_leaks); 4458 } 4459 xmlCleanupParser(); 4460 xmlMemoryDump(); 4461 4462 return(ret); 4463 } 4464 4465 #else /* ! LIBXML_OUTPUT_ENABLED */ 4466 int 4467 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { 4468 fprintf(stderr, "runtest requires output to be enabled in libxml2\n"); 4469 return(1); 4470 } 4471 #endif 4472