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@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 } else 1708 unlink(temp); 1709 free(temp); 1710 1711 /* switch back to structured error handling */ 1712 xmlSetGenericErrorFunc(NULL, NULL); 1713 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler); 1714 1715 return(ret); 1716 } 1717 #endif 1718 1719 /************************************************************************ 1720 * * 1721 * Parse to tree based tests * 1722 * * 1723 ************************************************************************/ 1724 /** 1725 * oldParseTest: 1726 * @filename: the file to parse 1727 * @result: the file with expected result 1728 * @err: the file with error messages: unused 1729 * 1730 * Parse a file using the old xmlParseFile API, then serialize back 1731 * reparse the result and serialize again, then check for deviation 1732 * in serialization. 1733 * 1734 * Returns 0 in case of success, an error code otherwise 1735 */ 1736 static int 1737 oldParseTest(const char *filename, const char *result, 1738 const char *err ATTRIBUTE_UNUSED, 1739 int options ATTRIBUTE_UNUSED) { 1740 xmlDocPtr doc; 1741 char *temp; 1742 int res = 0; 1743 1744 nb_tests++; 1745 /* 1746 * base of the test, parse with the old API 1747 */ 1748 #ifdef LIBXML_SAX1_ENABLED 1749 doc = xmlParseFile(filename); 1750 #else 1751 doc = xmlReadFile(filename, NULL, 0); 1752 #endif 1753 if (doc == NULL) 1754 return(1); 1755 temp = resultFilename(filename, "", ".res"); 1756 if (temp == NULL) { 1757 fprintf(stderr, "out of memory\n"); 1758 fatalError(); 1759 } 1760 xmlSaveFile(temp, doc); 1761 if (compareFiles(temp, result)) { 1762 res = 1; 1763 } 1764 xmlFreeDoc(doc); 1765 1766 /* 1767 * Parse the saved result to make sure the round trip is okay 1768 */ 1769 #ifdef LIBXML_SAX1_ENABLED 1770 doc = xmlParseFile(temp); 1771 #else 1772 doc = xmlReadFile(temp, NULL, 0); 1773 #endif 1774 if (doc == NULL) 1775 return(1); 1776 xmlSaveFile(temp, doc); 1777 if (compareFiles(temp, result)) { 1778 res = 1; 1779 } 1780 xmlFreeDoc(doc); 1781 1782 unlink(temp); 1783 free(temp); 1784 return(res); 1785 } 1786 1787 #ifdef LIBXML_PUSH_ENABLED 1788 /** 1789 * pushParseTest: 1790 * @filename: the file to parse 1791 * @result: the file with expected result 1792 * @err: the file with error messages: unused 1793 * 1794 * Parse a file using the Push API, then serialize back 1795 * to check for content. 1796 * 1797 * Returns 0 in case of success, an error code otherwise 1798 */ 1799 static int 1800 pushParseTest(const char *filename, const char *result, 1801 const char *err ATTRIBUTE_UNUSED, 1802 int options) { 1803 xmlParserCtxtPtr ctxt; 1804 xmlDocPtr doc; 1805 const char *base; 1806 int size, res; 1807 int cur = 0; 1808 1809 nb_tests++; 1810 /* 1811 * load the document in memory and work from there. 1812 */ 1813 if (loadMem(filename, &base, &size) != 0) { 1814 fprintf(stderr, "Failed to load %s\n", filename); 1815 return(-1); 1816 } 1817 1818 #ifdef LIBXML_HTML_ENABLED 1819 if (options & XML_PARSE_HTML) 1820 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename, 1821 XML_CHAR_ENCODING_NONE); 1822 else 1823 #endif 1824 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename); 1825 xmlCtxtUseOptions(ctxt, options); 1826 cur += 4; 1827 while (cur < size) { 1828 if (cur + 1024 >= size) { 1829 #ifdef LIBXML_HTML_ENABLED 1830 if (options & XML_PARSE_HTML) 1831 htmlParseChunk(ctxt, base + cur, size - cur, 1); 1832 else 1833 #endif 1834 xmlParseChunk(ctxt, base + cur, size - cur, 1); 1835 break; 1836 } else { 1837 #ifdef LIBXML_HTML_ENABLED 1838 if (options & XML_PARSE_HTML) 1839 htmlParseChunk(ctxt, base + cur, 1024, 0); 1840 else 1841 #endif 1842 xmlParseChunk(ctxt, base + cur, 1024, 0); 1843 cur += 1024; 1844 } 1845 } 1846 doc = ctxt->myDoc; 1847 #ifdef LIBXML_HTML_ENABLED 1848 if (options & XML_PARSE_HTML) 1849 res = 1; 1850 else 1851 #endif 1852 res = ctxt->wellFormed; 1853 xmlFreeParserCtxt(ctxt); 1854 free((char *)base); 1855 if (!res) { 1856 xmlFreeDoc(doc); 1857 fprintf(stderr, "Failed to parse %s\n", filename); 1858 return(-1); 1859 } 1860 #ifdef LIBXML_HTML_ENABLED 1861 if (options & XML_PARSE_HTML) 1862 htmlDocDumpMemory(doc, (xmlChar **) &base, &size); 1863 else 1864 #endif 1865 xmlDocDumpMemory(doc, (xmlChar **) &base, &size); 1866 xmlFreeDoc(doc); 1867 res = compareFileMem(result, base, size); 1868 if ((base == NULL) || (res != 0)) { 1869 if (base != NULL) 1870 xmlFree((char *)base); 1871 fprintf(stderr, "Result for %s failed\n", filename); 1872 return(-1); 1873 } 1874 xmlFree((char *)base); 1875 if (err != NULL) { 1876 res = compareFileMem(err, testErrors, testErrorsSize); 1877 if (res != 0) { 1878 fprintf(stderr, "Error for %s failed\n", filename); 1879 return(-1); 1880 } 1881 } 1882 return(0); 1883 } 1884 #endif 1885 1886 /** 1887 * memParseTest: 1888 * @filename: the file to parse 1889 * @result: the file with expected result 1890 * @err: the file with error messages: unused 1891 * 1892 * Parse a file using the old xmlReadMemory API, then serialize back 1893 * reparse the result and serialize again, then check for deviation 1894 * in serialization. 1895 * 1896 * Returns 0 in case of success, an error code otherwise 1897 */ 1898 static int 1899 memParseTest(const char *filename, const char *result, 1900 const char *err ATTRIBUTE_UNUSED, 1901 int options ATTRIBUTE_UNUSED) { 1902 xmlDocPtr doc; 1903 const char *base; 1904 int size, res; 1905 1906 nb_tests++; 1907 /* 1908 * load and parse the memory 1909 */ 1910 if (loadMem(filename, &base, &size) != 0) { 1911 fprintf(stderr, "Failed to load %s\n", filename); 1912 return(-1); 1913 } 1914 1915 doc = xmlReadMemory(base, size, filename, NULL, 0); 1916 unloadMem(base); 1917 if (doc == NULL) { 1918 return(1); 1919 } 1920 xmlDocDumpMemory(doc, (xmlChar **) &base, &size); 1921 xmlFreeDoc(doc); 1922 res = compareFileMem(result, base, size); 1923 if ((base == NULL) || (res != 0)) { 1924 if (base != NULL) 1925 xmlFree((char *)base); 1926 fprintf(stderr, "Result for %s failed\n", filename); 1927 return(-1); 1928 } 1929 xmlFree((char *)base); 1930 return(0); 1931 } 1932 1933 /** 1934 * noentParseTest: 1935 * @filename: the file to parse 1936 * @result: the file with expected result 1937 * @err: the file with error messages: unused 1938 * 1939 * Parse a file with entity resolution, then serialize back 1940 * reparse the result and serialize again, then check for deviation 1941 * in serialization. 1942 * 1943 * Returns 0 in case of success, an error code otherwise 1944 */ 1945 static int 1946 noentParseTest(const char *filename, const char *result, 1947 const char *err ATTRIBUTE_UNUSED, 1948 int options) { 1949 xmlDocPtr doc; 1950 char *temp; 1951 int res = 0; 1952 1953 nb_tests++; 1954 /* 1955 * base of the test, parse with the old API 1956 */ 1957 doc = xmlReadFile(filename, NULL, options); 1958 if (doc == NULL) 1959 return(1); 1960 temp = resultFilename(filename, "", ".res"); 1961 if (temp == NULL) { 1962 fprintf(stderr, "Out of memory\n"); 1963 fatalError(); 1964 } 1965 xmlSaveFile(temp, doc); 1966 if (compareFiles(temp, result)) { 1967 res = 1; 1968 } 1969 xmlFreeDoc(doc); 1970 1971 /* 1972 * Parse the saved result to make sure the round trip is okay 1973 */ 1974 doc = xmlReadFile(filename, NULL, options); 1975 if (doc == NULL) 1976 return(1); 1977 xmlSaveFile(temp, doc); 1978 if (compareFiles(temp, result)) { 1979 res = 1; 1980 } 1981 xmlFreeDoc(doc); 1982 1983 unlink(temp); 1984 free(temp); 1985 return(res); 1986 } 1987 1988 /** 1989 * errParseTest: 1990 * @filename: the file to parse 1991 * @result: the file with expected result 1992 * @err: the file with error messages 1993 * 1994 * Parse a file using the xmlReadFile API and check for errors. 1995 * 1996 * Returns 0 in case of success, an error code otherwise 1997 */ 1998 static int 1999 errParseTest(const char *filename, const char *result, const char *err, 2000 int options) { 2001 xmlDocPtr doc; 2002 const char *base = NULL; 2003 int size, res = 0; 2004 2005 nb_tests++; 2006 #ifdef LIBXML_HTML_ENABLED 2007 if (options & XML_PARSE_HTML) { 2008 doc = htmlReadFile(filename, NULL, options); 2009 } else 2010 #endif 2011 #ifdef LIBXML_XINCLUDE_ENABLED 2012 if (options & XML_PARSE_XINCLUDE) { 2013 doc = xmlReadFile(filename, NULL, options); 2014 xmlXIncludeProcessFlags(doc, options); 2015 } else 2016 #endif 2017 { 2018 xmlGetWarningsDefaultValue = 1; 2019 doc = xmlReadFile(filename, NULL, options); 2020 } 2021 xmlGetWarningsDefaultValue = 0; 2022 if (result) { 2023 if (doc == NULL) { 2024 base = ""; 2025 size = 0; 2026 } else { 2027 #ifdef LIBXML_HTML_ENABLED 2028 if (options & XML_PARSE_HTML) { 2029 htmlDocDumpMemory(doc, (xmlChar **) &base, &size); 2030 } else 2031 #endif 2032 xmlDocDumpMemory(doc, (xmlChar **) &base, &size); 2033 } 2034 res = compareFileMem(result, base, size); 2035 } 2036 if (doc != NULL) { 2037 if (base != NULL) 2038 xmlFree((char *)base); 2039 xmlFreeDoc(doc); 2040 } 2041 if (res != 0) { 2042 fprintf(stderr, "Result for %s failed\n", filename); 2043 return(-1); 2044 } 2045 if (err != NULL) { 2046 res = compareFileMem(err, testErrors, testErrorsSize); 2047 if (res != 0) { 2048 fprintf(stderr, "Error for %s failed\n", filename); 2049 return(-1); 2050 } 2051 } else if (options & XML_PARSE_DTDVALID) { 2052 if (testErrorsSize != 0) 2053 fprintf(stderr, "Validation for %s failed\n", filename); 2054 } 2055 2056 return(0); 2057 } 2058 2059 #ifdef LIBXML_READER_ENABLED 2060 /************************************************************************ 2061 * * 2062 * Reader based tests * 2063 * * 2064 ************************************************************************/ 2065 2066 static void processNode(FILE *out, xmlTextReaderPtr reader) { 2067 const xmlChar *name, *value; 2068 int type, empty; 2069 2070 type = xmlTextReaderNodeType(reader); 2071 empty = xmlTextReaderIsEmptyElement(reader); 2072 2073 name = xmlTextReaderConstName(reader); 2074 if (name == NULL) 2075 name = BAD_CAST "--"; 2076 2077 value = xmlTextReaderConstValue(reader); 2078 2079 2080 fprintf(out, "%d %d %s %d %d", 2081 xmlTextReaderDepth(reader), 2082 type, 2083 name, 2084 empty, 2085 xmlTextReaderHasValue(reader)); 2086 if (value == NULL) 2087 fprintf(out, "\n"); 2088 else { 2089 fprintf(out, " %s\n", value); 2090 } 2091 } 2092 static int 2093 streamProcessTest(const char *filename, const char *result, const char *err, 2094 xmlTextReaderPtr reader, const char *rng) { 2095 int ret; 2096 char *temp = NULL; 2097 FILE *t = NULL; 2098 2099 if (reader == NULL) 2100 return(-1); 2101 2102 nb_tests++; 2103 if (result != NULL) { 2104 temp = resultFilename(filename, "", ".res"); 2105 if (temp == NULL) { 2106 fprintf(stderr, "Out of memory\n"); 2107 fatalError(); 2108 } 2109 t = fopen(temp, "wb"); 2110 if (t == NULL) { 2111 fprintf(stderr, "Can't open temp file %s\n", temp); 2112 free(temp); 2113 return(-1); 2114 } 2115 } 2116 #ifdef LIBXML_SCHEMAS_ENABLED 2117 if (rng != NULL) { 2118 ret = xmlTextReaderRelaxNGValidate(reader, rng); 2119 if (ret < 0) { 2120 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n", 2121 rng); 2122 fclose(t); 2123 unlink(temp); 2124 free(temp); 2125 return(0); 2126 } 2127 } 2128 #endif 2129 xmlGetWarningsDefaultValue = 1; 2130 ret = xmlTextReaderRead(reader); 2131 while (ret == 1) { 2132 if ((t != NULL) && (rng == NULL)) 2133 processNode(t, reader); 2134 ret = xmlTextReaderRead(reader); 2135 } 2136 if (ret != 0) { 2137 testErrorHandler(NULL, "%s : failed to parse\n", filename); 2138 } 2139 if (rng != NULL) { 2140 if (xmlTextReaderIsValid(reader) != 1) { 2141 testErrorHandler(NULL, "%s fails to validate\n", filename); 2142 } else { 2143 testErrorHandler(NULL, "%s validates\n", filename); 2144 } 2145 } 2146 xmlGetWarningsDefaultValue = 0; 2147 if (t != NULL) { 2148 fclose(t); 2149 ret = compareFiles(temp, result); 2150 unlink(temp); 2151 free(temp); 2152 if (ret) { 2153 fprintf(stderr, "Result for %s failed\n", filename); 2154 return(-1); 2155 } 2156 } 2157 if (err != NULL) { 2158 ret = compareFileMem(err, testErrors, testErrorsSize); 2159 if (ret != 0) { 2160 fprintf(stderr, "Error for %s failed\n", filename); 2161 printf("%s", testErrors); 2162 return(-1); 2163 } 2164 } 2165 2166 return(0); 2167 } 2168 2169 /** 2170 * streamParseTest: 2171 * @filename: the file to parse 2172 * @result: the file with expected result 2173 * @err: the file with error messages 2174 * 2175 * Parse a file using the reader API and check for errors. 2176 * 2177 * Returns 0 in case of success, an error code otherwise 2178 */ 2179 static int 2180 streamParseTest(const char *filename, const char *result, const char *err, 2181 int options) { 2182 xmlTextReaderPtr reader; 2183 int ret; 2184 2185 reader = xmlReaderForFile(filename, NULL, options); 2186 ret = streamProcessTest(filename, result, err, reader, NULL); 2187 xmlFreeTextReader(reader); 2188 return(ret); 2189 } 2190 2191 /** 2192 * walkerParseTest: 2193 * @filename: the file to parse 2194 * @result: the file with expected result 2195 * @err: the file with error messages 2196 * 2197 * Parse a file using the walker, i.e. a reader built from a atree. 2198 * 2199 * Returns 0 in case of success, an error code otherwise 2200 */ 2201 static int 2202 walkerParseTest(const char *filename, const char *result, const char *err, 2203 int options) { 2204 xmlDocPtr doc; 2205 xmlTextReaderPtr reader; 2206 int ret; 2207 2208 doc = xmlReadFile(filename, NULL, options); 2209 if (doc == NULL) { 2210 fprintf(stderr, "Failed to parse %s\n", filename); 2211 return(-1); 2212 } 2213 reader = xmlReaderWalker(doc); 2214 ret = streamProcessTest(filename, result, err, reader, NULL); 2215 xmlFreeTextReader(reader); 2216 xmlFreeDoc(doc); 2217 return(ret); 2218 } 2219 2220 /** 2221 * streamMemParseTest: 2222 * @filename: the file to parse 2223 * @result: the file with expected result 2224 * @err: the file with error messages 2225 * 2226 * Parse a file using the reader API from memory and check for errors. 2227 * 2228 * Returns 0 in case of success, an error code otherwise 2229 */ 2230 static int 2231 streamMemParseTest(const char *filename, const char *result, const char *err, 2232 int options) { 2233 xmlTextReaderPtr reader; 2234 int ret; 2235 const char *base; 2236 int size; 2237 2238 /* 2239 * load and parse the memory 2240 */ 2241 if (loadMem(filename, &base, &size) != 0) { 2242 fprintf(stderr, "Failed to load %s\n", filename); 2243 return(-1); 2244 } 2245 reader = xmlReaderForMemory(base, size, filename, NULL, options); 2246 ret = streamProcessTest(filename, result, err, reader, NULL); 2247 free((char *)base); 2248 xmlFreeTextReader(reader); 2249 return(ret); 2250 } 2251 #endif 2252 2253 #ifdef LIBXML_XPATH_ENABLED 2254 #ifdef LIBXML_DEBUG_ENABLED 2255 /************************************************************************ 2256 * * 2257 * XPath and XPointer based tests * 2258 * * 2259 ************************************************************************/ 2260 2261 static FILE *xpathOutput; 2262 static xmlDocPtr xpathDocument; 2263 2264 static void 2265 testXPath(const char *str, int xptr, int expr) { 2266 xmlXPathObjectPtr res; 2267 xmlXPathContextPtr ctxt; 2268 2269 nb_tests++; 2270 #if defined(LIBXML_XPTR_ENABLED) 2271 if (xptr) { 2272 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL); 2273 res = xmlXPtrEval(BAD_CAST str, ctxt); 2274 } else { 2275 #endif 2276 ctxt = xmlXPathNewContext(xpathDocument); 2277 ctxt->node = xmlDocGetRootElement(xpathDocument); 2278 if (expr) 2279 res = xmlXPathEvalExpression(BAD_CAST str, ctxt); 2280 else { 2281 /* res = xmlXPathEval(BAD_CAST str, ctxt); */ 2282 xmlXPathCompExprPtr comp; 2283 2284 comp = xmlXPathCompile(BAD_CAST str); 2285 if (comp != NULL) { 2286 res = xmlXPathCompiledEval(comp, ctxt); 2287 xmlXPathFreeCompExpr(comp); 2288 } else 2289 res = NULL; 2290 } 2291 #if defined(LIBXML_XPTR_ENABLED) 2292 } 2293 #endif 2294 xmlXPathDebugDumpObject(xpathOutput, res, 0); 2295 xmlXPathFreeObject(res); 2296 xmlXPathFreeContext(ctxt); 2297 } 2298 2299 /** 2300 * xpathExprTest: 2301 * @filename: the file to parse 2302 * @result: the file with expected result 2303 * @err: the file with error messages 2304 * 2305 * Parse a file containing XPath standalone expressions and evaluate them 2306 * 2307 * Returns 0 in case of success, an error code otherwise 2308 */ 2309 static int 2310 xpathCommonTest(const char *filename, const char *result, 2311 int xptr, int expr) { 2312 FILE *input; 2313 char expression[5000]; 2314 int len, ret = 0; 2315 char *temp; 2316 2317 temp = resultFilename(filename, "", ".res"); 2318 if (temp == NULL) { 2319 fprintf(stderr, "Out of memory\n"); 2320 fatalError(); 2321 } 2322 xpathOutput = fopen(temp, "wb"); 2323 if (xpathOutput == NULL) { 2324 fprintf(stderr, "failed to open output file %s\n", temp); 2325 free(temp); 2326 return(-1); 2327 } 2328 2329 input = fopen(filename, "rb"); 2330 if (input == NULL) { 2331 xmlGenericError(xmlGenericErrorContext, 2332 "Cannot open %s for reading\n", filename); 2333 free(temp); 2334 return(-1); 2335 } 2336 while (fgets(expression, 4500, input) != NULL) { 2337 len = strlen(expression); 2338 len--; 2339 while ((len >= 0) && 2340 ((expression[len] == '\n') || (expression[len] == '\t') || 2341 (expression[len] == '\r') || (expression[len] == ' '))) len--; 2342 expression[len + 1] = 0; 2343 if (len >= 0) { 2344 fprintf(xpathOutput, 2345 "\n========================\nExpression: %s\n", 2346 expression) ; 2347 testXPath(expression, xptr, expr); 2348 } 2349 } 2350 2351 fclose(input); 2352 fclose(xpathOutput); 2353 if (result != NULL) { 2354 ret = compareFiles(temp, result); 2355 if (ret) { 2356 fprintf(stderr, "Result for %s failed\n", filename); 2357 } 2358 } 2359 2360 unlink(temp); 2361 free(temp); 2362 return(ret); 2363 } 2364 2365 /** 2366 * xpathExprTest: 2367 * @filename: the file to parse 2368 * @result: the file with expected result 2369 * @err: the file with error messages 2370 * 2371 * Parse a file containing XPath standalone expressions and evaluate them 2372 * 2373 * Returns 0 in case of success, an error code otherwise 2374 */ 2375 static int 2376 xpathExprTest(const char *filename, const char *result, 2377 const char *err ATTRIBUTE_UNUSED, 2378 int options ATTRIBUTE_UNUSED) { 2379 return(xpathCommonTest(filename, result, 0, 1)); 2380 } 2381 2382 /** 2383 * xpathDocTest: 2384 * @filename: the file to parse 2385 * @result: the file with expected result 2386 * @err: the file with error messages 2387 * 2388 * Parse a file containing XPath expressions and evaluate them against 2389 * a set of corresponding documents. 2390 * 2391 * Returns 0 in case of success, an error code otherwise 2392 */ 2393 static int 2394 xpathDocTest(const char *filename, 2395 const char *resul ATTRIBUTE_UNUSED, 2396 const char *err ATTRIBUTE_UNUSED, 2397 int options) { 2398 2399 char pattern[500]; 2400 char result[500]; 2401 glob_t globbuf; 2402 size_t i; 2403 int ret = 0, res; 2404 2405 xpathDocument = xmlReadFile(filename, NULL, 2406 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); 2407 if (xpathDocument == NULL) { 2408 fprintf(stderr, "Failed to load %s\n", filename); 2409 return(-1); 2410 } 2411 2412 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename)); 2413 pattern[499] = 0; 2414 globbuf.gl_offs = 0; 2415 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 2416 for (i = 0;i < globbuf.gl_pathc;i++) { 2417 snprintf(result, 499, "result/XPath/tests/%s", 2418 baseFilename(globbuf.gl_pathv[i])); 2419 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0); 2420 if (res != 0) 2421 ret = res; 2422 } 2423 globfree(&globbuf); 2424 2425 xmlFreeDoc(xpathDocument); 2426 return(ret); 2427 } 2428 2429 #ifdef LIBXML_XPTR_ENABLED 2430 /** 2431 * xptrDocTest: 2432 * @filename: the file to parse 2433 * @result: the file with expected result 2434 * @err: the file with error messages 2435 * 2436 * Parse a file containing XPath expressions and evaluate them against 2437 * a set of corresponding documents. 2438 * 2439 * Returns 0 in case of success, an error code otherwise 2440 */ 2441 static int 2442 xptrDocTest(const char *filename, 2443 const char *resul ATTRIBUTE_UNUSED, 2444 const char *err ATTRIBUTE_UNUSED, 2445 int options) { 2446 2447 char pattern[500]; 2448 char result[500]; 2449 glob_t globbuf; 2450 size_t i; 2451 int ret = 0, res; 2452 2453 xpathDocument = xmlReadFile(filename, NULL, 2454 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); 2455 if (xpathDocument == NULL) { 2456 fprintf(stderr, "Failed to load %s\n", filename); 2457 return(-1); 2458 } 2459 2460 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename)); 2461 pattern[499] = 0; 2462 globbuf.gl_offs = 0; 2463 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 2464 for (i = 0;i < globbuf.gl_pathc;i++) { 2465 snprintf(result, 499, "result/XPath/xptr/%s", 2466 baseFilename(globbuf.gl_pathv[i])); 2467 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0); 2468 if (res != 0) 2469 ret = res; 2470 } 2471 globfree(&globbuf); 2472 2473 xmlFreeDoc(xpathDocument); 2474 return(ret); 2475 } 2476 #endif /* LIBXML_XPTR_ENABLED */ 2477 2478 /** 2479 * xmlidDocTest: 2480 * @filename: the file to parse 2481 * @result: the file with expected result 2482 * @err: the file with error messages 2483 * 2484 * Parse a file containing xml:id and check for errors and verify 2485 * that XPath queries will work on them as expected. 2486 * 2487 * Returns 0 in case of success, an error code otherwise 2488 */ 2489 static int 2490 xmlidDocTest(const char *filename, 2491 const char *result, 2492 const char *err, 2493 int options) { 2494 2495 int res = 0; 2496 int ret = 0; 2497 char *temp; 2498 2499 xpathDocument = xmlReadFile(filename, NULL, 2500 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); 2501 if (xpathDocument == NULL) { 2502 fprintf(stderr, "Failed to load %s\n", filename); 2503 return(-1); 2504 } 2505 2506 temp = resultFilename(filename, "", ".res"); 2507 if (temp == NULL) { 2508 fprintf(stderr, "Out of memory\n"); 2509 fatalError(); 2510 } 2511 xpathOutput = fopen(temp, "wb"); 2512 if (xpathOutput == NULL) { 2513 fprintf(stderr, "failed to open output file %s\n", temp); 2514 xmlFreeDoc(xpathDocument); 2515 free(temp); 2516 return(-1); 2517 } 2518 2519 testXPath("id('bar')", 0, 0); 2520 2521 fclose(xpathOutput); 2522 if (result != NULL) { 2523 ret = compareFiles(temp, result); 2524 if (ret) { 2525 fprintf(stderr, "Result for %s failed\n", filename); 2526 res = 1; 2527 } 2528 } 2529 2530 unlink(temp); 2531 free(temp); 2532 xmlFreeDoc(xpathDocument); 2533 2534 if (err != NULL) { 2535 ret = compareFileMem(err, testErrors, testErrorsSize); 2536 if (ret != 0) { 2537 fprintf(stderr, "Error for %s failed\n", filename); 2538 res = 1; 2539 } 2540 } 2541 return(res); 2542 } 2543 2544 #endif /* LIBXML_DEBUG_ENABLED */ 2545 #endif /* XPATH */ 2546 /************************************************************************ 2547 * * 2548 * URI based tests * 2549 * * 2550 ************************************************************************/ 2551 2552 static void 2553 handleURI(const char *str, const char *base, FILE *o) { 2554 int ret; 2555 xmlURIPtr uri; 2556 xmlChar *res = NULL; 2557 2558 uri = xmlCreateURI(); 2559 2560 if (base == NULL) { 2561 ret = xmlParseURIReference(uri, str); 2562 if (ret != 0) 2563 fprintf(o, "%s : error %d\n", str, ret); 2564 else { 2565 xmlNormalizeURIPath(uri->path); 2566 xmlPrintURI(o, uri); 2567 fprintf(o, "\n"); 2568 } 2569 } else { 2570 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base); 2571 if (res != NULL) { 2572 fprintf(o, "%s\n", (char *) res); 2573 } 2574 else 2575 fprintf(o, "::ERROR::\n"); 2576 } 2577 if (res != NULL) 2578 xmlFree(res); 2579 xmlFreeURI(uri); 2580 } 2581 2582 /** 2583 * uriCommonTest: 2584 * @filename: the file to parse 2585 * @result: the file with expected result 2586 * @err: the file with error messages 2587 * 2588 * Parse a file containing URI and check for errors 2589 * 2590 * Returns 0 in case of success, an error code otherwise 2591 */ 2592 static int 2593 uriCommonTest(const char *filename, 2594 const char *result, 2595 const char *err, 2596 const char *base) { 2597 char *temp; 2598 FILE *o, *f; 2599 char str[1024]; 2600 int res = 0, i, ret; 2601 2602 temp = resultFilename(filename, "", ".res"); 2603 if (temp == NULL) { 2604 fprintf(stderr, "Out of memory\n"); 2605 fatalError(); 2606 } 2607 o = fopen(temp, "wb"); 2608 if (o == NULL) { 2609 fprintf(stderr, "failed to open output file %s\n", temp); 2610 free(temp); 2611 return(-1); 2612 } 2613 f = fopen(filename, "rb"); 2614 if (f == NULL) { 2615 fprintf(stderr, "failed to open input file %s\n", filename); 2616 fclose(o); 2617 unlink(temp); 2618 free(temp); 2619 return(-1); 2620 } 2621 2622 while (1) { 2623 /* 2624 * read one line in string buffer. 2625 */ 2626 if (fgets (&str[0], sizeof (str) - 1, f) == NULL) 2627 break; 2628 2629 /* 2630 * remove the ending spaces 2631 */ 2632 i = strlen(str); 2633 while ((i > 0) && 2634 ((str[i - 1] == '\n') || (str[i - 1] == '\r') || 2635 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { 2636 i--; 2637 str[i] = 0; 2638 } 2639 nb_tests++; 2640 handleURI(str, base, o); 2641 } 2642 2643 fclose(f); 2644 fclose(o); 2645 2646 if (result != NULL) { 2647 ret = compareFiles(temp, result); 2648 if (ret) { 2649 fprintf(stderr, "Result for %s failed\n", filename); 2650 res = 1; 2651 } 2652 } 2653 if (err != NULL) { 2654 ret = compareFileMem(err, testErrors, testErrorsSize); 2655 if (ret != 0) { 2656 fprintf(stderr, "Error for %s failed\n", filename); 2657 res = 1; 2658 } 2659 } 2660 2661 unlink(temp); 2662 free(temp); 2663 return(res); 2664 } 2665 2666 /** 2667 * uriParseTest: 2668 * @filename: the file to parse 2669 * @result: the file with expected result 2670 * @err: the file with error messages 2671 * 2672 * Parse a file containing URI and check for errors 2673 * 2674 * Returns 0 in case of success, an error code otherwise 2675 */ 2676 static int 2677 uriParseTest(const char *filename, 2678 const char *result, 2679 const char *err, 2680 int options ATTRIBUTE_UNUSED) { 2681 return(uriCommonTest(filename, result, err, NULL)); 2682 } 2683 2684 /** 2685 * uriBaseTest: 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, compose them against a fixed base and 2691 * check for errors 2692 * 2693 * Returns 0 in case of success, an error code otherwise 2694 */ 2695 static int 2696 uriBaseTest(const char *filename, 2697 const char *result, 2698 const char *err, 2699 int options ATTRIBUTE_UNUSED) { 2700 return(uriCommonTest(filename, result, err, 2701 "http://foo.com/path/to/index.html?orig#help")); 2702 } 2703 2704 static int urip_success = 1; 2705 static int urip_current = 0; 2706 static const char *urip_testURLs[] = { 2707 "urip://example.com/a b.html", 2708 "urip://example.com/a%20b.html", 2709 "file:///path/to/a b.html", 2710 "file:///path/to/a%20b.html", 2711 "/path/to/a b.html", 2712 "/path/to/a%20b.html", 2713 "urip://example.com/résumé.html", 2714 "urip://example.com/test?a=1&b=2%263&c=4#foo", 2715 NULL 2716 }; 2717 static const char *urip_rcvsURLs[] = { 2718 /* it is an URI the strings must be escaped */ 2719 "urip://example.com/a%20b.html", 2720 /* check that % escaping is not broken */ 2721 "urip://example.com/a%20b.html", 2722 /* it's an URI path the strings must be escaped */ 2723 "file:///path/to/a%20b.html", 2724 /* check that % escaping is not broken */ 2725 "file:///path/to/a%20b.html", 2726 /* this is not an URI, this is a path, so this should not be escaped */ 2727 "/path/to/a b.html", 2728 /* check that paths with % are not broken */ 2729 "/path/to/a%20b.html", 2730 /* out of context the encoding can't be guessed byte by byte conversion */ 2731 "urip://example.com/r%E9sum%E9.html", 2732 /* verify we don't destroy URIs especially the query part */ 2733 "urip://example.com/test?a=1&b=2%263&c=4#foo", 2734 NULL 2735 }; 2736 static const char *urip_res = "<list/>"; 2737 static const char *urip_cur = NULL; 2738 static int urip_rlen; 2739 2740 /** 2741 * uripMatch: 2742 * @URI: an URI to test 2743 * 2744 * Check for an urip: query 2745 * 2746 * Returns 1 if yes and 0 if another Input module should be used 2747 */ 2748 static int 2749 uripMatch(const char * URI) { 2750 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog"))) 2751 return(0); 2752 /* Verify we received the escaped URL */ 2753 if (strcmp(urip_rcvsURLs[urip_current], URI)) 2754 urip_success = 0; 2755 return(1); 2756 } 2757 2758 /** 2759 * uripOpen: 2760 * @URI: an URI to test 2761 * 2762 * Return a pointer to the urip: query handler, in this example simply 2763 * the urip_current pointer... 2764 * 2765 * Returns an Input context or NULL in case or error 2766 */ 2767 static void * 2768 uripOpen(const char * URI) { 2769 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog"))) 2770 return(NULL); 2771 /* Verify we received the escaped URL */ 2772 if (strcmp(urip_rcvsURLs[urip_current], URI)) 2773 urip_success = 0; 2774 urip_cur = urip_res; 2775 urip_rlen = strlen(urip_res); 2776 return((void *) urip_cur); 2777 } 2778 2779 /** 2780 * uripClose: 2781 * @context: the read context 2782 * 2783 * Close the urip: query handler 2784 * 2785 * Returns 0 or -1 in case of error 2786 */ 2787 static int 2788 uripClose(void * context) { 2789 if (context == NULL) return(-1); 2790 urip_cur = NULL; 2791 urip_rlen = 0; 2792 return(0); 2793 } 2794 2795 /** 2796 * uripRead: 2797 * @context: the read context 2798 * @buffer: where to store data 2799 * @len: number of bytes to read 2800 * 2801 * Implement an urip: query read. 2802 * 2803 * Returns the number of bytes read or -1 in case of error 2804 */ 2805 static int 2806 uripRead(void * context, char * buffer, int len) { 2807 const char *ptr = (const char *) context; 2808 2809 if ((context == NULL) || (buffer == NULL) || (len < 0)) 2810 return(-1); 2811 2812 if (len > urip_rlen) len = urip_rlen; 2813 memcpy(buffer, ptr, len); 2814 urip_rlen -= len; 2815 return(len); 2816 } 2817 2818 static int 2819 urip_checkURL(const char *URL) { 2820 xmlDocPtr doc; 2821 2822 doc = xmlReadFile(URL, NULL, 0); 2823 if (doc == NULL) 2824 return(-1); 2825 xmlFreeDoc(doc); 2826 return(1); 2827 } 2828 2829 /** 2830 * uriPathTest: 2831 * @filename: ignored 2832 * @result: ignored 2833 * @err: ignored 2834 * 2835 * Run a set of tests to check how Path and URI are handled before 2836 * being passed to the I/O layer 2837 * 2838 * Returns 0 in case of success, an error code otherwise 2839 */ 2840 static int 2841 uriPathTest(const char *filename ATTRIBUTE_UNUSED, 2842 const char *result ATTRIBUTE_UNUSED, 2843 const char *err ATTRIBUTE_UNUSED, 2844 int options ATTRIBUTE_UNUSED) { 2845 int parsed; 2846 int failures = 0; 2847 2848 /* 2849 * register the new I/O handlers 2850 */ 2851 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0) 2852 { 2853 fprintf(stderr, "failed to register HTTP handler\n"); 2854 return(-1); 2855 } 2856 2857 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) { 2858 urip_success = 1; 2859 parsed = urip_checkURL(urip_testURLs[urip_current]); 2860 if (urip_success != 1) { 2861 fprintf(stderr, "failed the URL passing test for %s", 2862 urip_testURLs[urip_current]); 2863 failures++; 2864 } else if (parsed != 1) { 2865 fprintf(stderr, "failed the parsing test for %s", 2866 urip_testURLs[urip_current]); 2867 failures++; 2868 } 2869 nb_tests++; 2870 } 2871 2872 xmlPopInputCallbacks(); 2873 return(failures); 2874 } 2875 2876 #ifdef LIBXML_SCHEMAS_ENABLED 2877 /************************************************************************ 2878 * * 2879 * Schemas tests * 2880 * * 2881 ************************************************************************/ 2882 static int 2883 schemasOneTest(const char *sch, 2884 const char *filename, 2885 const char *result, 2886 const char *err, 2887 int options, 2888 xmlSchemaPtr schemas) { 2889 xmlDocPtr doc; 2890 xmlSchemaValidCtxtPtr ctxt; 2891 int ret = 0; 2892 int validResult = 0; 2893 char *temp; 2894 FILE *schemasOutput; 2895 2896 doc = xmlReadFile(filename, NULL, options); 2897 if (doc == NULL) { 2898 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); 2899 return(-1); 2900 } 2901 2902 temp = resultFilename(result, "", ".res"); 2903 if (temp == NULL) { 2904 fprintf(stderr, "Out of memory\n"); 2905 fatalError(); 2906 } 2907 schemasOutput = fopen(temp, "wb"); 2908 if (schemasOutput == NULL) { 2909 fprintf(stderr, "failed to open output file %s\n", temp); 2910 xmlFreeDoc(doc); 2911 free(temp); 2912 return(-1); 2913 } 2914 2915 ctxt = xmlSchemaNewValidCtxt(schemas); 2916 xmlSchemaSetValidErrors(ctxt, 2917 (xmlSchemaValidityErrorFunc) testErrorHandler, 2918 (xmlSchemaValidityWarningFunc) testErrorHandler, 2919 ctxt); 2920 validResult = xmlSchemaValidateDoc(ctxt, doc); 2921 if (validResult == 0) { 2922 fprintf(schemasOutput, "%s validates\n", filename); 2923 } else if (validResult > 0) { 2924 fprintf(schemasOutput, "%s fails to validate\n", filename); 2925 } else { 2926 fprintf(schemasOutput, "%s validation generated an internal error\n", 2927 filename); 2928 } 2929 fclose(schemasOutput); 2930 if (result) { 2931 if (compareFiles(temp, result)) { 2932 fprintf(stderr, "Result for %s on %s failed\n", filename, sch); 2933 ret = 1; 2934 } 2935 } 2936 unlink(temp); 2937 free(temp); 2938 2939 if ((validResult != 0) && (err != NULL)) { 2940 if (compareFileMem(err, testErrors, testErrorsSize)) { 2941 fprintf(stderr, "Error for %s on %s failed\n", filename, sch); 2942 ret = 1; 2943 } 2944 } 2945 2946 xmlSchemaFreeValidCtxt(ctxt); 2947 xmlFreeDoc(doc); 2948 return(ret); 2949 } 2950 /** 2951 * schemasTest: 2952 * @filename: the schemas file 2953 * @result: the file with expected result 2954 * @err: the file with error messages 2955 * 2956 * Parse a file containing URI, compose them against a fixed base and 2957 * check for errors 2958 * 2959 * Returns 0 in case of success, an error code otherwise 2960 */ 2961 static int 2962 schemasTest(const char *filename, 2963 const char *resul ATTRIBUTE_UNUSED, 2964 const char *errr ATTRIBUTE_UNUSED, 2965 int options) { 2966 const char *base = baseFilename(filename); 2967 const char *base2; 2968 const char *instance; 2969 xmlSchemaParserCtxtPtr ctxt; 2970 xmlSchemaPtr schemas; 2971 int res = 0, len, ret; 2972 char pattern[500]; 2973 char prefix[500]; 2974 char result[500]; 2975 char err[500]; 2976 glob_t globbuf; 2977 size_t i; 2978 char count = 0; 2979 2980 /* first compile the schemas if possible */ 2981 ctxt = xmlSchemaNewParserCtxt(filename); 2982 xmlSchemaSetParserErrors(ctxt, 2983 (xmlSchemaValidityErrorFunc) testErrorHandler, 2984 (xmlSchemaValidityWarningFunc) testErrorHandler, 2985 ctxt); 2986 schemas = xmlSchemaParse(ctxt); 2987 xmlSchemaFreeParserCtxt(ctxt); 2988 2989 /* 2990 * most of the mess is about the output filenames generated by the Makefile 2991 */ 2992 len = strlen(base); 2993 if ((len > 499) || (len < 5)) { 2994 xmlSchemaFree(schemas); 2995 return(-1); 2996 } 2997 len -= 4; /* remove trailing .xsd */ 2998 if (base[len - 2] == '_') { 2999 len -= 2; /* remove subtest number */ 3000 } 3001 if (base[len - 2] == '_') { 3002 len -= 2; /* remove subtest number */ 3003 } 3004 memcpy(prefix, base, len); 3005 prefix[len] = 0; 3006 3007 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix); 3008 pattern[499] = 0; 3009 3010 if (base[len] == '_') { 3011 len += 2; 3012 memcpy(prefix, base, len); 3013 prefix[len] = 0; 3014 } 3015 3016 globbuf.gl_offs = 0; 3017 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 3018 for (i = 0;i < globbuf.gl_pathc;i++) { 3019 testErrorsSize = 0; 3020 testErrors[0] = 0; 3021 instance = globbuf.gl_pathv[i]; 3022 base2 = baseFilename(instance); 3023 len = strlen(base2); 3024 if ((len > 6) && (base2[len - 6] == '_')) { 3025 count = base2[len - 5]; 3026 snprintf(result, 499, "result/schemas/%s_%c", 3027 prefix, count); 3028 result[499] = 0; 3029 snprintf(err, 499, "result/schemas/%s_%c.err", 3030 prefix, count); 3031 err[499] = 0; 3032 } else { 3033 fprintf(stderr, "don't know how to process %s\n", instance); 3034 continue; 3035 } 3036 if (schemas == NULL) { 3037 } else { 3038 nb_tests++; 3039 ret = schemasOneTest(filename, instance, result, err, 3040 options, schemas); 3041 if (ret != 0) 3042 res = ret; 3043 } 3044 } 3045 globfree(&globbuf); 3046 xmlSchemaFree(schemas); 3047 3048 return(res); 3049 } 3050 3051 /************************************************************************ 3052 * * 3053 * Schemas tests * 3054 * * 3055 ************************************************************************/ 3056 static int 3057 rngOneTest(const char *sch, 3058 const char *filename, 3059 const char *result, 3060 const char *err, 3061 int options, 3062 xmlRelaxNGPtr schemas) { 3063 xmlDocPtr doc; 3064 xmlRelaxNGValidCtxtPtr ctxt; 3065 int ret = 0; 3066 char *temp; 3067 FILE *schemasOutput; 3068 3069 doc = xmlReadFile(filename, NULL, options); 3070 if (doc == NULL) { 3071 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); 3072 return(-1); 3073 } 3074 3075 temp = resultFilename(result, "", ".res"); 3076 if (temp == NULL) { 3077 fprintf(stderr, "Out of memory\n"); 3078 fatalError(); 3079 } 3080 schemasOutput = fopen(temp, "wb"); 3081 if (schemasOutput == NULL) { 3082 fprintf(stderr, "failed to open output file %s\n", temp); 3083 xmlFreeDoc(doc); 3084 free(temp); 3085 return(-1); 3086 } 3087 3088 ctxt = xmlRelaxNGNewValidCtxt(schemas); 3089 xmlRelaxNGSetValidErrors(ctxt, 3090 (xmlRelaxNGValidityErrorFunc) testErrorHandler, 3091 (xmlRelaxNGValidityWarningFunc) testErrorHandler, 3092 ctxt); 3093 ret = xmlRelaxNGValidateDoc(ctxt, doc); 3094 if (ret == 0) { 3095 testErrorHandler(NULL, "%s validates\n", filename); 3096 } else if (ret > 0) { 3097 testErrorHandler(NULL, "%s fails to validate\n", filename); 3098 } else { 3099 testErrorHandler(NULL, "%s validation generated an internal error\n", 3100 filename); 3101 } 3102 fclose(schemasOutput); 3103 if (result) { 3104 if (compareFiles(temp, result)) { 3105 fprintf(stderr, "Result for %s on %s failed\n", filename, sch); 3106 ret = 1; 3107 } 3108 } 3109 unlink(temp); 3110 free(temp); 3111 3112 if (err != NULL) { 3113 if (compareFileMem(err, testErrors, testErrorsSize)) { 3114 fprintf(stderr, "Error for %s on %s failed\n", filename, sch); 3115 ret = 1; 3116 printf("%s", testErrors); 3117 } 3118 } 3119 3120 3121 xmlRelaxNGFreeValidCtxt(ctxt); 3122 xmlFreeDoc(doc); 3123 return(ret); 3124 } 3125 /** 3126 * rngTest: 3127 * @filename: the schemas file 3128 * @result: the file with expected result 3129 * @err: the file with error messages 3130 * 3131 * Parse an RNG schemas and then apply it to the related .xml 3132 * 3133 * Returns 0 in case of success, an error code otherwise 3134 */ 3135 static int 3136 rngTest(const char *filename, 3137 const char *resul ATTRIBUTE_UNUSED, 3138 const char *errr ATTRIBUTE_UNUSED, 3139 int options) { 3140 const char *base = baseFilename(filename); 3141 const char *base2; 3142 const char *instance; 3143 xmlRelaxNGParserCtxtPtr ctxt; 3144 xmlRelaxNGPtr schemas; 3145 int res = 0, len, ret; 3146 char pattern[500]; 3147 char prefix[500]; 3148 char result[500]; 3149 char err[500]; 3150 glob_t globbuf; 3151 size_t i; 3152 char count = 0; 3153 3154 /* first compile the schemas if possible */ 3155 ctxt = xmlRelaxNGNewParserCtxt(filename); 3156 xmlRelaxNGSetParserErrors(ctxt, 3157 (xmlRelaxNGValidityErrorFunc) testErrorHandler, 3158 (xmlRelaxNGValidityWarningFunc) testErrorHandler, 3159 ctxt); 3160 schemas = xmlRelaxNGParse(ctxt); 3161 xmlRelaxNGFreeParserCtxt(ctxt); 3162 3163 /* 3164 * most of the mess is about the output filenames generated by the Makefile 3165 */ 3166 len = strlen(base); 3167 if ((len > 499) || (len < 5)) { 3168 xmlRelaxNGFree(schemas); 3169 return(-1); 3170 } 3171 len -= 4; /* remove trailing .rng */ 3172 memcpy(prefix, base, len); 3173 prefix[len] = 0; 3174 3175 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); 3176 pattern[499] = 0; 3177 3178 globbuf.gl_offs = 0; 3179 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 3180 for (i = 0;i < globbuf.gl_pathc;i++) { 3181 testErrorsSize = 0; 3182 testErrors[0] = 0; 3183 instance = globbuf.gl_pathv[i]; 3184 base2 = baseFilename(instance); 3185 len = strlen(base2); 3186 if ((len > 6) && (base2[len - 6] == '_')) { 3187 count = base2[len - 5]; 3188 snprintf(result, 499, "result/relaxng/%s_%c", 3189 prefix, count); 3190 result[499] = 0; 3191 snprintf(err, 499, "result/relaxng/%s_%c.err", 3192 prefix, count); 3193 err[499] = 0; 3194 } else { 3195 fprintf(stderr, "don't know how to process %s\n", instance); 3196 continue; 3197 } 3198 if (schemas == NULL) { 3199 } else { 3200 nb_tests++; 3201 ret = rngOneTest(filename, instance, result, err, 3202 options, schemas); 3203 if (res != 0) 3204 ret = res; 3205 } 3206 } 3207 globfree(&globbuf); 3208 xmlRelaxNGFree(schemas); 3209 3210 return(res); 3211 } 3212 3213 #ifdef LIBXML_READER_ENABLED 3214 /** 3215 * rngStreamTest: 3216 * @filename: the schemas file 3217 * @result: the file with expected result 3218 * @err: the file with error messages 3219 * 3220 * Parse a set of files with streaming, applying an RNG schemas 3221 * 3222 * Returns 0 in case of success, an error code otherwise 3223 */ 3224 static int 3225 rngStreamTest(const char *filename, 3226 const char *resul ATTRIBUTE_UNUSED, 3227 const char *errr ATTRIBUTE_UNUSED, 3228 int options) { 3229 const char *base = baseFilename(filename); 3230 const char *base2; 3231 const char *instance; 3232 int res = 0, len, ret; 3233 char pattern[500]; 3234 char prefix[500]; 3235 char result[500]; 3236 char err[500]; 3237 glob_t globbuf; 3238 size_t i; 3239 char count = 0; 3240 xmlTextReaderPtr reader; 3241 int disable_err = 0; 3242 3243 /* 3244 * most of the mess is about the output filenames generated by the Makefile 3245 */ 3246 len = strlen(base); 3247 if ((len > 499) || (len < 5)) { 3248 fprintf(stderr, "len(base) == %d !\n", len); 3249 return(-1); 3250 } 3251 len -= 4; /* remove trailing .rng */ 3252 memcpy(prefix, base, len); 3253 prefix[len] = 0; 3254 3255 /* 3256 * strictly unifying the error messages is nearly impossible this 3257 * hack is also done in the Makefile 3258 */ 3259 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) || 3260 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377"))) 3261 disable_err = 1; 3262 3263 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); 3264 pattern[499] = 0; 3265 3266 globbuf.gl_offs = 0; 3267 glob(pattern, GLOB_DOOFFS, NULL, &globbuf); 3268 for (i = 0;i < globbuf.gl_pathc;i++) { 3269 testErrorsSize = 0; 3270 testErrors[0] = 0; 3271 instance = globbuf.gl_pathv[i]; 3272 base2 = baseFilename(instance); 3273 len = strlen(base2); 3274 if ((len > 6) && (base2[len - 6] == '_')) { 3275 count = base2[len - 5]; 3276 snprintf(result, 499, "result/relaxng/%s_%c", 3277 prefix, count); 3278 result[499] = 0; 3279 snprintf(err, 499, "result/relaxng/%s_%c.err", 3280 prefix, count); 3281 err[499] = 0; 3282 } else { 3283 fprintf(stderr, "don't know how to process %s\n", instance); 3284 continue; 3285 } 3286 reader = xmlReaderForFile(instance, NULL, options); 3287 if (reader == NULL) { 3288 fprintf(stderr, "Failed to build reder for %s\n", instance); 3289 } 3290 if (disable_err == 1) 3291 ret = streamProcessTest(instance, result, NULL, reader, filename); 3292 else 3293 ret = streamProcessTest(instance, result, err, reader, filename); 3294 xmlFreeTextReader(reader); 3295 if (ret != 0) { 3296 fprintf(stderr, "instance %s failed\n", instance); 3297 res = ret; 3298 } 3299 } 3300 globfree(&globbuf); 3301 3302 return(res); 3303 } 3304 #endif /* READER */ 3305 3306 #endif 3307 3308 #ifdef LIBXML_PATTERN_ENABLED 3309 #ifdef LIBXML_READER_ENABLED 3310 /************************************************************************ 3311 * * 3312 * Patterns tests * 3313 * * 3314 ************************************************************************/ 3315 static void patternNode(FILE *out, xmlTextReaderPtr reader, 3316 const char *pattern, xmlPatternPtr patternc, 3317 xmlStreamCtxtPtr patstream) { 3318 xmlChar *path = NULL; 3319 int match = -1; 3320 int type, empty; 3321 3322 type = xmlTextReaderNodeType(reader); 3323 empty = xmlTextReaderIsEmptyElement(reader); 3324 3325 if (type == XML_READER_TYPE_ELEMENT) { 3326 /* do the check only on element start */ 3327 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader)); 3328 3329 if (match) { 3330 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader)); 3331 fprintf(out, "Node %s matches pattern %s\n", path, pattern); 3332 } 3333 } 3334 if (patstream != NULL) { 3335 int ret; 3336 3337 if (type == XML_READER_TYPE_ELEMENT) { 3338 ret = xmlStreamPush(patstream, 3339 xmlTextReaderConstLocalName(reader), 3340 xmlTextReaderConstNamespaceUri(reader)); 3341 if (ret < 0) { 3342 fprintf(out, "xmlStreamPush() failure\n"); 3343 xmlFreeStreamCtxt(patstream); 3344 patstream = NULL; 3345 } else if (ret != match) { 3346 if (path == NULL) { 3347 path = xmlGetNodePath( 3348 xmlTextReaderCurrentNode(reader)); 3349 } 3350 fprintf(out, 3351 "xmlPatternMatch and xmlStreamPush disagree\n"); 3352 fprintf(out, 3353 " pattern %s node %s\n", 3354 pattern, path); 3355 } 3356 3357 3358 } 3359 if ((type == XML_READER_TYPE_END_ELEMENT) || 3360 ((type == XML_READER_TYPE_ELEMENT) && (empty))) { 3361 ret = xmlStreamPop(patstream); 3362 if (ret < 0) { 3363 fprintf(out, "xmlStreamPop() failure\n"); 3364 xmlFreeStreamCtxt(patstream); 3365 patstream = NULL; 3366 } 3367 } 3368 } 3369 if (path != NULL) 3370 xmlFree(path); 3371 } 3372 3373 /** 3374 * patternTest: 3375 * @filename: the schemas file 3376 * @result: the file with expected result 3377 * @err: the file with error messages 3378 * 3379 * Parse a set of files with streaming, applying an RNG schemas 3380 * 3381 * Returns 0 in case of success, an error code otherwise 3382 */ 3383 static int 3384 patternTest(const char *filename, 3385 const char *resul ATTRIBUTE_UNUSED, 3386 const char *err ATTRIBUTE_UNUSED, 3387 int options) { 3388 xmlPatternPtr patternc = NULL; 3389 xmlStreamCtxtPtr patstream = NULL; 3390 FILE *o, *f; 3391 char str[1024]; 3392 char xml[500]; 3393 char result[500]; 3394 int len, i; 3395 int ret = 0, res; 3396 char *temp; 3397 xmlTextReaderPtr reader; 3398 xmlDocPtr doc; 3399 3400 len = strlen(filename); 3401 len -= 4; 3402 memcpy(xml, filename, len); 3403 xml[len] = 0; 3404 snprintf(result, 499, "result/pattern/%s", baseFilename(xml)); 3405 result[499] = 0; 3406 memcpy(xml + len, ".xml", 5); 3407 3408 if (!checkTestFile(xml)) { 3409 fprintf(stderr, "Missing xml file %s\n", xml); 3410 return(-1); 3411 } 3412 if (!checkTestFile(result)) { 3413 fprintf(stderr, "Missing result file %s\n", result); 3414 return(-1); 3415 } 3416 f = fopen(filename, "rb"); 3417 if (f == NULL) { 3418 fprintf(stderr, "Failed to open %s\n", filename); 3419 return(-1); 3420 } 3421 temp = resultFilename(filename, "", ".res"); 3422 if (temp == NULL) { 3423 fprintf(stderr, "Out of memory\n"); 3424 fatalError(); 3425 } 3426 o = fopen(temp, "wb"); 3427 if (o == NULL) { 3428 fprintf(stderr, "failed to open output file %s\n", temp); 3429 fclose(f); 3430 free(temp); 3431 return(-1); 3432 } 3433 while (1) { 3434 /* 3435 * read one line in string buffer. 3436 */ 3437 if (fgets (&str[0], sizeof (str) - 1, f) == NULL) 3438 break; 3439 3440 /* 3441 * remove the ending spaces 3442 */ 3443 i = strlen(str); 3444 while ((i > 0) && 3445 ((str[i - 1] == '\n') || (str[i - 1] == '\r') || 3446 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { 3447 i--; 3448 str[i] = 0; 3449 } 3450 doc = xmlReadFile(xml, NULL, options); 3451 if (doc == NULL) { 3452 fprintf(stderr, "Failed to parse %s\n", xml); 3453 ret = 1; 3454 } else { 3455 xmlNodePtr root; 3456 const xmlChar *namespaces[22]; 3457 int j; 3458 xmlNsPtr ns; 3459 3460 root = xmlDocGetRootElement(doc); 3461 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) { 3462 namespaces[j++] = ns->href; 3463 namespaces[j++] = ns->prefix; 3464 } 3465 namespaces[j++] = NULL; 3466 namespaces[j++] = NULL; 3467 3468 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict, 3469 0, &namespaces[0]); 3470 if (patternc == NULL) { 3471 testErrorHandler(NULL, 3472 "Pattern %s failed to compile\n", str); 3473 xmlFreeDoc(doc); 3474 ret = 1; 3475 continue; 3476 } 3477 patstream = xmlPatternGetStreamCtxt(patternc); 3478 if (patstream != NULL) { 3479 ret = xmlStreamPush(patstream, NULL, NULL); 3480 if (ret < 0) { 3481 fprintf(stderr, "xmlStreamPush() failure\n"); 3482 xmlFreeStreamCtxt(patstream); 3483 patstream = NULL; 3484 } 3485 } 3486 nb_tests++; 3487 3488 reader = xmlReaderWalker(doc); 3489 res = xmlTextReaderRead(reader); 3490 while (res == 1) { 3491 patternNode(o, reader, str, patternc, patstream); 3492 res = xmlTextReaderRead(reader); 3493 } 3494 if (res != 0) { 3495 fprintf(o, "%s : failed to parse\n", filename); 3496 } 3497 xmlFreeTextReader(reader); 3498 xmlFreeDoc(doc); 3499 xmlFreeStreamCtxt(patstream); 3500 patstream = NULL; 3501 xmlFreePattern(patternc); 3502 3503 } 3504 } 3505 3506 fclose(f); 3507 fclose(o); 3508 3509 ret = compareFiles(temp, result); 3510 if (ret) { 3511 fprintf(stderr, "Result for %s failed\n", filename); 3512 ret = 1; 3513 } 3514 unlink(temp); 3515 free(temp); 3516 return(ret); 3517 } 3518 #endif /* READER */ 3519 #endif /* PATTERN */ 3520 #ifdef LIBXML_C14N_ENABLED 3521 /************************************************************************ 3522 * * 3523 * Canonicalization tests * 3524 * * 3525 ************************************************************************/ 3526 static xmlXPathObjectPtr 3527 load_xpath_expr (xmlDocPtr parent_doc, const char* filename) { 3528 xmlXPathObjectPtr xpath; 3529 xmlDocPtr doc; 3530 xmlChar *expr; 3531 xmlXPathContextPtr ctx; 3532 xmlNodePtr node; 3533 xmlNsPtr ns; 3534 3535 /* 3536 * load XPath expr as a file 3537 */ 3538 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; 3539 xmlSubstituteEntitiesDefault(1); 3540 3541 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT); 3542 if (doc == NULL) { 3543 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename); 3544 return(NULL); 3545 } 3546 3547 /* 3548 * Check the document is of the right kind 3549 */ 3550 if(xmlDocGetRootElement(doc) == NULL) { 3551 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename); 3552 xmlFreeDoc(doc); 3553 return(NULL); 3554 } 3555 3556 node = doc->children; 3557 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) { 3558 node = node->next; 3559 } 3560 3561 if(node == NULL) { 3562 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename); 3563 xmlFreeDoc(doc); 3564 return(NULL); 3565 } 3566 3567 expr = xmlNodeGetContent(node); 3568 if(expr == NULL) { 3569 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename); 3570 xmlFreeDoc(doc); 3571 return(NULL); 3572 } 3573 3574 ctx = xmlXPathNewContext(parent_doc); 3575 if(ctx == NULL) { 3576 fprintf(stderr,"Error: unable to create new context\n"); 3577 xmlFree(expr); 3578 xmlFreeDoc(doc); 3579 return(NULL); 3580 } 3581 3582 /* 3583 * Register namespaces 3584 */ 3585 ns = node->nsDef; 3586 while(ns != NULL) { 3587 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) { 3588 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href); 3589 xmlFree(expr); 3590 xmlXPathFreeContext(ctx); 3591 xmlFreeDoc(doc); 3592 return(NULL); 3593 } 3594 ns = ns->next; 3595 } 3596 3597 /* 3598 * Evaluate xpath 3599 */ 3600 xpath = xmlXPathEvalExpression(expr, ctx); 3601 if(xpath == NULL) { 3602 fprintf(stderr,"Error: unable to evaluate xpath expression\n"); 3603 xmlFree(expr); 3604 xmlXPathFreeContext(ctx); 3605 xmlFreeDoc(doc); 3606 return(NULL); 3607 } 3608 3609 /* print_xpath_nodes(xpath->nodesetval); */ 3610 3611 xmlFree(expr); 3612 xmlXPathFreeContext(ctx); 3613 xmlFreeDoc(doc); 3614 return(xpath); 3615 } 3616 3617 /* 3618 * Macro used to grow the current buffer. 3619 */ 3620 #define xxx_growBufferReentrant() { \ 3621 buffer_size *= 2; \ 3622 buffer = (xmlChar **) \ 3623 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \ 3624 if (buffer == NULL) { \ 3625 perror("realloc failed"); \ 3626 return(NULL); \ 3627 } \ 3628 } 3629 3630 static xmlChar ** 3631 parse_list(xmlChar *str) { 3632 xmlChar **buffer; 3633 xmlChar **out = NULL; 3634 int buffer_size = 0; 3635 int len; 3636 3637 if(str == NULL) { 3638 return(NULL); 3639 } 3640 3641 len = xmlStrlen(str); 3642 if((str[0] == '\'') && (str[len - 1] == '\'')) { 3643 str[len - 1] = '\0'; 3644 str++; 3645 len -= 2; 3646 } 3647 /* 3648 * allocate an translation buffer. 3649 */ 3650 buffer_size = 1000; 3651 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*)); 3652 if (buffer == NULL) { 3653 perror("malloc failed"); 3654 return(NULL); 3655 } 3656 out = buffer; 3657 3658 while(*str != '\0') { 3659 if (out - buffer > buffer_size - 10) { 3660 int indx = out - buffer; 3661 3662 xxx_growBufferReentrant(); 3663 out = &buffer[indx]; 3664 } 3665 (*out++) = str; 3666 while(*str != ',' && *str != '\0') ++str; 3667 if(*str == ',') *(str++) = '\0'; 3668 } 3669 (*out) = NULL; 3670 return buffer; 3671 } 3672 3673 static int 3674 c14nRunTest(const char* xml_filename, int with_comments, int exclusive, 3675 const char* xpath_filename, const char *ns_filename, 3676 const char* result_file) { 3677 xmlDocPtr doc; 3678 xmlXPathObjectPtr xpath = NULL; 3679 xmlChar *result = NULL; 3680 int ret; 3681 xmlChar **inclusive_namespaces = NULL; 3682 const char *nslist = NULL; 3683 int nssize; 3684 3685 3686 /* 3687 * build an XML tree from a the file; we need to add default 3688 * attributes and resolve all character and entities references 3689 */ 3690 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; 3691 xmlSubstituteEntitiesDefault(1); 3692 3693 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT); 3694 if (doc == NULL) { 3695 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename); 3696 return(-1); 3697 } 3698 3699 /* 3700 * Check the document is of the right kind 3701 */ 3702 if(xmlDocGetRootElement(doc) == NULL) { 3703 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename); 3704 xmlFreeDoc(doc); 3705 return(-1); 3706 } 3707 3708 /* 3709 * load xpath file if specified 3710 */ 3711 if(xpath_filename) { 3712 xpath = load_xpath_expr(doc, xpath_filename); 3713 if(xpath == NULL) { 3714 fprintf(stderr,"Error: unable to evaluate xpath expression\n"); 3715 xmlFreeDoc(doc); 3716 return(-1); 3717 } 3718 } 3719 3720 if (ns_filename != NULL) { 3721 if (loadMem(ns_filename, &nslist, &nssize)) { 3722 fprintf(stderr,"Error: unable to evaluate xpath expression\n"); 3723 if(xpath != NULL) xmlXPathFreeObject(xpath); 3724 xmlFreeDoc(doc); 3725 return(-1); 3726 } 3727 inclusive_namespaces = parse_list((xmlChar *) nslist); 3728 } 3729 3730 /* 3731 * Canonical form 3732 */ 3733 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */ 3734 ret = xmlC14NDocDumpMemory(doc, 3735 (xpath) ? xpath->nodesetval : NULL, 3736 exclusive, inclusive_namespaces, 3737 with_comments, &result); 3738 if (ret >= 0) { 3739 if(result != NULL) { 3740 if (compareFileMem(result_file, (const char *) result, ret)) { 3741 fprintf(stderr, "Result mismatch for %s\n", xml_filename); 3742 ret = -1; 3743 } 3744 } 3745 } else { 3746 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret); 3747 ret = -1; 3748 } 3749 3750 /* 3751 * Cleanup 3752 */ 3753 if (result != NULL) xmlFree(result); 3754 if(xpath != NULL) xmlXPathFreeObject(xpath); 3755 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces); 3756 if (nslist != NULL) free((char *) nslist); 3757 xmlFreeDoc(doc); 3758 3759 return(ret); 3760 } 3761 3762 static int 3763 c14nCommonTest(const char *filename, int with_comments, int exclusive, 3764 const char *subdir) { 3765 char buf[500]; 3766 char prefix[500]; 3767 const char *base; 3768 int len; 3769 char *result = NULL; 3770 char *xpath = NULL; 3771 char *ns = NULL; 3772 int ret = 0; 3773 3774 base = baseFilename(filename); 3775 len = strlen(base); 3776 len -= 4; 3777 memcpy(prefix, base, len); 3778 prefix[len] = 0; 3779 3780 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix); 3781 if (!checkTestFile(buf)) { 3782 fprintf(stderr, "Missing result file %s", buf); 3783 return(-1); 3784 } 3785 result = strdup(buf); 3786 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix); 3787 if (checkTestFile(buf)) { 3788 xpath = strdup(buf); 3789 } 3790 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix); 3791 if (checkTestFile(buf)) { 3792 ns = strdup(buf); 3793 } 3794 3795 nb_tests++; 3796 if (c14nRunTest(filename, with_comments, exclusive, 3797 xpath, ns, result) < 0) 3798 ret = 1; 3799 3800 if (result != NULL) free(result); 3801 if (xpath != NULL) free(xpath); 3802 if (ns != NULL) free(ns); 3803 return(ret); 3804 } 3805 3806 static int 3807 c14nWithCommentTest(const char *filename, 3808 const char *resul ATTRIBUTE_UNUSED, 3809 const char *err ATTRIBUTE_UNUSED, 3810 int options ATTRIBUTE_UNUSED) { 3811 return(c14nCommonTest(filename, 1, 0, "with-comments")); 3812 } 3813 static int 3814 c14nWithoutCommentTest(const char *filename, 3815 const char *resul ATTRIBUTE_UNUSED, 3816 const char *err ATTRIBUTE_UNUSED, 3817 int options ATTRIBUTE_UNUSED) { 3818 return(c14nCommonTest(filename, 0, 0, "without-comments")); 3819 } 3820 static int 3821 c14nExcWithoutCommentTest(const char *filename, 3822 const char *resul ATTRIBUTE_UNUSED, 3823 const char *err ATTRIBUTE_UNUSED, 3824 int options ATTRIBUTE_UNUSED) { 3825 return(c14nCommonTest(filename, 0, 1, "exc-without-comments")); 3826 } 3827 #endif 3828 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED) 3829 /************************************************************************ 3830 * * 3831 * Catalog and threads test * 3832 * * 3833 ************************************************************************/ 3834 3835 /* 3836 * mostly a cut and paste from testThreads.c 3837 */ 3838 #define MAX_ARGC 20 3839 3840 static const char *catalog = "test/threads/complex.xml"; 3841 static const char *testfiles[] = { 3842 "test/threads/abc.xml", 3843 "test/threads/acb.xml", 3844 "test/threads/bac.xml", 3845 "test/threads/bca.xml", 3846 "test/threads/cab.xml", 3847 "test/threads/cba.xml", 3848 "test/threads/invalid.xml", 3849 }; 3850 3851 static const char *Okay = "OK"; 3852 static const char *Failed = "Failed"; 3853 3854 #ifndef xmlDoValidityCheckingDefaultValue 3855 #error xmlDoValidityCheckingDefaultValue is not a macro 3856 #endif 3857 #ifndef xmlGenericErrorContext 3858 #error xmlGenericErrorContext is not a macro 3859 #endif 3860 3861 static void * 3862 thread_specific_data(void *private_data) 3863 { 3864 xmlDocPtr myDoc; 3865 const char *filename = (const char *) private_data; 3866 int okay = 1; 3867 3868 if (!strcmp(filename, "test/threads/invalid.xml")) { 3869 xmlDoValidityCheckingDefaultValue = 0; 3870 xmlGenericErrorContext = stdout; 3871 } else { 3872 xmlDoValidityCheckingDefaultValue = 1; 3873 xmlGenericErrorContext = stderr; 3874 } 3875 myDoc = xmlParseFile(filename); 3876 if (myDoc) { 3877 xmlFreeDoc(myDoc); 3878 } else { 3879 printf("parse failed\n"); 3880 okay = 0; 3881 } 3882 if (!strcmp(filename, "test/threads/invalid.xml")) { 3883 if (xmlDoValidityCheckingDefaultValue != 0) { 3884 printf("ValidityCheckingDefaultValue override failed\n"); 3885 okay = 0; 3886 } 3887 if (xmlGenericErrorContext != stdout) { 3888 printf("xmlGenericErrorContext override failed\n"); 3889 okay = 0; 3890 } 3891 } else { 3892 if (xmlDoValidityCheckingDefaultValue != 1) { 3893 printf("ValidityCheckingDefaultValue override failed\n"); 3894 okay = 0; 3895 } 3896 if (xmlGenericErrorContext != stderr) { 3897 printf("xmlGenericErrorContext override failed\n"); 3898 okay = 0; 3899 } 3900 } 3901 if (okay == 0) 3902 return ((void *) Failed); 3903 return ((void *) Okay); 3904 } 3905 3906 #if defined(linux) || defined(solaris) || defined(__APPLE_CC__) 3907 3908 #include <pthread.h> 3909 3910 static pthread_t tid[MAX_ARGC]; 3911 3912 static int 3913 testThread(void) 3914 { 3915 unsigned int i, repeat; 3916 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); 3917 void *results[MAX_ARGC]; 3918 int ret; 3919 int res = 0; 3920 3921 xmlInitParser(); 3922 3923 for (repeat = 0; repeat < 500; repeat++) { 3924 xmlLoadCatalog(catalog); 3925 nb_tests++; 3926 3927 for (i = 0; i < num_threads; i++) { 3928 results[i] = NULL; 3929 tid[i] = (pthread_t) - 1; 3930 } 3931 3932 for (i = 0; i < num_threads; i++) { 3933 ret = pthread_create(&tid[i], 0, thread_specific_data, 3934 (void *) testfiles[i]); 3935 if (ret != 0) { 3936 fprintf(stderr, "pthread_create failed\n"); 3937 return (1); 3938 } 3939 } 3940 for (i = 0; i < num_threads; i++) { 3941 ret = pthread_join(tid[i], &results[i]); 3942 if (ret != 0) { 3943 fprintf(stderr, "pthread_join failed\n"); 3944 return (1); 3945 } 3946 } 3947 3948 xmlCatalogCleanup(); 3949 for (i = 0; i < num_threads; i++) 3950 if (results[i] != (void *) Okay) { 3951 fprintf(stderr, "Thread %d handling %s failed\n", 3952 i, testfiles[i]); 3953 res = 1; 3954 } 3955 } 3956 return (res); 3957 } 3958 3959 #elif defined WIN32 3960 #include <windows.h> 3961 #include <string.h> 3962 3963 #define TEST_REPEAT_COUNT 500 3964 3965 static HANDLE tid[MAX_ARGC]; 3966 3967 static DWORD WINAPI 3968 win32_thread_specific_data(void *private_data) 3969 { 3970 return((DWORD) thread_specific_data(private_data)); 3971 } 3972 3973 static int 3974 testThread(void) 3975 { 3976 unsigned int i, repeat; 3977 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); 3978 DWORD results[MAX_ARGC]; 3979 BOOL ret; 3980 int res = 0; 3981 3982 xmlInitParser(); 3983 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) { 3984 xmlLoadCatalog(catalog); 3985 nb_tests++; 3986 3987 for (i = 0; i < num_threads; i++) { 3988 results[i] = 0; 3989 tid[i] = (HANDLE) - 1; 3990 } 3991 3992 for (i = 0; i < num_threads; i++) { 3993 DWORD useless; 3994 3995 tid[i] = CreateThread(NULL, 0, 3996 win32_thread_specific_data, 3997 (void *) testfiles[i], 0, 3998 &useless); 3999 if (tid[i] == NULL) { 4000 fprintf(stderr, "CreateThread failed\n"); 4001 return(1); 4002 } 4003 } 4004 4005 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) == 4006 WAIT_FAILED) { 4007 fprintf(stderr, "WaitForMultipleObjects failed\n"); 4008 return(1); 4009 } 4010 4011 for (i = 0; i < num_threads; i++) { 4012 ret = GetExitCodeThread(tid[i], &results[i]); 4013 if (ret == 0) { 4014 fprintf(stderr, "GetExitCodeThread failed\n"); 4015 return(1); 4016 } 4017 CloseHandle(tid[i]); 4018 } 4019 4020 xmlCatalogCleanup(); 4021 for (i = 0; i < num_threads; i++) { 4022 if (results[i] != (DWORD) Okay) { 4023 fprintf(stderr, "Thread %d handling %s failed\n", 4024 i, testfiles[i]); 4025 res = 1; 4026 } 4027 } 4028 } 4029 4030 return (res); 4031 } 4032 4033 #elif defined __BEOS__ 4034 #include <OS.h> 4035 4036 static thread_id tid[MAX_ARGC]; 4037 4038 static int 4039 testThread(void) 4040 { 4041 unsigned int i, repeat; 4042 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); 4043 void *results[MAX_ARGC]; 4044 status_t ret; 4045 int res = 0; 4046 4047 xmlInitParser(); 4048 for (repeat = 0; repeat < 500; repeat++) { 4049 xmlLoadCatalog(catalog); 4050 for (i = 0; i < num_threads; i++) { 4051 results[i] = NULL; 4052 tid[i] = (thread_id) - 1; 4053 } 4054 for (i = 0; i < num_threads; i++) { 4055 tid[i] = 4056 spawn_thread(thread_specific_data, "xmlTestThread", 4057 B_NORMAL_PRIORITY, (void *) testfiles[i]); 4058 if (tid[i] < B_OK) { 4059 fprintf(stderr, "beos_thread_create failed\n"); 4060 return (1); 4061 } 4062 printf("beos_thread_create %d -> %d\n", i, tid[i]); 4063 } 4064 for (i = 0; i < num_threads; i++) { 4065 ret = wait_for_thread(tid[i], &results[i]); 4066 printf("beos_thread_wait %d -> %d\n", i, ret); 4067 if (ret != B_OK) { 4068 fprintf(stderr, "beos_thread_wait failed\n"); 4069 return (1); 4070 } 4071 } 4072 4073 xmlCatalogCleanup(); 4074 ret = B_OK; 4075 for (i = 0; i < num_threads; i++) 4076 if (results[i] != (void *) Okay) { 4077 printf("Thread %d handling %s failed\n", i, testfiles[i]); 4078 ret = B_ERROR; 4079 } 4080 } 4081 if (ret != B_OK) 4082 return(1); 4083 return (0); 4084 } 4085 #else 4086 static int 4087 testThread(void) 4088 { 4089 fprintf(stderr, 4090 "Specific platform thread support not detected\n"); 4091 return (-1); 4092 } 4093 #endif 4094 static int 4095 threadsTest(const char *filename ATTRIBUTE_UNUSED, 4096 const char *resul ATTRIBUTE_UNUSED, 4097 const char *err ATTRIBUTE_UNUSED, 4098 int options ATTRIBUTE_UNUSED) { 4099 return(testThread()); 4100 } 4101 #endif 4102 /************************************************************************ 4103 * * 4104 * Tests Descriptions * 4105 * * 4106 ************************************************************************/ 4107 4108 static 4109 testDesc testDescriptions[] = { 4110 { "XML regression tests" , 4111 oldParseTest, "./test/*", "result/", "", NULL, 4112 0 }, 4113 { "XML regression tests on memory" , 4114 memParseTest, "./test/*", "result/", "", NULL, 4115 0 }, 4116 { "XML entity subst regression tests" , 4117 noentParseTest, "./test/*", "result/noent/", "", NULL, 4118 XML_PARSE_NOENT }, 4119 { "XML Namespaces regression tests", 4120 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err", 4121 0 }, 4122 { "Error cases regression tests", 4123 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err", 4124 0 }, 4125 #ifdef LIBXML_READER_ENABLED 4126 { "Error cases stream regression tests", 4127 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str", 4128 0 }, 4129 { "Reader regression tests", 4130 streamParseTest, "./test/*", "result/", ".rdr", NULL, 4131 0 }, 4132 { "Reader entities substitution regression tests", 4133 streamParseTest, "./test/*", "result/", ".rde", NULL, 4134 XML_PARSE_NOENT }, 4135 { "Reader on memory regression tests", 4136 streamMemParseTest, "./test/*", "result/", ".rdr", NULL, 4137 0 }, 4138 { "Walker regression tests", 4139 walkerParseTest, "./test/*", "result/", ".rdr", NULL, 4140 0 }, 4141 #endif 4142 #ifdef LIBXML_SAX1_ENABLED 4143 { "SAX1 callbacks regression tests" , 4144 saxParseTest, "./test/*", "result/", ".sax", NULL, 4145 XML_PARSE_SAX1 }, 4146 { "SAX2 callbacks regression tests" , 4147 saxParseTest, "./test/*", "result/", ".sax2", NULL, 4148 0 }, 4149 #endif 4150 #ifdef LIBXML_PUSH_ENABLED 4151 { "XML push regression tests" , 4152 pushParseTest, "./test/*", "result/", "", NULL, 4153 0 }, 4154 #endif 4155 #ifdef LIBXML_HTML_ENABLED 4156 { "HTML regression tests" , 4157 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err", 4158 XML_PARSE_HTML }, 4159 #ifdef LIBXML_PUSH_ENABLED 4160 { "Push HTML regression tests" , 4161 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err", 4162 XML_PARSE_HTML }, 4163 #endif 4164 #ifdef LIBXML_SAX1_ENABLED 4165 { "HTML SAX regression tests" , 4166 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL, 4167 XML_PARSE_HTML }, 4168 #endif 4169 #endif 4170 #ifdef LIBXML_VALID_ENABLED 4171 { "Valid documents regression tests" , 4172 errParseTest, "./test/VCM/*", NULL, NULL, NULL, 4173 XML_PARSE_DTDVALID }, 4174 { "Validity checking regression tests" , 4175 errParseTest, "./test/VC/*", "result/VC/", NULL, "", 4176 XML_PARSE_DTDVALID }, 4177 { "General documents valid regression tests" , 4178 errParseTest, "./test/valid/*", "result/valid/", "", ".err", 4179 XML_PARSE_DTDVALID }, 4180 #endif 4181 #ifdef LIBXML_XINCLUDE_ENABLED 4182 { "XInclude regression tests" , 4183 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, 4184 /* Ignore errors at this point ".err", */ 4185 XML_PARSE_XINCLUDE }, 4186 #ifdef LIBXML_READER_ENABLED 4187 { "XInclude xmlReader regression tests", 4188 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", 4189 /* Ignore errors at this point ".err", */ 4190 NULL, XML_PARSE_XINCLUDE }, 4191 #endif 4192 { "XInclude regression tests stripping include nodes" , 4193 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, 4194 /* Ignore errors at this point ".err", */ 4195 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, 4196 #ifdef LIBXML_READER_ENABLED 4197 { "XInclude xmlReader regression tests stripping include nodes", 4198 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", 4199 /* Ignore errors at this point ".err", */ 4200 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, 4201 #endif 4202 #endif 4203 #ifdef LIBXML_XPATH_ENABLED 4204 #ifdef LIBXML_DEBUG_ENABLED 4205 { "XPath expressions regression tests" , 4206 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL, 4207 0 }, 4208 { "XPath document queries regression tests" , 4209 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, 4210 0 }, 4211 #ifdef LIBXML_XPTR_ENABLED 4212 { "XPointer document queries regression tests" , 4213 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, 4214 0 }, 4215 #endif 4216 { "xml:id regression tests" , 4217 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err", 4218 0 }, 4219 #endif 4220 #endif 4221 { "URI parsing tests" , 4222 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL, 4223 0 }, 4224 { "URI base composition tests" , 4225 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL, 4226 0 }, 4227 { "Path URI conversion tests" , 4228 uriPathTest, NULL, NULL, NULL, NULL, 4229 0 }, 4230 #ifdef LIBXML_SCHEMAS_ENABLED 4231 { "Schemas regression tests" , 4232 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL, 4233 0 }, 4234 { "Relax-NG regression tests" , 4235 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL, 4236 XML_PARSE_DTDATTR | XML_PARSE_NOENT }, 4237 #ifdef LIBXML_READER_ENABLED 4238 { "Relax-NG streaming regression tests" , 4239 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL, 4240 XML_PARSE_DTDATTR | XML_PARSE_NOENT }, 4241 #endif 4242 #endif 4243 #ifdef LIBXML_PATTERN_ENABLED 4244 #ifdef LIBXML_READER_ENABLED 4245 { "Pattern regression tests" , 4246 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL, 4247 0 }, 4248 #endif 4249 #endif 4250 #ifdef LIBXML_C14N_ENABLED 4251 { "C14N with comments regression tests" , 4252 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL, 4253 0 }, 4254 { "C14N without comments regression tests" , 4255 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL, 4256 0 }, 4257 { "C14N exclusive without comments regression tests" , 4258 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL, 4259 0 }, 4260 #endif 4261 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED) 4262 { "Catalog and Threads regression tests" , 4263 threadsTest, NULL, NULL, NULL, NULL, 4264 0 }, 4265 #endif 4266 {NULL, NULL, NULL, NULL, NULL, NULL, 0} 4267 }; 4268 4269 /************************************************************************ 4270 * * 4271 * The main code driving the tests * 4272 * * 4273 ************************************************************************/ 4274 4275 static int 4276 launchTests(testDescPtr tst) { 4277 int res = 0, err = 0; 4278 size_t i; 4279 char *result; 4280 char *error; 4281 int mem; 4282 4283 if (tst == NULL) return(-1); 4284 if (tst->in != NULL) { 4285 glob_t globbuf; 4286 4287 globbuf.gl_offs = 0; 4288 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf); 4289 for (i = 0;i < globbuf.gl_pathc;i++) { 4290 if (!checkTestFile(globbuf.gl_pathv[i])) 4291 continue; 4292 if (tst->suffix != NULL) { 4293 result = resultFilename(globbuf.gl_pathv[i], tst->out, 4294 tst->suffix); 4295 if (result == NULL) { 4296 fprintf(stderr, "Out of memory !\n"); 4297 fatalError(); 4298 } 4299 } else { 4300 result = NULL; 4301 } 4302 if (tst->err != NULL) { 4303 error = resultFilename(globbuf.gl_pathv[i], tst->out, 4304 tst->err); 4305 if (error == NULL) { 4306 fprintf(stderr, "Out of memory !\n"); 4307 fatalError(); 4308 } 4309 } else { 4310 error = NULL; 4311 } 4312 if ((result) &&(!checkTestFile(result))) { 4313 fprintf(stderr, "Missing result file %s\n", result); 4314 } else if ((error) &&(!checkTestFile(error))) { 4315 fprintf(stderr, "Missing error file %s\n", error); 4316 } else { 4317 mem = xmlMemUsed(); 4318 extraMemoryFromResolver = 0; 4319 testErrorsSize = 0; 4320 testErrors[0] = 0; 4321 res = tst->func(globbuf.gl_pathv[i], result, error, 4322 tst->options | XML_PARSE_COMPACT); 4323 xmlResetLastError(); 4324 if (res != 0) { 4325 fprintf(stderr, "File %s generated an error\n", 4326 globbuf.gl_pathv[i]); 4327 nb_errors++; 4328 err++; 4329 } 4330 else if (xmlMemUsed() != mem) { 4331 if ((xmlMemUsed() != mem) && 4332 (extraMemoryFromResolver == 0)) { 4333 fprintf(stderr, "File %s leaked %d bytes\n", 4334 globbuf.gl_pathv[i], xmlMemUsed() - mem); 4335 nb_leaks++; 4336 err++; 4337 } 4338 } 4339 testErrorsSize = 0; 4340 } 4341 if (result) 4342 free(result); 4343 if (error) 4344 free(error); 4345 } 4346 globfree(&globbuf); 4347 } else { 4348 testErrorsSize = 0; 4349 testErrors[0] = 0; 4350 extraMemoryFromResolver = 0; 4351 res = tst->func(NULL, NULL, NULL, tst->options); 4352 if (res != 0) { 4353 nb_errors++; 4354 err++; 4355 } 4356 } 4357 return(err); 4358 } 4359 4360 static int verbose = 0; 4361 static int tests_quiet = 0; 4362 4363 static int 4364 runtest(int i) { 4365 int ret = 0, res; 4366 int old_errors, old_tests, old_leaks; 4367 4368 old_errors = nb_errors; 4369 old_tests = nb_tests; 4370 old_leaks = nb_leaks; 4371 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL)) 4372 printf("## %s\n", testDescriptions[i].desc); 4373 res = launchTests(&testDescriptions[i]); 4374 if (res != 0) 4375 ret++; 4376 if (verbose) { 4377 if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) 4378 printf("Ran %d tests, no errors\n", nb_tests - old_tests); 4379 else 4380 printf("Ran %d tests, %d errors, %d leaks\n", 4381 nb_tests - old_tests, 4382 nb_errors - old_errors, 4383 nb_leaks - old_leaks); 4384 } 4385 return(ret); 4386 } 4387 4388 int 4389 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { 4390 int i, a, ret = 0; 4391 int subset = 0; 4392 4393 initializeLibxml2(); 4394 4395 for (a = 1; a < argc;a++) { 4396 if (!strcmp(argv[a], "-v")) 4397 verbose = 1; 4398 else if (!strcmp(argv[a], "-quiet")) 4399 tests_quiet = 1; 4400 else { 4401 for (i = 0; testDescriptions[i].func != NULL; i++) { 4402 if (strstr(testDescriptions[i].desc, argv[a])) { 4403 ret += runtest(i); 4404 subset++; 4405 } 4406 } 4407 } 4408 } 4409 if (subset == 0) { 4410 for (i = 0; testDescriptions[i].func != NULL; i++) { 4411 ret += runtest(i); 4412 } 4413 } 4414 if ((nb_errors == 0) && (nb_leaks == 0)) { 4415 ret = 0; 4416 printf("Total %d tests, no errors\n", 4417 nb_tests); 4418 } else { 4419 ret = 1; 4420 printf("Total %d tests, %d errors, %d leaks\n", 4421 nb_tests, nb_errors, nb_leaks); 4422 } 4423 xmlCleanupParser(); 4424 xmlMemoryDump(); 4425 4426 return(ret); 4427 } 4428 4429 #else /* ! LIBXML_OUTPUT_ENABLED */ 4430 int 4431 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { 4432 fprintf(stderr, "runtest requires output to be enabled in libxml2\n"); 4433 return(1); 4434 } 4435 #endif