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