cleanups, logfile and portability fixed a memory leak Daniel

* runsuite.c runtest.c: cleanups, logfile and portability
* xmllint.c: fixed a memory leak
Daniel
diff --git a/runsuite.c b/runsuite.c
index e9fcc0c..da63e26 100644
--- a/runsuite.c
+++ b/runsuite.c
@@ -6,14 +6,15 @@
  * daniel@veillard.com
  */
 
+#if !defined(_WIN32) || defined(__CYGWIN__)
 #include <unistd.h>
+#endif
 #include <string.h>
 #include <stdio.h>
 #include <glob.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <unistd.h>
 
 #include <libxml/parser.h>
 #include <libxml/parserInternals.h>
@@ -29,6 +30,10 @@
 #include <libxml/xmlschemas.h>
 #include <libxml/xmlschemastypes.h>
 
+#define LOGFILE "runsuite.log"
+FILE *logfile = NULL;
+int verbose = 0;
+
 /************************************************************************
  *									*
  *		File name and path utilities				*
@@ -64,6 +69,8 @@
 
 static int nb_tests = 0;
 static int nb_errors = 0;
+static int nb_internals = 0;
+static int nb_schematas = 0;
 static int nb_leaks = 0;
 static long libxmlMemoryAllocatedBase = 0;
 static int extraMemoryFromResolver = 0;
@@ -148,6 +155,23 @@
 static char testErrors[32769];
 static int testErrorsSize = 0;
 
+static void test_log(const char *msg, ...) {
+    va_list args;
+    if (logfile != NULL) {
+        fprintf(logfile, "\n------------\n");
+	va_start(args, msg);
+	vfprintf(logfile, msg, args);
+	va_end(args);
+	fprintf(logfile, "%s", testErrors);
+	testErrorsSize = 0; testErrors[0] = 0;
+    }
+    if (verbose) {
+	va_start(args, msg);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+    }
+}
+
 static void
 testErrorHandler(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
     va_list args;
@@ -255,7 +279,7 @@
  ************************************************************************/
 
 static int 
-xsdIncorectTestCase(int verbose, xmlNodePtr cur) {
+xsdIncorectTestCase(xmlNodePtr cur) {
     xmlNodePtr test;
     xmlBufferPtr buf;
     xmlRelaxNGParserCtxtPtr pctxt;
@@ -269,7 +293,7 @@
     
     test = getNext(cur, "./*");
     if (test == NULL) {
-        fprintf(stderr, "Failed to find test in correct line %ld\n",
+        test_log("Failed to find test in correct line %ld\n",
 	        xmlGetLineNo(cur));
         return(1);
     }
@@ -293,10 +317,8 @@
     rng = xmlRelaxNGParse(pctxt);
     xmlRelaxNGFreeParserCtxt(pctxt);
     if (rng != NULL) {
-	if (verbose) {
-	    fprintf(stderr, "Failed to detect incorect RNG line %ld\n",
+	test_log("Failed to detect incorect RNG line %ld\n",
 		    xmlGetLineNo(test));
-	}
         ret = 1;
 	goto done;
     }
@@ -308,7 +330,7 @@
         xmlRelaxNGFree(rng);
     xmlResetLastError();
     if ((memt != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
-	fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
+	test_log("Validation of tests starting line %ld leaked %d\n",
 		xmlGetLineNo(cur), xmlMemUsed() - memt);
 	nb_leaks++;
     }
@@ -320,6 +342,7 @@
     xmlNodePtr test;
     xmlBufferPtr buf;
     xmlChar *name, *content, *res;
+
     buf = xmlBufferCreate();
     if (buf == NULL) {
         fprintf(stderr, "out of memory !\n");
@@ -376,7 +399,7 @@
 }
 
 static int 
-xsdTestCase(int verbose, xmlNodePtr tst) {
+xsdTestCase(xmlNodePtr tst) {
     xmlNodePtr test, tmp, cur;
     xmlBufferPtr buf;
     xmlDocPtr doc = NULL;
@@ -387,6 +410,7 @@
     xmlChar *dtd;
 
     resetEntities();
+    testErrorsSize = 0; testErrors[0] = 0;
 
     tmp = getNext(tst, "./dir[1]");
     if (tmp != NULL) {
@@ -399,7 +423,7 @@
 
     cur = getNext(tst, "./correct[1]");
     if (cur == NULL) {
-        return(xsdIncorectTestCase(verbose, tst));
+        return(xsdIncorectTestCase(tst));
     }
     
     test = getNext(cur, "./*");
@@ -431,7 +455,7 @@
         memt = 0;
 
     if (rng == NULL) {
-        fprintf(stderr, "Failed to parse RNGtest line %ld\n",
+        test_log("Failed to parse RNGtest line %ld\n",
 	        xmlGetLineNo(test));
 	nb_errors++;
         ret = 1;
@@ -462,8 +486,7 @@
             doc = xmlReadMemory((const char *)buf->content, buf->use,
 	                        "test", NULL, 0);
 	    if (doc == NULL) {
-		fprintf(stderr,
-			"Failed to parse valid instance line %ld\n",
+		test_log("Failed to parse valid instance line %ld\n",
 			xmlGetLineNo(tmp));
 		nb_errors++;
 	    } else {
@@ -476,15 +499,11 @@
 		ret = xmlRelaxNGValidateDoc(ctxt, doc);
 		xmlRelaxNGFreeValidCtxt(ctxt);
 		if (ret > 0) {
-		    if (verbose) {
-			fprintf(stderr,
-				"Failed to validate valid instance line %ld\n",
+		    test_log("Failed to validate valid instance line %ld\n",
 				xmlGetLineNo(tmp));
-		    }
 		    nb_errors++;
 		} else if (ret < 0) {
-		    fprintf(stderr,
-		            "Internal error validating instance line %ld\n",
+		    test_log("Internal error validating instance line %ld\n",
 			    xmlGetLineNo(tmp));
 		    nb_errors++;
 		}
@@ -492,7 +511,7 @@
 	    }
 	    xmlResetLastError();
 	    if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
-	        fprintf(stderr, "Validation of instance line %ld leaked %d\n",
+	        test_log("Validation of instance line %ld leaked %d\n",
 		        xmlGetLineNo(tmp), xmlMemUsed() - mem);
 		xmlMemoryDump();
 	        nb_leaks++;
@@ -524,8 +543,7 @@
             doc = xmlReadMemory((const char *)buf->content, buf->use,
 	                        "test", NULL, 0);
 	    if (doc == NULL) {
-		fprintf(stderr,
-			"Failed to parse valid instance line %ld\n",
+		test_log("Failed to parse valid instance line %ld\n",
 			xmlGetLineNo(tmp));
 		nb_errors++;
 	    } else {
@@ -538,15 +556,11 @@
 		ret = xmlRelaxNGValidateDoc(ctxt, doc);
 		xmlRelaxNGFreeValidCtxt(ctxt);
 		if (ret == 0) {
-		    if (verbose) {
-			fprintf(stderr,
-				"Failed to detect invalid instance line %ld\n",
+		    test_log("Failed to detect invalid instance line %ld\n",
 				xmlGetLineNo(tmp));
-		    }
 		    nb_errors++;
 		} else if (ret < 0) {
-		    fprintf(stderr,
-		            "Internal error validating instance line %ld\n",
+		    test_log("Internal error validating instance line %ld\n",
 			    xmlGetLineNo(tmp));
 		    nb_errors++;
 		}
@@ -554,7 +568,7 @@
 	    }
 	    xmlResetLastError();
 	    if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
-	        fprintf(stderr, "Validation of instance line %ld leaked %d\n",
+	        test_log("Validation of instance line %ld leaked %d\n",
 		        xmlGetLineNo(tmp), xmlMemUsed() - mem);
 		xmlMemoryDump();
 	        nb_leaks++;
@@ -570,7 +584,7 @@
         xmlRelaxNGFree(rng);
     xmlResetLastError();
     if ((memt != xmlMemUsed()) && (memt != 0)) {
-	fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
+	test_log("Validation of tests starting line %ld leaked %d\n",
 		xmlGetLineNo(cur), xmlMemUsed() - memt);
 	nb_leaks++;
     }
@@ -578,7 +592,7 @@
 }
 
 static int 
-xsdTestSuite(int verbose, xmlNodePtr cur) {
+xsdTestSuite(xmlNodePtr cur) {
     if (verbose) {
 	xmlChar *doc = getString(cur, "string(documentation)");
 
@@ -589,7 +603,7 @@
     }
     cur = getNext(cur, "./testCase[1]");
     while (cur != NULL) {
-        xsdTestCase(verbose, cur);
+        xsdTestCase(cur);
 	cur = getNext(cur, "following-sibling::testCase[1]");
     }
         
@@ -597,7 +611,7 @@
 }
 
 static int 
-xsdTest(int verbose) {
+xsdTest(void) {
     xmlDocPtr doc;
     xmlNodePtr cur;
     const char *filename = "test/xsdtest/xsdtestsuite.xml";
@@ -624,7 +638,7 @@
 	goto done;
     }
     while (cur != NULL) {
-        xsdTestSuite(verbose, cur);
+        xsdTestSuite(cur);
 	cur = getNext(cur, "following-sibling::testSuite[1]");
     }
 
@@ -635,7 +649,7 @@
 }
 
 static int 
-rngTestSuite(int verbose, xmlNodePtr cur) {
+rngTestSuite(xmlNodePtr cur) {
     if (verbose) {
 	xmlChar *doc = getString(cur, "string(documentation)");
 
@@ -652,7 +666,7 @@
     }
     cur = getNext(cur, "./testSuite[1]");
     while (cur != NULL) {
-        xsdTestSuite(verbose, cur);
+        xsdTestSuite(cur);
 	cur = getNext(cur, "following-sibling::testSuite[1]");
     }
         
@@ -660,7 +674,7 @@
 }
 
 static int 
-rngTest1(int verbose) {
+rngTest1(void) {
     xmlDocPtr doc;
     xmlNodePtr cur;
     const char *filename = "test/relaxng/OASIS/spectest.xml";
@@ -687,7 +701,7 @@
 	goto done;
     }
     while (cur != NULL) {
-        rngTestSuite(verbose, cur);
+        rngTestSuite(cur);
 	cur = getNext(cur, "following-sibling::testSuite[1]");
     }
 
@@ -698,7 +712,7 @@
 }
 
 static int 
-rngTest2(int verbose) {
+rngTest2(void) {
     xmlDocPtr doc;
     xmlNodePtr cur;
     const char *filename = "test/relaxng/testsuite.xml";
@@ -725,7 +739,7 @@
 	goto done;
     }
     while (cur != NULL) {
-        xsdTestSuite(verbose, cur);
+        xsdTestSuite(cur);
 	cur = getNext(cur, "following-sibling::testSuite[1]");
     }
 
@@ -742,7 +756,7 @@
  ************************************************************************/
 
 static int
-xstcTestInstance(int verbose, xmlNodePtr cur, xmlSchemaPtr schemas,
+xstcTestInstance(xmlNodePtr cur, xmlSchemaPtr schemas,
                  const xmlChar *spath, const char *base) {
     xmlChar *href = NULL;
     xmlChar *path = NULL;
@@ -752,13 +766,12 @@
     int ret = 0, mem;
 
     xmlResetLastError();
+    testErrorsSize = 0; testErrors[0] = 0;
     mem = xmlMemUsed();
     href = getString(cur,
                      "string(ts:instanceDocument/@xlink:href)");
     if ((href == NULL) || (href[0] == 0)) {
-        if (verbose)
-	    fprintf(stderr,
-	            "testGroup line %ld misses href for schemaDocument\n",
+	test_log("testGroup line %ld misses href for schemaDocument\n",
 		    xmlGetLineNo(cur));
 	ret = -1;
 	goto done;
@@ -772,8 +785,7 @@
 	goto done;
     }
     if (checkTestFile((const char *) path) <= 0) {
-	fprintf(stderr,
-	        "schemas for testGroup line %ld is missing: %s\n",
+	test_log("schemas for testGroup line %ld is missing: %s\n",
 		xmlGetLineNo(cur), path);
 	ret = -1;
 	goto done;
@@ -803,24 +815,24 @@
     ret = xmlSchemaValidateDoc(ctxt, doc);
 
     if (xmlStrEqual(validity, BAD_CAST "valid")) {
-	if (ret != 0) {
-	    if (verbose)
-		fprintf(stderr,
-		        "valid instance %s failed to validate against %s\n",
+	if (ret > 0) {
+	    test_log("valid instance %s failed to validate against %s\n",
 			path, spath);
 	    nb_errors++;
+	} else if (ret < 0) {
+	    test_log("valid instance %s got internal error validating %s\n",
+			path, spath);
+	    nb_internals++;
+	    nb_errors++;
 	}
     } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
 	if (ret == 0) {
-	    if (verbose)
-		fprintf(stderr,
-		        "Failed to detect invalid instance %s against %s\n",
+	    test_log("Failed to detect invalid instance %s against %s\n",
 			path, spath);
 	    nb_errors++;
 	}
     } else {
-        fprintf(stderr,
-	        "instanceDocument line %ld has unexpected validity value%s\n",
+        test_log("instanceDocument line %ld has unexpected validity value%s\n",
 	        xmlGetLineNo(cur), validity);
 	ret = -1;
 	goto done;
@@ -834,7 +846,7 @@
     if (doc != NULL) xmlFreeDoc(doc);
     xmlResetLastError();
     if (mem != xmlMemUsed()) {
-	fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
+	test_log("Validation of tests starting line %ld leaked %d\n",
 		xmlGetLineNo(cur), xmlMemUsed() - mem);
 	nb_leaks++;
     }
@@ -842,7 +854,7 @@
 }
 
 static int
-xstcTestGroup(int verbose, xmlNodePtr cur, const char *base) {
+xstcTestGroup(xmlNodePtr cur, const char *base) {
     xmlChar *href = NULL;
     xmlChar *path = NULL;
     xmlChar *validity = NULL;
@@ -852,28 +864,25 @@
     int ret = 0, mem;
 
     xmlResetLastError();
+    testErrorsSize = 0; testErrors[0] = 0;
     mem = xmlMemUsed();
     href = getString(cur,
                      "string(ts:schemaTest/ts:schemaDocument/@xlink:href)");
     if ((href == NULL) || (href[0] == 0)) {
-        if (verbose)
-	    fprintf(stderr,
-	            "testGroup line %ld misses href for schemaDocument\n",
+        test_log("testGroup line %ld misses href for schemaDocument\n",
 		    xmlGetLineNo(cur));
 	ret = -1;
 	goto done;
     }
     path = xmlBuildURI(href, BAD_CAST base);
     if (path == NULL) {
-	fprintf(stderr,
-	        "Failed to build path to schemas testGroup line %ld : %s\n",
+	test_log("Failed to build path to schemas testGroup line %ld : %s\n",
 		xmlGetLineNo(cur), href);
 	ret = -1;
 	goto done;
     }
     if (checkTestFile((const char *) path) <= 0) {
-	fprintf(stderr,
-	        "schemas for testGroup line %ld is missing: %s\n",
+	test_log("schemas for testGroup line %ld is missing: %s\n",
 		xmlGetLineNo(cur), path);
 	ret = -1;
 	goto done;
@@ -881,12 +890,14 @@
     validity = getString(cur,
                          "string(ts:schemaTest/ts:expected/@validity)");
     if (validity == NULL) {
-        fprintf(stderr, "testGroup line %ld misses expected validity\n",
+        test_log("testGroup line %ld misses expected validity\n",
 	        xmlGetLineNo(cur));
 	ret = -1;
 	goto done;
     }
+    nb_tests++;
     if (xmlStrEqual(validity, BAD_CAST "valid")) {
+        nb_schematas++;
 	ctxt = xmlSchemaNewParserCtxt((const char *) path);
 	xmlSchemaSetParserErrors(ctxt,
 	     (xmlSchemaValidityErrorFunc) testErrorHandler,
@@ -895,21 +906,18 @@
 	schemas = xmlSchemaParse(ctxt);
 	xmlSchemaFreeParserCtxt(ctxt);
 	if (schemas == NULL) {
-	    if (verbose)
-		fprintf(stderr, "valid schemas %s failed to parse\n",
+	    test_log("valid schemas %s failed to parse\n",
 			path);
 	    nb_errors++;
 	}
 	instance = getNext(cur, "./ts:instanceTest[1]");
-	if (instance == NULL) {
-	    nb_tests++;
-	}
 	while (instance != NULL) {
-            xstcTestInstance(verbose, instance, schemas, path, base);
+            xstcTestInstance(instance, schemas, path, base);
 	    instance = getNext(instance,
 	                       "following-sibling::ts:instanceTest[1]");
 	}
     } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
+        nb_schematas++;
 	ctxt = xmlSchemaNewParserCtxt((const char *) path);
 	xmlSchemaSetParserErrors(ctxt,
 	     (xmlSchemaValidityErrorFunc) testErrorHandler,
@@ -918,15 +926,12 @@
 	schemas = xmlSchemaParse(ctxt);
 	xmlSchemaFreeParserCtxt(ctxt);
 	if (schemas == NULL) {
-	    if (verbose)
-		fprintf(stderr, "Failed to detect error in schemas %s\n",
+	    test_log("Failed to detect error in schemas %s\n",
 			path);
 	    nb_errors++;
 	}
-	nb_tests++;
     } else {
-        fprintf(stderr,
-	        "testGroup line %ld misses unexpected validity value%s\n",
+        test_log("testGroup line %ld misses unexpected validity value%s\n",
 	        xmlGetLineNo(cur), validity);
 	ret = -1;
 	goto done;
@@ -939,15 +944,15 @@
     if (schemas != NULL) xmlSchemaFree(schemas);
     xmlResetLastError();
     if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
-	fprintf(stderr, "Processing test line %ld leaked %d\n",
-		xmlGetLineNo(cur), xmlMemUsed() - mem);
+	test_log("Processing test line %ld %s leaked %d\n",
+		xmlGetLineNo(cur), path, xmlMemUsed() - mem);
 	nb_leaks++;
     }
     return(ret);
 }
 
 static int
-xstcMetadata(int verbose, const char *metadata, const char *base) {
+xstcMetadata(const char *metadata, const char *base) {
     xmlDocPtr doc;
     xmlNodePtr cur;
     xmlChar *contributor;
@@ -984,7 +989,7 @@
 	goto done;
     }
     while (cur != NULL) {
-        xstcTestGroup(verbose, cur, base);
+        xstcTestGroup(cur, base);
 	cur = getNext(cur, "following-sibling::ts:testGroup[1]");
     }
 
@@ -1002,9 +1007,14 @@
 int
 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
     int res, ret = 0;
-    int verbose = 0;
     int old_errors, old_tests, old_leaks;
 
+    logfile = fopen(LOGFILE, "w");
+    if (logfile == NULL) {
+        fprintf(stderr,
+	        "Could not open the log file, running in verbose mode\n");
+	verbose = 1;
+    }
     initializeLibxml2();
 
     if ((argc >= 2) && (!strcmp(argv[1], "-v")))
@@ -1014,7 +1024,7 @@
     old_errors = nb_errors;
     old_tests = nb_tests;
     old_leaks = nb_leaks;
-    res = xsdTest(verbose);
+    res = xsdTest();
     if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
 	printf("Ran %d tests, no errors\n", nb_tests - old_tests);
     else
@@ -1025,7 +1035,7 @@
     old_errors = nb_errors;
     old_tests = nb_tests;
     old_leaks = nb_leaks;
-    res = rngTest1(verbose);
+    res = rngTest1();
     if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
 	printf("Ran %d tests, no errors\n", nb_tests - old_tests);
     else
@@ -1036,7 +1046,7 @@
     old_errors = nb_errors;
     old_tests = nb_tests;
     old_leaks = nb_leaks;
-    res = rngTest2(verbose);
+    res = rngTest2();
     if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
 	printf("Ran %d tests, no errors\n", nb_tests - old_tests);
     else
@@ -1047,41 +1057,56 @@
     old_errors = nb_errors;
     old_tests = nb_tests;
     old_leaks = nb_leaks;
-    res = xstcMetadata(verbose,
+    nb_internals = 0;
+    nb_schematas = 0;
+    res = xstcMetadata(
                  "xstc/Tests/Metadata/NISTXMLSchemaDatatypes.testSet",
 		 "xstc/Tests/Metadata/");
     if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
-	printf("Ran %d tests, no errors\n", nb_tests - old_tests);
+	printf("Ran %d tests (%d schemata), no errors\n",
+	       nb_tests - old_tests, nb_schematas);
     else
-	printf("Ran %d tests, %d errors, %d leaks\n",
+	printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n",
 	       nb_tests - old_tests,
+	       nb_schematas,
 	       nb_errors - old_errors,
+	       nb_internals,
 	       nb_leaks - old_leaks);
     old_errors = nb_errors;
     old_tests = nb_tests;
     old_leaks = nb_leaks;
-    res = xstcMetadata(verbose,
+    nb_internals = 0;
+    nb_schematas = 0;
+    res = xstcMetadata(
                  "xstc/Tests/Metadata/SunXMLSchema1-0-20020116.testSet",
-		 "xstc/");
+		 "xstc/Tests/");
     if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
-	printf("Ran %d tests, no errors\n", nb_tests - old_tests);
+	printf("Ran %d tests (%d schemata), no errors\n",
+	       nb_tests - old_tests, nb_schematas);
     else
-	printf("Ran %d tests, %d errors, %d leaks\n",
+	printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n",
 	       nb_tests - old_tests,
+	       nb_schematas,
 	       nb_errors - old_errors,
+	       nb_internals,
 	       nb_leaks - old_leaks);
     old_errors = nb_errors;
     old_tests = nb_tests;
     old_leaks = nb_leaks;
-    res = xstcMetadata(verbose,
+    nb_internals = 0;
+    nb_schematas = 0;
+    res = xstcMetadata(
                  "xstc/Tests/Metadata/MSXMLSchema1-0-20020116.testSet",
 		 "xstc/Tests/");
     if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
-	printf("Ran %d tests, no errors\n", nb_tests - old_tests);
+	printf("Ran %d tests (%d schemata), no errors\n",
+	       nb_tests - old_tests, nb_schematas);
     else
-	printf("Ran %d tests, %d errors, %d leaks\n",
+	printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n",
 	       nb_tests - old_tests,
+	       nb_schematas,
 	       nb_errors - old_errors,
+	       nb_internals,
 	       nb_leaks - old_leaks);
 
     if ((nb_errors == 0) && (nb_leaks == 0)) {
@@ -1098,6 +1123,8 @@
     xmlCleanupParser();
     xmlMemoryDump();
 
+    if (logfile != NULL)
+        fclose(logfile);
     return(ret);
 }
 #else /* !SCHEMAS */