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