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