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