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