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