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