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