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