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