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