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