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