1/*
2 * xmllint.c : a small tester program for XML input.
3 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9#include "libxml.h"
10
11#include <string.h>
12#include <stdarg.h>
13#include <assert.h>
14
15#if defined (_WIN32) && !defined(__CYGWIN__)
16#if defined (_MSC_VER) || defined(__BORLANDC__)
17#include <winsock2.h>
18#pragma comment(lib, "ws2_32.lib")
19#define gettimeofday(p1,p2)
20#endif /* _MSC_VER */
21#endif /* _WIN32 */
22
23#ifdef HAVE_SYS_TIME_H
24#include <sys/time.h>
25#endif
26#ifdef HAVE_TIME_H
27#include <time.h>
28#endif
29
30#ifdef __MINGW32__
31#define _WINSOCKAPI_
32#include <wsockcompat.h>
33#include <winsock2.h>
34#undef XML_SOCKLEN_T
35#define XML_SOCKLEN_T unsigned int
36#endif
37
38#ifdef HAVE_SYS_TIMEB_H
39#include <sys/timeb.h>
40#endif
41
42#ifdef HAVE_SYS_TYPES_H
43#include <sys/types.h>
44#endif
45#ifdef HAVE_SYS_STAT_H
46#include <sys/stat.h>
47#endif
48#ifdef HAVE_FCNTL_H
49#include <fcntl.h>
50#endif
51#ifdef HAVE_UNISTD_H
52#include <unistd.h>
53#endif
54#ifdef HAVE_SYS_MMAN_H
55#include <sys/mman.h>
56/* seems needed for Solaris */
57#ifndef MAP_FAILED
58#define MAP_FAILED ((void *) -1)
59#endif
60#endif
61#ifdef HAVE_STDLIB_H
62#include <stdlib.h>
63#endif
64#ifdef HAVE_LIBREADLINE
65#include <readline/readline.h>
66#ifdef HAVE_LIBHISTORY
67#include <readline/history.h>
68#endif
69#endif
70
71#include <libxml/xmlmemory.h>
72#include <libxml/parser.h>
73#include <libxml/parserInternals.h>
74#include <libxml/HTMLparser.h>
75#include <libxml/HTMLtree.h>
76#include <libxml/tree.h>
77#include <libxml/xpath.h>
78#include <libxml/debugXML.h>
79#include <libxml/xmlerror.h>
80#ifdef LIBXML_XINCLUDE_ENABLED
81#include <libxml/xinclude.h>
82#endif
83#ifdef LIBXML_CATALOG_ENABLED
84#include <libxml/catalog.h>
85#endif
86#include <libxml/globals.h>
87#include <libxml/xmlreader.h>
88#ifdef LIBXML_SCHEMATRON_ENABLED
89#include <libxml/schematron.h>
90#endif
91#ifdef LIBXML_SCHEMAS_ENABLED
92#include <libxml/relaxng.h>
93#include <libxml/xmlschemas.h>
94#endif
95#ifdef LIBXML_PATTERN_ENABLED
96#include <libxml/pattern.h>
97#endif
98#ifdef LIBXML_C14N_ENABLED
99#include <libxml/c14n.h>
100#endif
101#ifdef LIBXML_OUTPUT_ENABLED
102#include <libxml/xmlsave.h>
103#endif
104
105#ifndef XML_XML_DEFAULT_CATALOG
106#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
107#endif
108
109typedef enum {
110    XMLLINT_RETURN_OK = 0,	/* No error */
111    XMLLINT_ERR_UNCLASS = 1,	/* Unclassified */
112    XMLLINT_ERR_DTD = 2,	/* Error in DTD */
113    XMLLINT_ERR_VALID = 3,	/* Validation error */
114    XMLLINT_ERR_RDFILE = 4,	/* CtxtReadFile error */
115    XMLLINT_ERR_SCHEMACOMP = 5,	/* Schema compilation */
116    XMLLINT_ERR_OUT = 6,	/* Error writing output */
117    XMLLINT_ERR_SCHEMAPAT = 7,	/* Error in schema pattern */
118    XMLLINT_ERR_RDREGIS = 8,	/* Error in Reader registration */
119    XMLLINT_ERR_MEM = 9,	/* Out of memory error */
120    XMLLINT_ERR_XPATH = 10	/* XPath evaluation error */
121} xmllintReturnCode;
122#ifdef LIBXML_DEBUG_ENABLED
123static int shell = 0;
124static int debugent = 0;
125#endif
126static int debug = 0;
127static int maxmem = 0;
128#ifdef LIBXML_TREE_ENABLED
129static int copy = 0;
130#endif /* LIBXML_TREE_ENABLED */
131static int recovery = 0;
132static int noent = 0;
133static int noenc = 0;
134static int noblanks = 0;
135static int noout = 0;
136static int nowrap = 0;
137#ifdef LIBXML_OUTPUT_ENABLED
138static int format = 0;
139static const char *output = NULL;
140static int compress = 0;
141static int oldout = 0;
142#endif /* LIBXML_OUTPUT_ENABLED */
143#ifdef LIBXML_VALID_ENABLED
144static int valid = 0;
145static int postvalid = 0;
146static char * dtdvalid = NULL;
147static char * dtdvalidfpi = NULL;
148#endif
149#ifdef LIBXML_SCHEMAS_ENABLED
150static char * relaxng = NULL;
151static xmlRelaxNGPtr relaxngschemas = NULL;
152static char * schema = NULL;
153static xmlSchemaPtr wxschemas = NULL;
154#endif
155#ifdef LIBXML_SCHEMATRON_ENABLED
156static char * schematron = NULL;
157static xmlSchematronPtr wxschematron = NULL;
158#endif
159static int repeat = 0;
160static int insert = 0;
161#if defined(LIBXML_HTML_ENABLED) || defined(LIBXML_VALID_ENABLED)
162static int html = 0;
163static int xmlout = 0;
164#endif
165static int htmlout = 0;
166#if defined(LIBXML_HTML_ENABLED)
167static int nodefdtd = 0;
168#endif
169#ifdef LIBXML_PUSH_ENABLED
170static int push = 0;
171static int pushsize = 4096;
172#endif /* LIBXML_PUSH_ENABLED */
173#ifdef HAVE_MMAP
174static int memory = 0;
175#endif
176static int testIO = 0;
177static char *encoding = NULL;
178#ifdef LIBXML_XINCLUDE_ENABLED
179static int xinclude = 0;
180#endif
181static int dtdattrs = 0;
182static int loaddtd = 0;
183static xmllintReturnCode progresult = XMLLINT_RETURN_OK;
184static int timing = 0;
185static int generate = 0;
186static int dropdtd = 0;
187#ifdef LIBXML_CATALOG_ENABLED
188static int catalogs = 0;
189static int nocatalogs = 0;
190#endif
191#ifdef LIBXML_C14N_ENABLED
192static int canonical = 0;
193static int canonical_11 = 0;
194static int exc_canonical = 0;
195#endif
196#ifdef LIBXML_READER_ENABLED
197static int stream = 0;
198static int walker = 0;
199#endif /* LIBXML_READER_ENABLED */
200static int chkregister = 0;
201static int nbregister = 0;
202#ifdef LIBXML_SAX1_ENABLED
203static int sax1 = 0;
204#endif /* LIBXML_SAX1_ENABLED */
205#ifdef LIBXML_PATTERN_ENABLED
206static const char *pattern = NULL;
207static xmlPatternPtr patternc = NULL;
208static xmlStreamCtxtPtr patstream = NULL;
209#endif
210#ifdef LIBXML_XPATH_ENABLED
211static const char *xpathquery = NULL;
212#endif
213static int options = XML_PARSE_COMPACT | XML_PARSE_BIG_LINES;
214static int sax = 0;
215static int oldxml10 = 0;
216
217/************************************************************************
218 *									*
219 *		 Entity loading control and customization.		*
220 *									*
221 ************************************************************************/
222#define MAX_PATHS 64
223#ifdef _WIN32
224# define PATH_SEPARATOR ';'
225#else
226# define PATH_SEPARATOR ':'
227#endif
228static xmlChar *paths[MAX_PATHS + 1];
229static int nbpaths = 0;
230static int load_trace = 0;
231
232static
233void parsePath(const xmlChar *path) {
234    const xmlChar *cur;
235
236    if (path == NULL)
237	return;
238    while (*path != 0) {
239	if (nbpaths >= MAX_PATHS) {
240	    fprintf(stderr, "MAX_PATHS reached: too many paths\n");
241	    return;
242	}
243	cur = path;
244	while ((*cur == ' ') || (*cur == PATH_SEPARATOR))
245	    cur++;
246	path = cur;
247	while ((*cur != 0) && (*cur != ' ') && (*cur != PATH_SEPARATOR))
248	    cur++;
249	if (cur != path) {
250	    paths[nbpaths] = xmlStrndup(path, cur - path);
251	    if (paths[nbpaths] != NULL)
252		nbpaths++;
253	    path = cur;
254	}
255    }
256}
257
258static xmlExternalEntityLoader defaultEntityLoader = NULL;
259
260static xmlParserInputPtr
261xmllintExternalEntityLoader(const char *URL, const char *ID,
262			     xmlParserCtxtPtr ctxt) {
263    xmlParserInputPtr ret;
264    warningSAXFunc warning = NULL;
265    errorSAXFunc err = NULL;
266
267    int i;
268    const char *lastsegment = URL;
269    const char *iter = URL;
270
271    if ((nbpaths > 0) && (iter != NULL)) {
272	while (*iter != 0) {
273	    if (*iter == '/')
274		lastsegment = iter + 1;
275	    iter++;
276	}
277    }
278
279    if ((ctxt != NULL) && (ctxt->sax != NULL)) {
280	warning = ctxt->sax->warning;
281	err = ctxt->sax->error;
282	ctxt->sax->warning = NULL;
283	ctxt->sax->error = NULL;
284    }
285
286    if (defaultEntityLoader != NULL) {
287	ret = defaultEntityLoader(URL, ID, ctxt);
288	if (ret != NULL) {
289	    if (warning != NULL)
290		ctxt->sax->warning = warning;
291	    if (err != NULL)
292		ctxt->sax->error = err;
293	    if (load_trace) {
294		fprintf \
295			(stderr,
296			 "Loaded URL=\"%s\" ID=\"%s\"\n",
297			 URL ? URL : "(null)",
298			 ID ? ID : "(null)");
299	    }
300	    return(ret);
301	}
302    }
303    for (i = 0;i < nbpaths;i++) {
304	xmlChar *newURL;
305
306	newURL = xmlStrdup((const xmlChar *) paths[i]);
307	newURL = xmlStrcat(newURL, (const xmlChar *) "/");
308	newURL = xmlStrcat(newURL, (const xmlChar *) lastsegment);
309	if (newURL != NULL) {
310	    ret = defaultEntityLoader((const char *)newURL, ID, ctxt);
311	    if (ret != NULL) {
312		if (warning != NULL)
313		    ctxt->sax->warning = warning;
314		if (err != NULL)
315		    ctxt->sax->error = err;
316		if (load_trace) {
317		    fprintf \
318			(stderr,
319			 "Loaded URL=\"%s\" ID=\"%s\"\n",
320			 newURL,
321			 ID ? ID : "(null)");
322		}
323		xmlFree(newURL);
324		return(ret);
325	    }
326	    xmlFree(newURL);
327	}
328    }
329    if (err != NULL)
330        ctxt->sax->error = err;
331    if (warning != NULL) {
332	ctxt->sax->warning = warning;
333	if (URL != NULL)
334	    warning(ctxt, "failed to load external entity \"%s\"\n", URL);
335	else if (ID != NULL)
336	    warning(ctxt, "failed to load external entity \"%s\"\n", ID);
337    }
338    return(NULL);
339}
340/************************************************************************
341 *									*
342 * Memory allocation consumption debugging				*
343 *									*
344 ************************************************************************/
345
346static void
347OOM(void)
348{
349    fprintf(stderr, "Ran out of memory needs > %d bytes\n", maxmem);
350    progresult = XMLLINT_ERR_MEM;
351}
352
353static void
354myFreeFunc(void *mem)
355{
356    xmlMemFree(mem);
357}
358static void *
359myMallocFunc(size_t size)
360{
361    void *ret;
362
363    ret = xmlMemMalloc(size);
364    if (ret != NULL) {
365        if (xmlMemUsed() > maxmem) {
366            OOM();
367            xmlMemFree(ret);
368            return (NULL);
369        }
370    }
371    return (ret);
372}
373static void *
374myReallocFunc(void *mem, size_t size)
375{
376    void *ret;
377
378    ret = xmlMemRealloc(mem, size);
379    if (ret != NULL) {
380        if (xmlMemUsed() > maxmem) {
381            OOM();
382            xmlMemFree(ret);
383            return (NULL);
384        }
385    }
386    return (ret);
387}
388static char *
389myStrdupFunc(const char *str)
390{
391    char *ret;
392
393    ret = xmlMemoryStrdup(str);
394    if (ret != NULL) {
395        if (xmlMemUsed() > maxmem) {
396            OOM();
397            xmlFree(ret);
398            return (NULL);
399        }
400    }
401    return (ret);
402}
403/************************************************************************
404 *									*
405 * Internal timing routines to remove the necessity to have		*
406 * unix-specific function calls.					*
407 *									*
408 ************************************************************************/
409
410#ifndef HAVE_GETTIMEOFDAY
411#ifdef HAVE_SYS_TIMEB_H
412#ifdef HAVE_SYS_TIME_H
413#ifdef HAVE_FTIME
414
415static int
416my_gettimeofday(struct timeval *tvp, void *tzp)
417{
418	struct timeb timebuffer;
419
420	ftime(&timebuffer);
421	if (tvp) {
422		tvp->tv_sec = timebuffer.time;
423		tvp->tv_usec = timebuffer.millitm * 1000L;
424	}
425	return (0);
426}
427#define HAVE_GETTIMEOFDAY 1
428#define gettimeofday my_gettimeofday
429
430#endif /* HAVE_FTIME */
431#endif /* HAVE_SYS_TIME_H */
432#endif /* HAVE_SYS_TIMEB_H */
433#endif /* !HAVE_GETTIMEOFDAY */
434
435#if defined(HAVE_GETTIMEOFDAY)
436static struct timeval begin, end;
437
438/*
439 * startTimer: call where you want to start timing
440 */
441static void
442startTimer(void)
443{
444    gettimeofday(&begin, NULL);
445}
446
447/*
448 * endTimer: call where you want to stop timing and to print out a
449 *           message about the timing performed; format is a printf
450 *           type argument
451 */
452static void XMLCDECL
453endTimer(const char *fmt, ...)
454{
455    long msec;
456    va_list ap;
457
458    gettimeofday(&end, NULL);
459    msec = end.tv_sec - begin.tv_sec;
460    msec *= 1000;
461    msec += (end.tv_usec - begin.tv_usec) / 1000;
462
463#ifndef HAVE_STDARG_H
464#error "endTimer required stdarg functions"
465#endif
466    va_start(ap, fmt);
467    vfprintf(stderr, fmt, ap);
468    va_end(ap);
469
470    fprintf(stderr, " took %ld ms\n", msec);
471}
472#elif defined(HAVE_TIME_H)
473/*
474 * No gettimeofday function, so we have to make do with calling clock.
475 * This is obviously less accurate, but there's little we can do about
476 * that.
477 */
478#ifndef CLOCKS_PER_SEC
479#define CLOCKS_PER_SEC 100
480#endif
481
482static clock_t begin, end;
483static void
484startTimer(void)
485{
486    begin = clock();
487}
488static void XMLCDECL
489endTimer(const char *fmt, ...)
490{
491    long msec;
492    va_list ap;
493
494    end = clock();
495    msec = ((end - begin) * 1000) / CLOCKS_PER_SEC;
496
497#ifndef HAVE_STDARG_H
498#error "endTimer required stdarg functions"
499#endif
500    va_start(ap, fmt);
501    vfprintf(stderr, fmt, ap);
502    va_end(ap);
503    fprintf(stderr, " took %ld ms\n", msec);
504}
505#else
506
507/*
508 * We don't have a gettimeofday or time.h, so we just don't do timing
509 */
510static void
511startTimer(void)
512{
513    /*
514     * Do nothing
515     */
516}
517static void XMLCDECL
518endTimer(char *format, ...)
519{
520    /*
521     * We cannot do anything because we don't have a timing function
522     */
523#ifdef HAVE_STDARG_H
524    va_list ap;
525    va_start(ap, format);
526    vfprintf(stderr, format, ap);
527    va_end(ap);
528    fprintf(stderr, " was not timed\n");
529#else
530    /* We don't have gettimeofday, time or stdarg.h, what crazy world is
531     * this ?!
532     */
533#endif
534}
535#endif
536/************************************************************************
537 *									*
538 *			HTML ouput					*
539 *									*
540 ************************************************************************/
541static char buffer[50000];
542
543static void
544xmlHTMLEncodeSend(void) {
545    char *result;
546
547    result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer);
548    if (result) {
549	xmlGenericError(xmlGenericErrorContext, "%s", result);
550	xmlFree(result);
551    }
552    buffer[0] = 0;
553}
554
555/**
556 * xmlHTMLPrintFileInfo:
557 * @input:  an xmlParserInputPtr input
558 *
559 * Displays the associated file and line informations for the current input
560 */
561
562static void
563xmlHTMLPrintFileInfo(xmlParserInputPtr input) {
564    int len;
565    xmlGenericError(xmlGenericErrorContext, "<p>");
566
567    len = strlen(buffer);
568    if (input != NULL) {
569	if (input->filename) {
570	    snprintf(&buffer[len], sizeof(buffer) - len, "%s:%d: ", input->filename,
571		    input->line);
572	} else {
573	    snprintf(&buffer[len], sizeof(buffer) - len, "Entity: line %d: ", input->line);
574	}
575    }
576    xmlHTMLEncodeSend();
577}
578
579/**
580 * xmlHTMLPrintFileContext:
581 * @input:  an xmlParserInputPtr input
582 *
583 * Displays current context within the input content for error tracking
584 */
585
586static void
587xmlHTMLPrintFileContext(xmlParserInputPtr input) {
588    const xmlChar *cur, *base;
589    int len;
590    int n;
591
592    if (input == NULL) return;
593    xmlGenericError(xmlGenericErrorContext, "<pre>\n");
594    cur = input->cur;
595    base = input->base;
596    while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
597	cur--;
598    }
599    n = 0;
600    while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
601        cur--;
602    if ((*cur == '\n') || (*cur == '\r')) cur++;
603    base = cur;
604    n = 0;
605    while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
606	len = strlen(buffer);
607        snprintf(&buffer[len], sizeof(buffer) - len, "%c",
608		    (unsigned char) *cur++);
609	n++;
610    }
611    len = strlen(buffer);
612    snprintf(&buffer[len], sizeof(buffer) - len, "\n");
613    cur = input->cur;
614    while ((*cur == '\n') || (*cur == '\r'))
615	cur--;
616    n = 0;
617    while ((cur != base) && (n++ < 80)) {
618	len = strlen(buffer);
619        snprintf(&buffer[len], sizeof(buffer) - len, " ");
620        base++;
621    }
622    len = strlen(buffer);
623    snprintf(&buffer[len], sizeof(buffer) - len, "^\n");
624    xmlHTMLEncodeSend();
625    xmlGenericError(xmlGenericErrorContext, "</pre>");
626}
627
628/**
629 * xmlHTMLError:
630 * @ctx:  an XML parser context
631 * @msg:  the message to display/transmit
632 * @...:  extra parameters for the message display
633 *
634 * Display and format an error messages, gives file, line, position and
635 * extra parameters.
636 */
637static void XMLCDECL
638xmlHTMLError(void *ctx, const char *msg, ...)
639{
640    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
641    xmlParserInputPtr input;
642    va_list args;
643    int len;
644
645    buffer[0] = 0;
646    input = ctxt->input;
647    if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
648        input = ctxt->inputTab[ctxt->inputNr - 2];
649    }
650
651    xmlHTMLPrintFileInfo(input);
652
653    xmlGenericError(xmlGenericErrorContext, "<b>error</b>: ");
654    va_start(args, msg);
655    len = strlen(buffer);
656    vsnprintf(&buffer[len],  sizeof(buffer) - len, msg, args);
657    va_end(args);
658    xmlHTMLEncodeSend();
659    xmlGenericError(xmlGenericErrorContext, "</p>\n");
660
661    xmlHTMLPrintFileContext(input);
662    xmlHTMLEncodeSend();
663}
664
665/**
666 * xmlHTMLWarning:
667 * @ctx:  an XML parser context
668 * @msg:  the message to display/transmit
669 * @...:  extra parameters for the message display
670 *
671 * Display and format a warning messages, gives file, line, position and
672 * extra parameters.
673 */
674static void XMLCDECL
675xmlHTMLWarning(void *ctx, const char *msg, ...)
676{
677    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
678    xmlParserInputPtr input;
679    va_list args;
680    int len;
681
682    buffer[0] = 0;
683    input = ctxt->input;
684    if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
685        input = ctxt->inputTab[ctxt->inputNr - 2];
686    }
687
688
689    xmlHTMLPrintFileInfo(input);
690
691    xmlGenericError(xmlGenericErrorContext, "<b>warning</b>: ");
692    va_start(args, msg);
693    len = strlen(buffer);
694    vsnprintf(&buffer[len],  sizeof(buffer) - len, msg, args);
695    va_end(args);
696    xmlHTMLEncodeSend();
697    xmlGenericError(xmlGenericErrorContext, "</p>\n");
698
699    xmlHTMLPrintFileContext(input);
700    xmlHTMLEncodeSend();
701}
702
703/**
704 * xmlHTMLValidityError:
705 * @ctx:  an XML parser context
706 * @msg:  the message to display/transmit
707 * @...:  extra parameters for the message display
708 *
709 * Display and format an validity error messages, gives file,
710 * line, position and extra parameters.
711 */
712static void XMLCDECL
713xmlHTMLValidityError(void *ctx, const char *msg, ...)
714{
715    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
716    xmlParserInputPtr input;
717    va_list args;
718    int len;
719
720    buffer[0] = 0;
721    input = ctxt->input;
722    if ((input->filename == NULL) && (ctxt->inputNr > 1))
723        input = ctxt->inputTab[ctxt->inputNr - 2];
724
725    xmlHTMLPrintFileInfo(input);
726
727    xmlGenericError(xmlGenericErrorContext, "<b>validity error</b>: ");
728    len = strlen(buffer);
729    va_start(args, msg);
730    vsnprintf(&buffer[len],  sizeof(buffer) - len, msg, args);
731    va_end(args);
732    xmlHTMLEncodeSend();
733    xmlGenericError(xmlGenericErrorContext, "</p>\n");
734
735    xmlHTMLPrintFileContext(input);
736    xmlHTMLEncodeSend();
737    progresult = XMLLINT_ERR_VALID;
738}
739
740/**
741 * xmlHTMLValidityWarning:
742 * @ctx:  an XML parser context
743 * @msg:  the message to display/transmit
744 * @...:  extra parameters for the message display
745 *
746 * Display and format a validity warning messages, gives file, line,
747 * position and extra parameters.
748 */
749static void XMLCDECL
750xmlHTMLValidityWarning(void *ctx, const char *msg, ...)
751{
752    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
753    xmlParserInputPtr input;
754    va_list args;
755    int len;
756
757    buffer[0] = 0;
758    input = ctxt->input;
759    if ((input->filename == NULL) && (ctxt->inputNr > 1))
760        input = ctxt->inputTab[ctxt->inputNr - 2];
761
762    xmlHTMLPrintFileInfo(input);
763
764    xmlGenericError(xmlGenericErrorContext, "<b>validity warning</b>: ");
765    va_start(args, msg);
766    len = strlen(buffer);
767    vsnprintf(&buffer[len],  sizeof(buffer) - len, msg, args);
768    va_end(args);
769    xmlHTMLEncodeSend();
770    xmlGenericError(xmlGenericErrorContext, "</p>\n");
771
772    xmlHTMLPrintFileContext(input);
773    xmlHTMLEncodeSend();
774}
775
776/************************************************************************
777 *									*
778 *			Shell Interface					*
779 *									*
780 ************************************************************************/
781#ifdef LIBXML_DEBUG_ENABLED
782#ifdef LIBXML_XPATH_ENABLED
783/**
784 * xmlShellReadline:
785 * @prompt:  the prompt value
786 *
787 * Read a string
788 *
789 * Returns a pointer to it or NULL on EOF the caller is expected to
790 *     free the returned string.
791 */
792static char *
793xmlShellReadline(char *prompt) {
794#ifdef HAVE_LIBREADLINE
795    char *line_read;
796
797    /* Get a line from the user. */
798    line_read = readline (prompt);
799
800    /* If the line has any text in it, save it on the history. */
801    if (line_read && *line_read)
802	add_history (line_read);
803
804    return (line_read);
805#else
806    char line_read[501];
807    char *ret;
808    int len;
809
810    if (prompt != NULL)
811	fprintf(stdout, "%s", prompt);
812    if (!fgets(line_read, 500, stdin))
813        return(NULL);
814    line_read[500] = 0;
815    len = strlen(line_read);
816    ret = (char *) malloc(len + 1);
817    if (ret != NULL) {
818	memcpy (ret, line_read, len + 1);
819    }
820    return(ret);
821#endif
822}
823#endif /* LIBXML_XPATH_ENABLED */
824#endif /* LIBXML_DEBUG_ENABLED */
825
826/************************************************************************
827 *									*
828 *			I/O Interfaces					*
829 *									*
830 ************************************************************************/
831
832static int myRead(FILE *f, char * buf, int len) {
833    return(fread(buf, 1, len, f));
834}
835static void myClose(FILE *f) {
836  if (f != stdin) {
837    fclose(f);
838  }
839}
840
841/************************************************************************
842 *									*
843 *			SAX based tests					*
844 *									*
845 ************************************************************************/
846
847/*
848 * empty SAX block
849 */
850static xmlSAXHandler emptySAXHandlerStruct = {
851    NULL, /* internalSubset */
852    NULL, /* isStandalone */
853    NULL, /* hasInternalSubset */
854    NULL, /* hasExternalSubset */
855    NULL, /* resolveEntity */
856    NULL, /* getEntity */
857    NULL, /* entityDecl */
858    NULL, /* notationDecl */
859    NULL, /* attributeDecl */
860    NULL, /* elementDecl */
861    NULL, /* unparsedEntityDecl */
862    NULL, /* setDocumentLocator */
863    NULL, /* startDocument */
864    NULL, /* endDocument */
865    NULL, /* startElement */
866    NULL, /* endElement */
867    NULL, /* reference */
868    NULL, /* characters */
869    NULL, /* ignorableWhitespace */
870    NULL, /* processingInstruction */
871    NULL, /* comment */
872    NULL, /* xmlParserWarning */
873    NULL, /* xmlParserError */
874    NULL, /* xmlParserError */
875    NULL, /* getParameterEntity */
876    NULL, /* cdataBlock; */
877    NULL, /* externalSubset; */
878    XML_SAX2_MAGIC,
879    NULL,
880    NULL, /* startElementNs */
881    NULL, /* endElementNs */
882    NULL  /* xmlStructuredErrorFunc */
883};
884
885static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
886extern xmlSAXHandlerPtr debugSAXHandler;
887static int callbacks;
888
889/**
890 * isStandaloneDebug:
891 * @ctxt:  An XML parser context
892 *
893 * Is this document tagged standalone ?
894 *
895 * Returns 1 if true
896 */
897static int
898isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
899{
900    callbacks++;
901    if (noout)
902	return(0);
903    fprintf(stdout, "SAX.isStandalone()\n");
904    return(0);
905}
906
907/**
908 * hasInternalSubsetDebug:
909 * @ctxt:  An XML parser context
910 *
911 * Does this document has an internal subset
912 *
913 * Returns 1 if true
914 */
915static int
916hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
917{
918    callbacks++;
919    if (noout)
920	return(0);
921    fprintf(stdout, "SAX.hasInternalSubset()\n");
922    return(0);
923}
924
925/**
926 * hasExternalSubsetDebug:
927 * @ctxt:  An XML parser context
928 *
929 * Does this document has an external subset
930 *
931 * Returns 1 if true
932 */
933static int
934hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
935{
936    callbacks++;
937    if (noout)
938	return(0);
939    fprintf(stdout, "SAX.hasExternalSubset()\n");
940    return(0);
941}
942
943/**
944 * internalSubsetDebug:
945 * @ctxt:  An XML parser context
946 *
947 * Does this document has an internal subset
948 */
949static void
950internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
951	       const xmlChar *ExternalID, const xmlChar *SystemID)
952{
953    callbacks++;
954    if (noout)
955	return;
956    fprintf(stdout, "SAX.internalSubset(%s,", name);
957    if (ExternalID == NULL)
958	fprintf(stdout, " ,");
959    else
960	fprintf(stdout, " %s,", ExternalID);
961    if (SystemID == NULL)
962	fprintf(stdout, " )\n");
963    else
964	fprintf(stdout, " %s)\n", SystemID);
965}
966
967/**
968 * externalSubsetDebug:
969 * @ctxt:  An XML parser context
970 *
971 * Does this document has an external subset
972 */
973static void
974externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
975	       const xmlChar *ExternalID, const xmlChar *SystemID)
976{
977    callbacks++;
978    if (noout)
979	return;
980    fprintf(stdout, "SAX.externalSubset(%s,", name);
981    if (ExternalID == NULL)
982	fprintf(stdout, " ,");
983    else
984	fprintf(stdout, " %s,", ExternalID);
985    if (SystemID == NULL)
986	fprintf(stdout, " )\n");
987    else
988	fprintf(stdout, " %s)\n", SystemID);
989}
990
991/**
992 * resolveEntityDebug:
993 * @ctxt:  An XML parser context
994 * @publicId: The public ID of the entity
995 * @systemId: The system ID of the entity
996 *
997 * Special entity resolver, better left to the parser, it has
998 * more context than the application layer.
999 * The default behaviour is to NOT resolve the entities, in that case
1000 * the ENTITY_REF nodes are built in the structure (and the parameter
1001 * values).
1002 *
1003 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
1004 */
1005static xmlParserInputPtr
1006resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
1007{
1008    callbacks++;
1009    if (noout)
1010	return(NULL);
1011    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1012
1013
1014    fprintf(stdout, "SAX.resolveEntity(");
1015    if (publicId != NULL)
1016	fprintf(stdout, "%s", (char *)publicId);
1017    else
1018	fprintf(stdout, " ");
1019    if (systemId != NULL)
1020	fprintf(stdout, ", %s)\n", (char *)systemId);
1021    else
1022	fprintf(stdout, ", )\n");
1023    return(NULL);
1024}
1025
1026/**
1027 * getEntityDebug:
1028 * @ctxt:  An XML parser context
1029 * @name: The entity name
1030 *
1031 * Get an entity by name
1032 *
1033 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
1034 */
1035static xmlEntityPtr
1036getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1037{
1038    callbacks++;
1039    if (noout)
1040	return(NULL);
1041    fprintf(stdout, "SAX.getEntity(%s)\n", name);
1042    return(NULL);
1043}
1044
1045/**
1046 * getParameterEntityDebug:
1047 * @ctxt:  An XML parser context
1048 * @name: The entity name
1049 *
1050 * Get a parameter entity by name
1051 *
1052 * Returns the xmlParserInputPtr
1053 */
1054static xmlEntityPtr
1055getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1056{
1057    callbacks++;
1058    if (noout)
1059	return(NULL);
1060    fprintf(stdout, "SAX.getParameterEntity(%s)\n", name);
1061    return(NULL);
1062}
1063
1064
1065/**
1066 * entityDeclDebug:
1067 * @ctxt:  An XML parser context
1068 * @name:  the entity name
1069 * @type:  the entity type
1070 * @publicId: The public ID of the entity
1071 * @systemId: The system ID of the entity
1072 * @content: the entity value (without processing).
1073 *
1074 * An entity definition has been parsed
1075 */
1076static void
1077entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1078          const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
1079{
1080const xmlChar *nullstr = BAD_CAST "(null)";
1081    /* not all libraries handle printing null pointers nicely */
1082    if (publicId == NULL)
1083        publicId = nullstr;
1084    if (systemId == NULL)
1085        systemId = nullstr;
1086    if (content == NULL)
1087        content = (xmlChar *)nullstr;
1088    callbacks++;
1089    if (noout)
1090	return;
1091    fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
1092            name, type, publicId, systemId, content);
1093}
1094
1095/**
1096 * attributeDeclDebug:
1097 * @ctxt:  An XML parser context
1098 * @name:  the attribute name
1099 * @type:  the attribute type
1100 *
1101 * An attribute definition has been parsed
1102 */
1103static void
1104attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
1105                   const xmlChar * name, int type, int def,
1106                   const xmlChar * defaultValue, xmlEnumerationPtr tree)
1107{
1108    callbacks++;
1109    if (noout)
1110        return;
1111    if (defaultValue == NULL)
1112        fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
1113                elem, name, type, def);
1114    else
1115        fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
1116                elem, name, type, def, defaultValue);
1117    xmlFreeEnumeration(tree);
1118}
1119
1120/**
1121 * elementDeclDebug:
1122 * @ctxt:  An XML parser context
1123 * @name:  the element name
1124 * @type:  the element type
1125 * @content: the element value (without processing).
1126 *
1127 * An element definition has been parsed
1128 */
1129static void
1130elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1131	    xmlElementContentPtr content ATTRIBUTE_UNUSED)
1132{
1133    callbacks++;
1134    if (noout)
1135	return;
1136    fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n",
1137            name, type);
1138}
1139
1140/**
1141 * notationDeclDebug:
1142 * @ctxt:  An XML parser context
1143 * @name: The name of the notation
1144 * @publicId: The public ID of the entity
1145 * @systemId: The system ID of the entity
1146 *
1147 * What to do when a notation declaration has been parsed.
1148 */
1149static void
1150notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1151	     const xmlChar *publicId, const xmlChar *systemId)
1152{
1153    callbacks++;
1154    if (noout)
1155	return;
1156    fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n",
1157            (char *) name, (char *) publicId, (char *) systemId);
1158}
1159
1160/**
1161 * unparsedEntityDeclDebug:
1162 * @ctxt:  An XML parser context
1163 * @name: The name of the entity
1164 * @publicId: The public ID of the entity
1165 * @systemId: The system ID of the entity
1166 * @notationName: the name of the notation
1167 *
1168 * What to do when an unparsed entity declaration is parsed
1169 */
1170static void
1171unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1172		   const xmlChar *publicId, const xmlChar *systemId,
1173		   const xmlChar *notationName)
1174{
1175const xmlChar *nullstr = BAD_CAST "(null)";
1176
1177    if (publicId == NULL)
1178        publicId = nullstr;
1179    if (systemId == NULL)
1180        systemId = nullstr;
1181    if (notationName == NULL)
1182        notationName = nullstr;
1183    callbacks++;
1184    if (noout)
1185	return;
1186    fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1187            (char *) name, (char *) publicId, (char *) systemId,
1188	    (char *) notationName);
1189}
1190
1191/**
1192 * setDocumentLocatorDebug:
1193 * @ctxt:  An XML parser context
1194 * @loc: A SAX Locator
1195 *
1196 * Receive the document locator at startup, actually xmlDefaultSAXLocator
1197 * Everything is available on the context, so this is useless in our case.
1198 */
1199static void
1200setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1201{
1202    callbacks++;
1203    if (noout)
1204	return;
1205    fprintf(stdout, "SAX.setDocumentLocator()\n");
1206}
1207
1208/**
1209 * startDocumentDebug:
1210 * @ctxt:  An XML parser context
1211 *
1212 * called when the document start being processed.
1213 */
1214static void
1215startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1216{
1217    callbacks++;
1218    if (noout)
1219	return;
1220    fprintf(stdout, "SAX.startDocument()\n");
1221}
1222
1223/**
1224 * endDocumentDebug:
1225 * @ctxt:  An XML parser context
1226 *
1227 * called when the document end has been detected.
1228 */
1229static void
1230endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1231{
1232    callbacks++;
1233    if (noout)
1234	return;
1235    fprintf(stdout, "SAX.endDocument()\n");
1236}
1237
1238/**
1239 * startElementDebug:
1240 * @ctxt:  An XML parser context
1241 * @name:  The element name
1242 *
1243 * called when an opening tag has been processed.
1244 */
1245static void
1246startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1247{
1248    int i;
1249
1250    callbacks++;
1251    if (noout)
1252	return;
1253    fprintf(stdout, "SAX.startElement(%s", (char *) name);
1254    if (atts != NULL) {
1255        for (i = 0;(atts[i] != NULL);i++) {
1256	    fprintf(stdout, ", %s='", atts[i++]);
1257	    if (atts[i] != NULL)
1258	        fprintf(stdout, "%s'", atts[i]);
1259	}
1260    }
1261    fprintf(stdout, ")\n");
1262}
1263
1264/**
1265 * endElementDebug:
1266 * @ctxt:  An XML parser context
1267 * @name:  The element name
1268 *
1269 * called when the end of an element has been detected.
1270 */
1271static void
1272endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1273{
1274    callbacks++;
1275    if (noout)
1276	return;
1277    fprintf(stdout, "SAX.endElement(%s)\n", (char *) name);
1278}
1279
1280/**
1281 * charactersDebug:
1282 * @ctxt:  An XML parser context
1283 * @ch:  a xmlChar string
1284 * @len: the number of xmlChar
1285 *
1286 * receiving some chars from the parser.
1287 * Question: how much at a time ???
1288 */
1289static void
1290charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1291{
1292    char out[40];
1293    int i;
1294
1295    callbacks++;
1296    if (noout)
1297	return;
1298    for (i = 0;(i<len) && (i < 30);i++)
1299	out[i] = ch[i];
1300    out[i] = 0;
1301
1302    fprintf(stdout, "SAX.characters(%s, %d)\n", out, len);
1303}
1304
1305/**
1306 * referenceDebug:
1307 * @ctxt:  An XML parser context
1308 * @name:  The entity name
1309 *
1310 * called when an entity reference is detected.
1311 */
1312static void
1313referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1314{
1315    callbacks++;
1316    if (noout)
1317	return;
1318    fprintf(stdout, "SAX.reference(%s)\n", name);
1319}
1320
1321/**
1322 * ignorableWhitespaceDebug:
1323 * @ctxt:  An XML parser context
1324 * @ch:  a xmlChar string
1325 * @start: the first char in the string
1326 * @len: the number of xmlChar
1327 *
1328 * receiving some ignorable whitespaces from the parser.
1329 * Question: how much at a time ???
1330 */
1331static void
1332ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1333{
1334    char out[40];
1335    int i;
1336
1337    callbacks++;
1338    if (noout)
1339	return;
1340    for (i = 0;(i<len) && (i < 30);i++)
1341	out[i] = ch[i];
1342    out[i] = 0;
1343    fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", out, len);
1344}
1345
1346/**
1347 * processingInstructionDebug:
1348 * @ctxt:  An XML parser context
1349 * @target:  the target name
1350 * @data: the PI data's
1351 * @len: the number of xmlChar
1352 *
1353 * A processing instruction has been parsed.
1354 */
1355static void
1356processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1357                      const xmlChar *data)
1358{
1359    callbacks++;
1360    if (noout)
1361	return;
1362    if (data != NULL)
1363	fprintf(stdout, "SAX.processingInstruction(%s, %s)\n",
1364		(char *) target, (char *) data);
1365    else
1366	fprintf(stdout, "SAX.processingInstruction(%s, NULL)\n",
1367		(char *) target);
1368}
1369
1370/**
1371 * cdataBlockDebug:
1372 * @ctx: the user data (XML parser context)
1373 * @value:  The pcdata content
1374 * @len:  the block length
1375 *
1376 * called when a pcdata block has been parsed
1377 */
1378static void
1379cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1380{
1381    callbacks++;
1382    if (noout)
1383	return;
1384    fprintf(stdout, "SAX.pcdata(%.20s, %d)\n",
1385	    (char *) value, len);
1386}
1387
1388/**
1389 * commentDebug:
1390 * @ctxt:  An XML parser context
1391 * @value:  the comment content
1392 *
1393 * A comment has been parsed.
1394 */
1395static void
1396commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1397{
1398    callbacks++;
1399    if (noout)
1400	return;
1401    fprintf(stdout, "SAX.comment(%s)\n", value);
1402}
1403
1404/**
1405 * warningDebug:
1406 * @ctxt:  An XML parser context
1407 * @msg:  the message to display/transmit
1408 * @...:  extra parameters for the message display
1409 *
1410 * Display and format a warning messages, gives file, line, position and
1411 * extra parameters.
1412 */
1413static void XMLCDECL
1414warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1415{
1416    va_list args;
1417
1418    callbacks++;
1419    if (noout)
1420	return;
1421    va_start(args, msg);
1422    fprintf(stdout, "SAX.warning: ");
1423    vfprintf(stdout, msg, args);
1424    va_end(args);
1425}
1426
1427/**
1428 * errorDebug:
1429 * @ctxt:  An XML parser context
1430 * @msg:  the message to display/transmit
1431 * @...:  extra parameters for the message display
1432 *
1433 * Display and format a error messages, gives file, line, position and
1434 * extra parameters.
1435 */
1436static void XMLCDECL
1437errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1438{
1439    va_list args;
1440
1441    callbacks++;
1442    if (noout)
1443	return;
1444    va_start(args, msg);
1445    fprintf(stdout, "SAX.error: ");
1446    vfprintf(stdout, msg, args);
1447    va_end(args);
1448}
1449
1450/**
1451 * fatalErrorDebug:
1452 * @ctxt:  An XML parser context
1453 * @msg:  the message to display/transmit
1454 * @...:  extra parameters for the message display
1455 *
1456 * Display and format a fatalError messages, gives file, line, position and
1457 * extra parameters.
1458 */
1459static void XMLCDECL
1460fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1461{
1462    va_list args;
1463
1464    callbacks++;
1465    if (noout)
1466	return;
1467    va_start(args, msg);
1468    fprintf(stdout, "SAX.fatalError: ");
1469    vfprintf(stdout, msg, args);
1470    va_end(args);
1471}
1472
1473static xmlSAXHandler debugSAXHandlerStruct = {
1474    internalSubsetDebug,
1475    isStandaloneDebug,
1476    hasInternalSubsetDebug,
1477    hasExternalSubsetDebug,
1478    resolveEntityDebug,
1479    getEntityDebug,
1480    entityDeclDebug,
1481    notationDeclDebug,
1482    attributeDeclDebug,
1483    elementDeclDebug,
1484    unparsedEntityDeclDebug,
1485    setDocumentLocatorDebug,
1486    startDocumentDebug,
1487    endDocumentDebug,
1488    startElementDebug,
1489    endElementDebug,
1490    referenceDebug,
1491    charactersDebug,
1492    ignorableWhitespaceDebug,
1493    processingInstructionDebug,
1494    commentDebug,
1495    warningDebug,
1496    errorDebug,
1497    fatalErrorDebug,
1498    getParameterEntityDebug,
1499    cdataBlockDebug,
1500    externalSubsetDebug,
1501    1,
1502    NULL,
1503    NULL,
1504    NULL,
1505    NULL
1506};
1507
1508xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
1509
1510/*
1511 * SAX2 specific callbacks
1512 */
1513/**
1514 * startElementNsDebug:
1515 * @ctxt:  An XML parser context
1516 * @name:  The element name
1517 *
1518 * called when an opening tag has been processed.
1519 */
1520static void
1521startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1522                    const xmlChar *localname,
1523                    const xmlChar *prefix,
1524                    const xmlChar *URI,
1525		    int nb_namespaces,
1526		    const xmlChar **namespaces,
1527		    int nb_attributes,
1528		    int nb_defaulted,
1529		    const xmlChar **attributes)
1530{
1531    int i;
1532
1533    callbacks++;
1534    if (noout)
1535	return;
1536    fprintf(stdout, "SAX.startElementNs(%s", (char *) localname);
1537    if (prefix == NULL)
1538	fprintf(stdout, ", NULL");
1539    else
1540	fprintf(stdout, ", %s", (char *) prefix);
1541    if (URI == NULL)
1542	fprintf(stdout, ", NULL");
1543    else
1544	fprintf(stdout, ", '%s'", (char *) URI);
1545    fprintf(stdout, ", %d", nb_namespaces);
1546
1547    if (namespaces != NULL) {
1548        for (i = 0;i < nb_namespaces * 2;i++) {
1549	    fprintf(stdout, ", xmlns");
1550	    if (namespaces[i] != NULL)
1551	        fprintf(stdout, ":%s", namespaces[i]);
1552	    i++;
1553	    fprintf(stdout, "='%s'", namespaces[i]);
1554	}
1555    }
1556    fprintf(stdout, ", %d, %d", nb_attributes, nb_defaulted);
1557    if (attributes != NULL) {
1558        for (i = 0;i < nb_attributes * 5;i += 5) {
1559	    if (attributes[i + 1] != NULL)
1560		fprintf(stdout, ", %s:%s='", attributes[i + 1], attributes[i]);
1561	    else
1562		fprintf(stdout, ", %s='", attributes[i]);
1563	    fprintf(stdout, "%.4s...', %d", attributes[i + 3],
1564		    (int)(attributes[i + 4] - attributes[i + 3]));
1565	}
1566    }
1567    fprintf(stdout, ")\n");
1568}
1569
1570/**
1571 * endElementDebug:
1572 * @ctxt:  An XML parser context
1573 * @name:  The element name
1574 *
1575 * called when the end of an element has been detected.
1576 */
1577static void
1578endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1579                  const xmlChar *localname,
1580                  const xmlChar *prefix,
1581                  const xmlChar *URI)
1582{
1583    callbacks++;
1584    if (noout)
1585	return;
1586    fprintf(stdout, "SAX.endElementNs(%s", (char *) localname);
1587    if (prefix == NULL)
1588	fprintf(stdout, ", NULL");
1589    else
1590	fprintf(stdout, ", %s", (char *) prefix);
1591    if (URI == NULL)
1592	fprintf(stdout, ", NULL)\n");
1593    else
1594	fprintf(stdout, ", '%s')\n", (char *) URI);
1595}
1596
1597static xmlSAXHandler debugSAX2HandlerStruct = {
1598    internalSubsetDebug,
1599    isStandaloneDebug,
1600    hasInternalSubsetDebug,
1601    hasExternalSubsetDebug,
1602    resolveEntityDebug,
1603    getEntityDebug,
1604    entityDeclDebug,
1605    notationDeclDebug,
1606    attributeDeclDebug,
1607    elementDeclDebug,
1608    unparsedEntityDeclDebug,
1609    setDocumentLocatorDebug,
1610    startDocumentDebug,
1611    endDocumentDebug,
1612    NULL,
1613    NULL,
1614    referenceDebug,
1615    charactersDebug,
1616    ignorableWhitespaceDebug,
1617    processingInstructionDebug,
1618    commentDebug,
1619    warningDebug,
1620    errorDebug,
1621    fatalErrorDebug,
1622    getParameterEntityDebug,
1623    cdataBlockDebug,
1624    externalSubsetDebug,
1625    XML_SAX2_MAGIC,
1626    NULL,
1627    startElementNsDebug,
1628    endElementNsDebug,
1629    NULL
1630};
1631
1632static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
1633
1634static void
1635testSAX(const char *filename) {
1636    xmlSAXHandlerPtr handler;
1637    const char *user_data = "user_data"; /* mostly for debugging */
1638    xmlParserInputBufferPtr buf = NULL;
1639    xmlParserInputPtr inputStream;
1640    xmlParserCtxtPtr ctxt = NULL;
1641    xmlSAXHandlerPtr old_sax = NULL;
1642
1643    callbacks = 0;
1644
1645    if (noout) {
1646        handler = emptySAXHandler;
1647#ifdef LIBXML_SAX1_ENABLED
1648    } else if (sax1) {
1649        handler = debugSAXHandler;
1650#endif
1651    } else {
1652        handler = debugSAX2Handler;
1653    }
1654
1655    /*
1656     * it's not the simplest code but the most generic in term of I/O
1657     */
1658    buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
1659    if (buf == NULL) {
1660        goto error;
1661    }
1662
1663#ifdef LIBXML_SCHEMAS_ENABLED
1664    if (wxschemas != NULL) {
1665        int ret;
1666	xmlSchemaValidCtxtPtr vctxt;
1667
1668	vctxt = xmlSchemaNewValidCtxt(wxschemas);
1669	xmlSchemaSetValidErrors(vctxt,
1670		(xmlSchemaValidityErrorFunc) fprintf,
1671		(xmlSchemaValidityWarningFunc) fprintf,
1672		stderr);
1673	xmlSchemaValidateSetFilename(vctxt, filename);
1674
1675	ret = xmlSchemaValidateStream(vctxt, buf, 0, handler,
1676	                              (void *)user_data);
1677	if (repeat == 0) {
1678	    if (ret == 0) {
1679		fprintf(stderr, "%s validates\n", filename);
1680	    } else if (ret > 0) {
1681		fprintf(stderr, "%s fails to validate\n", filename);
1682		progresult = XMLLINT_ERR_VALID;
1683	    } else {
1684		fprintf(stderr, "%s validation generated an internal error\n",
1685		       filename);
1686		progresult = XMLLINT_ERR_VALID;
1687	    }
1688	}
1689	xmlSchemaFreeValidCtxt(vctxt);
1690    } else
1691#endif
1692    {
1693	/*
1694	 * Create the parser context amd hook the input
1695	 */
1696	ctxt = xmlNewParserCtxt();
1697	if (ctxt == NULL) {
1698	    xmlFreeParserInputBuffer(buf);
1699	    goto error;
1700	}
1701	old_sax = ctxt->sax;
1702	ctxt->sax = handler;
1703	ctxt->userData = (void *) user_data;
1704	inputStream = xmlNewIOInputStream(ctxt, buf, XML_CHAR_ENCODING_NONE);
1705	if (inputStream == NULL) {
1706	    xmlFreeParserInputBuffer(buf);
1707	    goto error;
1708	}
1709	inputPush(ctxt, inputStream);
1710
1711	/* do the parsing */
1712	xmlParseDocument(ctxt);
1713
1714	if (ctxt->myDoc != NULL) {
1715	    fprintf(stderr, "SAX generated a doc !\n");
1716	    xmlFreeDoc(ctxt->myDoc);
1717	    ctxt->myDoc = NULL;
1718	}
1719    }
1720
1721error:
1722    if (ctxt != NULL) {
1723        ctxt->sax = old_sax;
1724        xmlFreeParserCtxt(ctxt);
1725    }
1726}
1727
1728/************************************************************************
1729 *									*
1730 *			Stream Test processing				*
1731 *									*
1732 ************************************************************************/
1733#ifdef LIBXML_READER_ENABLED
1734static void processNode(xmlTextReaderPtr reader) {
1735    const xmlChar *name, *value;
1736    int type, empty;
1737
1738    type = xmlTextReaderNodeType(reader);
1739    empty = xmlTextReaderIsEmptyElement(reader);
1740
1741    if (debug) {
1742	name = xmlTextReaderConstName(reader);
1743	if (name == NULL)
1744	    name = BAD_CAST "--";
1745
1746	value = xmlTextReaderConstValue(reader);
1747
1748
1749	printf("%d %d %s %d %d",
1750		xmlTextReaderDepth(reader),
1751		type,
1752		name,
1753		empty,
1754		xmlTextReaderHasValue(reader));
1755	if (value == NULL)
1756	    printf("\n");
1757	else {
1758	    printf(" %s\n", value);
1759	}
1760    }
1761#ifdef LIBXML_PATTERN_ENABLED
1762    if (patternc) {
1763        xmlChar *path = NULL;
1764        int match = -1;
1765
1766	if (type == XML_READER_TYPE_ELEMENT) {
1767	    /* do the check only on element start */
1768	    match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
1769
1770	    if (match) {
1771#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
1772		path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
1773		printf("Node %s matches pattern %s\n", path, pattern);
1774#else
1775                printf("Node %s matches pattern %s\n",
1776                       xmlTextReaderConstName(reader), pattern);
1777#endif
1778	    }
1779	}
1780	if (patstream != NULL) {
1781	    int ret;
1782
1783	    if (type == XML_READER_TYPE_ELEMENT) {
1784		ret = xmlStreamPush(patstream,
1785		                    xmlTextReaderConstLocalName(reader),
1786				    xmlTextReaderConstNamespaceUri(reader));
1787		if (ret < 0) {
1788		    fprintf(stderr, "xmlStreamPush() failure\n");
1789                    xmlFreeStreamCtxt(patstream);
1790		    patstream = NULL;
1791		} else if (ret != match) {
1792#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
1793		    if (path == NULL) {
1794		        path = xmlGetNodePath(
1795		                       xmlTextReaderCurrentNode(reader));
1796		    }
1797#endif
1798		    fprintf(stderr,
1799		            "xmlPatternMatch and xmlStreamPush disagree\n");
1800                    if (path != NULL)
1801                        fprintf(stderr, "  pattern %s node %s\n",
1802                                pattern, path);
1803                    else
1804		        fprintf(stderr, "  pattern %s node %s\n",
1805			    pattern, xmlTextReaderConstName(reader));
1806		}
1807
1808	    }
1809	    if ((type == XML_READER_TYPE_END_ELEMENT) ||
1810	        ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
1811	        ret = xmlStreamPop(patstream);
1812		if (ret < 0) {
1813		    fprintf(stderr, "xmlStreamPop() failure\n");
1814                    xmlFreeStreamCtxt(patstream);
1815		    patstream = NULL;
1816		}
1817	    }
1818	}
1819	if (path != NULL)
1820	    xmlFree(path);
1821    }
1822#endif
1823}
1824
1825static void streamFile(char *filename) {
1826    xmlTextReaderPtr reader;
1827    int ret;
1828#ifdef HAVE_MMAP
1829    int fd = -1;
1830    struct stat info;
1831    const char *base = NULL;
1832    xmlParserInputBufferPtr input = NULL;
1833
1834    if (memory) {
1835	if (stat(filename, &info) < 0)
1836	    return;
1837	if ((fd = open(filename, O_RDONLY)) < 0)
1838	    return;
1839	base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
1840	if (base == (void *) MAP_FAILED)
1841	    return;
1842
1843	reader = xmlReaderForMemory(base, info.st_size, filename,
1844	                            NULL, options);
1845    } else
1846#endif
1847	reader = xmlReaderForFile(filename, NULL, options);
1848#ifdef LIBXML_PATTERN_ENABLED
1849    if (pattern != NULL) {
1850        patternc = xmlPatterncompile((const xmlChar *) pattern, NULL, 0, NULL);
1851	if (patternc == NULL) {
1852	    xmlGenericError(xmlGenericErrorContext,
1853		    "Pattern %s failed to compile\n", pattern);
1854            progresult = XMLLINT_ERR_SCHEMAPAT;
1855	    pattern = NULL;
1856	}
1857    }
1858    if (patternc != NULL) {
1859        patstream = xmlPatternGetStreamCtxt(patternc);
1860	if (patstream != NULL) {
1861	    ret = xmlStreamPush(patstream, NULL, NULL);
1862	    if (ret < 0) {
1863		fprintf(stderr, "xmlStreamPush() failure\n");
1864		xmlFreeStreamCtxt(patstream);
1865		patstream = NULL;
1866            }
1867	}
1868    }
1869#endif
1870
1871
1872    if (reader != NULL) {
1873#ifdef LIBXML_VALID_ENABLED
1874	if (valid)
1875	    xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1);
1876	else
1877#endif /* LIBXML_VALID_ENABLED */
1878	    if (loaddtd)
1879		xmlTextReaderSetParserProp(reader, XML_PARSER_LOADDTD, 1);
1880#ifdef LIBXML_SCHEMAS_ENABLED
1881	if (relaxng != NULL) {
1882	    if ((timing) && (!repeat)) {
1883		startTimer();
1884	    }
1885	    ret = xmlTextReaderRelaxNGValidate(reader, relaxng);
1886	    if (ret < 0) {
1887		xmlGenericError(xmlGenericErrorContext,
1888			"Relax-NG schema %s failed to compile\n", relaxng);
1889		progresult = XMLLINT_ERR_SCHEMACOMP;
1890		relaxng = NULL;
1891	    }
1892	    if ((timing) && (!repeat)) {
1893		endTimer("Compiling the schemas");
1894	    }
1895	}
1896	if (schema != NULL) {
1897	    if ((timing) && (!repeat)) {
1898		startTimer();
1899	    }
1900	    ret = xmlTextReaderSchemaValidate(reader, schema);
1901	    if (ret < 0) {
1902		xmlGenericError(xmlGenericErrorContext,
1903			"XSD schema %s failed to compile\n", schema);
1904		progresult = XMLLINT_ERR_SCHEMACOMP;
1905		schema = NULL;
1906	    }
1907	    if ((timing) && (!repeat)) {
1908		endTimer("Compiling the schemas");
1909	    }
1910	}
1911#endif
1912
1913	/*
1914	 * Process all nodes in sequence
1915	 */
1916	if ((timing) && (!repeat)) {
1917	    startTimer();
1918	}
1919	ret = xmlTextReaderRead(reader);
1920	while (ret == 1) {
1921	    if ((debug)
1922#ifdef LIBXML_PATTERN_ENABLED
1923	        || (patternc)
1924#endif
1925	       )
1926		processNode(reader);
1927	    ret = xmlTextReaderRead(reader);
1928	}
1929	if ((timing) && (!repeat)) {
1930#ifdef LIBXML_SCHEMAS_ENABLED
1931	    if (relaxng != NULL)
1932		endTimer("Parsing and validating");
1933	    else
1934#endif
1935#ifdef LIBXML_VALID_ENABLED
1936	    if (valid)
1937		endTimer("Parsing and validating");
1938	    else
1939#endif
1940	    endTimer("Parsing");
1941	}
1942
1943#ifdef LIBXML_VALID_ENABLED
1944	if (valid) {
1945	    if (xmlTextReaderIsValid(reader) != 1) {
1946		xmlGenericError(xmlGenericErrorContext,
1947			"Document %s does not validate\n", filename);
1948		progresult = XMLLINT_ERR_VALID;
1949	    }
1950	}
1951#endif /* LIBXML_VALID_ENABLED */
1952#ifdef LIBXML_SCHEMAS_ENABLED
1953	if ((relaxng != NULL) || (schema != NULL)) {
1954	    if (xmlTextReaderIsValid(reader) != 1) {
1955		fprintf(stderr, "%s fails to validate\n", filename);
1956		progresult = XMLLINT_ERR_VALID;
1957	    } else {
1958		fprintf(stderr, "%s validates\n", filename);
1959	    }
1960	}
1961#endif
1962	/*
1963	 * Done, cleanup and status
1964	 */
1965	xmlFreeTextReader(reader);
1966	if (ret != 0) {
1967	    fprintf(stderr, "%s : failed to parse\n", filename);
1968	    progresult = XMLLINT_ERR_UNCLASS;
1969	}
1970    } else {
1971	fprintf(stderr, "Unable to open %s\n", filename);
1972	progresult = XMLLINT_ERR_UNCLASS;
1973    }
1974#ifdef LIBXML_PATTERN_ENABLED
1975    if (patstream != NULL) {
1976	xmlFreeStreamCtxt(patstream);
1977	patstream = NULL;
1978    }
1979#endif
1980#ifdef HAVE_MMAP
1981    if (memory) {
1982        xmlFreeParserInputBuffer(input);
1983	munmap((char *) base, info.st_size);
1984	close(fd);
1985    }
1986#endif
1987}
1988
1989static void walkDoc(xmlDocPtr doc) {
1990    xmlTextReaderPtr reader;
1991    int ret;
1992
1993#ifdef LIBXML_PATTERN_ENABLED
1994    xmlNodePtr root;
1995    const xmlChar *namespaces[22];
1996    int i;
1997    xmlNsPtr ns;
1998
1999    root = xmlDocGetRootElement(doc);
2000    for (ns = root->nsDef, i = 0;ns != NULL && i < 20;ns=ns->next) {
2001        namespaces[i++] = ns->href;
2002        namespaces[i++] = ns->prefix;
2003    }
2004    namespaces[i++] = NULL;
2005    namespaces[i] = NULL;
2006
2007    if (pattern != NULL) {
2008        patternc = xmlPatterncompile((const xmlChar *) pattern, doc->dict,
2009	                             0, &namespaces[0]);
2010	if (patternc == NULL) {
2011	    xmlGenericError(xmlGenericErrorContext,
2012		    "Pattern %s failed to compile\n", pattern);
2013            progresult = XMLLINT_ERR_SCHEMAPAT;
2014	    pattern = NULL;
2015	}
2016    }
2017    if (patternc != NULL) {
2018        patstream = xmlPatternGetStreamCtxt(patternc);
2019	if (patstream != NULL) {
2020	    ret = xmlStreamPush(patstream, NULL, NULL);
2021	    if (ret < 0) {
2022		fprintf(stderr, "xmlStreamPush() failure\n");
2023		xmlFreeStreamCtxt(patstream);
2024		patstream = NULL;
2025            }
2026	}
2027    }
2028#endif /* LIBXML_PATTERN_ENABLED */
2029    reader = xmlReaderWalker(doc);
2030    if (reader != NULL) {
2031	if ((timing) && (!repeat)) {
2032	    startTimer();
2033	}
2034	ret = xmlTextReaderRead(reader);
2035	while (ret == 1) {
2036	    if ((debug)
2037#ifdef LIBXML_PATTERN_ENABLED
2038	        || (patternc)
2039#endif
2040	       )
2041		processNode(reader);
2042	    ret = xmlTextReaderRead(reader);
2043	}
2044	if ((timing) && (!repeat)) {
2045	    endTimer("walking through the doc");
2046	}
2047	xmlFreeTextReader(reader);
2048	if (ret != 0) {
2049	    fprintf(stderr, "failed to walk through the doc\n");
2050	    progresult = XMLLINT_ERR_UNCLASS;
2051	}
2052    } else {
2053	fprintf(stderr, "Failed to crate a reader from the document\n");
2054	progresult = XMLLINT_ERR_UNCLASS;
2055    }
2056#ifdef LIBXML_PATTERN_ENABLED
2057    if (patstream != NULL) {
2058	xmlFreeStreamCtxt(patstream);
2059	patstream = NULL;
2060    }
2061#endif
2062}
2063#endif /* LIBXML_READER_ENABLED */
2064
2065#ifdef LIBXML_XPATH_ENABLED
2066/************************************************************************
2067 *									*
2068 *			XPath Query                                     *
2069 *									*
2070 ************************************************************************/
2071
2072static void doXPathDump(xmlXPathObjectPtr cur) {
2073    switch(cur->type) {
2074        case XPATH_NODESET: {
2075            int i;
2076            xmlNodePtr node;
2077#ifdef LIBXML_OUTPUT_ENABLED
2078            xmlSaveCtxtPtr ctxt;
2079
2080            if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr <= 0)) {
2081                fprintf(stderr, "XPath set is empty\n");
2082                progresult = XMLLINT_ERR_XPATH;
2083                break;
2084            }
2085            ctxt = xmlSaveToFd(1, NULL, 0);
2086            if (ctxt == NULL) {
2087                fprintf(stderr, "Out of memory for XPath\n");
2088                progresult = XMLLINT_ERR_MEM;
2089                return;
2090            }
2091            for (i = 0;i < cur->nodesetval->nodeNr;i++) {
2092                node = cur->nodesetval->nodeTab[i];
2093                xmlSaveTree(ctxt, node);
2094            }
2095            xmlSaveClose(ctxt);
2096#else
2097            printf("xpath returned %d nodes\n", cur->nodesetval->nodeNr);
2098#endif
2099	    break;
2100        }
2101        case XPATH_BOOLEAN:
2102	    if (cur->boolval) printf("true");
2103	    else printf("false");
2104	    break;
2105        case XPATH_NUMBER:
2106	    switch (xmlXPathIsInf(cur->floatval)) {
2107	    case 1:
2108		printf("Infinity");
2109		break;
2110	    case -1:
2111		printf("-Infinity");
2112		break;
2113	    default:
2114		if (xmlXPathIsNaN(cur->floatval)) {
2115		    printf("NaN");
2116		} else {
2117		    printf("%0g", cur->floatval);
2118		}
2119	    }
2120	    break;
2121        case XPATH_STRING:
2122	    printf("%s", (const char *) cur->stringval);
2123	    break;
2124        case XPATH_UNDEFINED:
2125	    fprintf(stderr, "XPath Object is uninitialized\n");
2126            progresult = XMLLINT_ERR_XPATH;
2127	    break;
2128	default:
2129	    fprintf(stderr, "XPath object of unexpected type\n");
2130            progresult = XMLLINT_ERR_XPATH;
2131	    break;
2132    }
2133}
2134
2135static void doXPathQuery(xmlDocPtr doc, const char *query) {
2136    xmlXPathContextPtr ctxt;
2137    xmlXPathObjectPtr res;
2138
2139    ctxt = xmlXPathNewContext(doc);
2140    if (ctxt == NULL) {
2141        fprintf(stderr, "Out of memory for XPath\n");
2142        progresult = XMLLINT_ERR_MEM;
2143        return;
2144    }
2145    ctxt->node = (xmlNodePtr) doc;
2146    res = xmlXPathEval(BAD_CAST query, ctxt);
2147    xmlXPathFreeContext(ctxt);
2148
2149    if (res == NULL) {
2150        fprintf(stderr, "XPath evaluation failure\n");
2151        progresult = XMLLINT_ERR_XPATH;
2152        return;
2153    }
2154    doXPathDump(res);
2155    xmlXPathFreeObject(res);
2156}
2157#endif /* LIBXML_XPATH_ENABLED */
2158
2159/************************************************************************
2160 *									*
2161 *			Tree Test processing				*
2162 *									*
2163 ************************************************************************/
2164static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
2165    xmlDocPtr doc = NULL;
2166#ifdef LIBXML_TREE_ENABLED
2167    xmlDocPtr tmp;
2168#endif /* LIBXML_TREE_ENABLED */
2169
2170    if ((timing) && (!repeat))
2171	startTimer();
2172
2173
2174#ifdef LIBXML_TREE_ENABLED
2175    if (filename == NULL) {
2176	if (generate) {
2177	    xmlNodePtr n;
2178
2179	    doc = xmlNewDoc(BAD_CAST "1.0");
2180	    n = xmlNewDocNode(doc, NULL, BAD_CAST "info", NULL);
2181	    xmlNodeSetContent(n, BAD_CAST "abc");
2182	    xmlDocSetRootElement(doc, n);
2183	}
2184    }
2185#endif /* LIBXML_TREE_ENABLED */
2186#ifdef LIBXML_HTML_ENABLED
2187#ifdef LIBXML_PUSH_ENABLED
2188    else if ((html) && (push)) {
2189        FILE *f;
2190
2191#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2192	f = fopen(filename, "rb");
2193#else
2194	f = fopen(filename, "r");
2195#endif
2196        if (f != NULL) {
2197            int res;
2198            char chars[4096];
2199            htmlParserCtxtPtr ctxt;
2200
2201            res = fread(chars, 1, 4, f);
2202            if (res > 0) {
2203                ctxt = htmlCreatePushParserCtxt(NULL, NULL,
2204                            chars, res, filename, XML_CHAR_ENCODING_NONE);
2205                while ((res = fread(chars, 1, pushsize, f)) > 0) {
2206                    htmlParseChunk(ctxt, chars, res, 0);
2207                }
2208                htmlParseChunk(ctxt, chars, 0, 1);
2209                doc = ctxt->myDoc;
2210                htmlFreeParserCtxt(ctxt);
2211            }
2212            fclose(f);
2213        }
2214    }
2215#endif /* LIBXML_PUSH_ENABLED */
2216#ifdef HAVE_MMAP
2217    else if ((html) && (memory)) {
2218	int fd;
2219	struct stat info;
2220	const char *base;
2221	if (stat(filename, &info) < 0)
2222	    return;
2223	if ((fd = open(filename, O_RDONLY)) < 0)
2224	    return;
2225	base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
2226	if (base == (void *) MAP_FAILED)
2227	    return;
2228
2229	doc = htmlReadMemory((char *) base, info.st_size, filename,
2230	                     NULL, options);
2231
2232	munmap((char *) base, info.st_size);
2233	close(fd);
2234    }
2235#endif
2236    else if (html) {
2237	doc = htmlReadFile(filename, NULL, options);
2238    }
2239#endif /* LIBXML_HTML_ENABLED */
2240    else {
2241#ifdef LIBXML_PUSH_ENABLED
2242	/*
2243	 * build an XML tree from a string;
2244	 */
2245	if (push) {
2246	    FILE *f;
2247
2248	    /* '-' Usually means stdin -<sven@zen.org> */
2249	    if ((filename[0] == '-') && (filename[1] == 0)) {
2250	      f = stdin;
2251	    } else {
2252#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2253		f = fopen(filename, "rb");
2254#else
2255		f = fopen(filename, "r");
2256#endif
2257	    }
2258	    if (f != NULL) {
2259		int ret;
2260	        int res, size = 1024;
2261	        char chars[1024];
2262                xmlParserCtxtPtr ctxt;
2263
2264		/* if (repeat) size = 1024; */
2265		res = fread(chars, 1, 4, f);
2266		if (res > 0) {
2267		    ctxt = xmlCreatePushParserCtxt(NULL, NULL,
2268		                chars, res, filename);
2269		    xmlCtxtUseOptions(ctxt, options);
2270		    while ((res = fread(chars, 1, size, f)) > 0) {
2271			xmlParseChunk(ctxt, chars, res, 0);
2272		    }
2273		    xmlParseChunk(ctxt, chars, 0, 1);
2274		    doc = ctxt->myDoc;
2275		    ret = ctxt->wellFormed;
2276		    xmlFreeParserCtxt(ctxt);
2277		    if (!ret) {
2278			xmlFreeDoc(doc);
2279			doc = NULL;
2280		    }
2281	        }
2282                if (f != stdin)
2283                    fclose(f);
2284	    }
2285	} else
2286#endif /* LIBXML_PUSH_ENABLED */
2287        if (testIO) {
2288	    if ((filename[0] == '-') && (filename[1] == 0)) {
2289	        doc = xmlReadFd(0, NULL, NULL, options);
2290	    } else {
2291	        FILE *f;
2292
2293#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2294		f = fopen(filename, "rb");
2295#else
2296		f = fopen(filename, "r");
2297#endif
2298		if (f != NULL) {
2299		    if (rectxt == NULL)
2300			doc = xmlReadIO((xmlInputReadCallback) myRead,
2301					(xmlInputCloseCallback) myClose, f,
2302					filename, NULL, options);
2303		    else
2304			doc = xmlCtxtReadIO(rectxt,
2305			                (xmlInputReadCallback) myRead,
2306					(xmlInputCloseCallback) myClose, f,
2307					filename, NULL, options);
2308		} else
2309		    doc = NULL;
2310	    }
2311	} else if (htmlout) {
2312	    xmlParserCtxtPtr ctxt;
2313
2314	    if (rectxt == NULL)
2315		ctxt = xmlNewParserCtxt();
2316	    else
2317	        ctxt = rectxt;
2318	    if (ctxt == NULL) {
2319	        doc = NULL;
2320	    } else {
2321	        ctxt->sax->error = xmlHTMLError;
2322	        ctxt->sax->warning = xmlHTMLWarning;
2323	        ctxt->vctxt.error = xmlHTMLValidityError;
2324	        ctxt->vctxt.warning = xmlHTMLValidityWarning;
2325
2326		doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
2327
2328		if (rectxt == NULL)
2329		    xmlFreeParserCtxt(ctxt);
2330	    }
2331#ifdef HAVE_MMAP
2332	} else if (memory) {
2333	    int fd;
2334	    struct stat info;
2335	    const char *base;
2336	    if (stat(filename, &info) < 0)
2337		return;
2338	    if ((fd = open(filename, O_RDONLY)) < 0)
2339		return;
2340	    base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
2341	    if (base == (void *) MAP_FAILED)
2342	        return;
2343
2344	    if (rectxt == NULL)
2345		doc = xmlReadMemory((char *) base, info.st_size,
2346		                    filename, NULL, options);
2347	    else
2348		doc = xmlCtxtReadMemory(rectxt, (char *) base, info.st_size,
2349			                filename, NULL, options);
2350
2351	    munmap((char *) base, info.st_size);
2352	    close(fd);
2353#endif
2354#ifdef LIBXML_VALID_ENABLED
2355	} else if (valid) {
2356	    xmlParserCtxtPtr ctxt = NULL;
2357
2358	    if (rectxt == NULL)
2359		ctxt = xmlNewParserCtxt();
2360	    else
2361	        ctxt = rectxt;
2362	    if (ctxt == NULL) {
2363	        doc = NULL;
2364	    } else {
2365		doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
2366
2367		if (ctxt->valid == 0)
2368		    progresult = XMLLINT_ERR_RDFILE;
2369		if (rectxt == NULL)
2370		    xmlFreeParserCtxt(ctxt);
2371	    }
2372#endif /* LIBXML_VALID_ENABLED */
2373	} else {
2374	    if (rectxt != NULL)
2375	        doc = xmlCtxtReadFile(rectxt, filename, NULL, options);
2376	    else {
2377#ifdef LIBXML_SAX1_ENABLED
2378                if (sax1)
2379		    doc = xmlParseFile(filename);
2380		else
2381#endif /* LIBXML_SAX1_ENABLED */
2382		doc = xmlReadFile(filename, NULL, options);
2383	    }
2384	}
2385    }
2386
2387    /*
2388     * If we don't have a document we might as well give up.  Do we
2389     * want an error message here?  <sven@zen.org> */
2390    if (doc == NULL) {
2391	progresult = XMLLINT_ERR_UNCLASS;
2392	return;
2393    }
2394
2395    if ((timing) && (!repeat)) {
2396	endTimer("Parsing");
2397    }
2398
2399    /*
2400     * Remove DOCTYPE nodes
2401     */
2402    if (dropdtd) {
2403	xmlDtdPtr dtd;
2404
2405	dtd = xmlGetIntSubset(doc);
2406	if (dtd != NULL) {
2407	    xmlUnlinkNode((xmlNodePtr)dtd);
2408	    xmlFreeDtd(dtd);
2409	}
2410    }
2411
2412#ifdef LIBXML_XINCLUDE_ENABLED
2413    if (xinclude) {
2414	if ((timing) && (!repeat)) {
2415	    startTimer();
2416	}
2417	if (xmlXIncludeProcessFlags(doc, options) < 0)
2418	    progresult = XMLLINT_ERR_UNCLASS;
2419	if ((timing) && (!repeat)) {
2420	    endTimer("Xinclude processing");
2421	}
2422    }
2423#endif
2424
2425#ifdef LIBXML_XPATH_ENABLED
2426    if (xpathquery != NULL) {
2427        doXPathQuery(doc, xpathquery);
2428    }
2429#endif
2430
2431#ifdef LIBXML_DEBUG_ENABLED
2432#ifdef LIBXML_XPATH_ENABLED
2433    /*
2434     * shell interaction
2435     */
2436    if (shell) {
2437        xmlXPathOrderDocElems(doc);
2438        xmlShell(doc, filename, xmlShellReadline, stdout);
2439    }
2440#endif
2441#endif
2442
2443#ifdef LIBXML_TREE_ENABLED
2444    /*
2445     * test intermediate copy if needed.
2446     */
2447    if (copy) {
2448        tmp = doc;
2449	if (timing) {
2450	    startTimer();
2451	}
2452	doc = xmlCopyDoc(doc, 1);
2453	if (timing) {
2454	    endTimer("Copying");
2455	}
2456	if (timing) {
2457	    startTimer();
2458	}
2459	xmlFreeDoc(tmp);
2460	if (timing) {
2461	    endTimer("Freeing original");
2462	}
2463    }
2464#endif /* LIBXML_TREE_ENABLED */
2465
2466#ifdef LIBXML_VALID_ENABLED
2467    if ((insert) && (!html)) {
2468        const xmlChar* list[256];
2469	int nb, i;
2470	xmlNodePtr node;
2471
2472	if (doc->children != NULL) {
2473	    node = doc->children;
2474	    while ((node != NULL) && (node->last == NULL)) node = node->next;
2475	    if (node != NULL) {
2476		nb = xmlValidGetValidElements(node->last, NULL, list, 256);
2477		if (nb < 0) {
2478		    fprintf(stderr, "could not get valid list of elements\n");
2479		} else if (nb == 0) {
2480		    fprintf(stderr, "No element can be inserted under root\n");
2481		} else {
2482		    fprintf(stderr, "%d element types can be inserted under root:\n",
2483		           nb);
2484		    for (i = 0;i < nb;i++) {
2485			 fprintf(stderr, "%s\n", (char *) list[i]);
2486		    }
2487		}
2488	    }
2489	}
2490    }else
2491#endif /* LIBXML_VALID_ENABLED */
2492#ifdef LIBXML_READER_ENABLED
2493    if (walker) {
2494        walkDoc(doc);
2495    }
2496#endif /* LIBXML_READER_ENABLED */
2497#ifdef LIBXML_OUTPUT_ENABLED
2498    if (noout == 0) {
2499        int ret;
2500
2501	/*
2502	 * print it.
2503	 */
2504#ifdef LIBXML_DEBUG_ENABLED
2505	if (!debug) {
2506#endif
2507	    if ((timing) && (!repeat)) {
2508		startTimer();
2509	    }
2510#ifdef LIBXML_HTML_ENABLED
2511            if ((html) && (!xmlout)) {
2512		if (compress) {
2513		    htmlSaveFile(output ? output : "-", doc);
2514		}
2515		else if (encoding != NULL) {
2516		    if (format == 1) {
2517			htmlSaveFileFormat(output ? output : "-", doc, encoding, 1);
2518		    }
2519		    else {
2520			htmlSaveFileFormat(output ? output : "-", doc, encoding, 0);
2521		    }
2522		}
2523		else if (format == 1) {
2524		    htmlSaveFileFormat(output ? output : "-", doc, NULL, 1);
2525		}
2526		else {
2527		    FILE *out;
2528		    if (output == NULL)
2529			out = stdout;
2530		    else {
2531			out = fopen(output,"wb");
2532		    }
2533		    if (out != NULL) {
2534			if (htmlDocDump(out, doc) < 0)
2535			    progresult = XMLLINT_ERR_OUT;
2536
2537			if (output != NULL)
2538			    fclose(out);
2539		    } else {
2540			fprintf(stderr, "failed to open %s\n", output);
2541			progresult = XMLLINT_ERR_OUT;
2542		    }
2543		}
2544		if ((timing) && (!repeat)) {
2545		    endTimer("Saving");
2546		}
2547	    } else
2548#endif
2549#ifdef LIBXML_C14N_ENABLED
2550            if (canonical) {
2551	        xmlChar *result = NULL;
2552		int size;
2553
2554		size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_1_0, NULL, 1, &result);
2555		if (size >= 0) {
2556		    if (write(1, result, size) == -1) {
2557		        fprintf(stderr, "Can't write data\n");
2558		    }
2559		    xmlFree(result);
2560		} else {
2561		    fprintf(stderr, "Failed to canonicalize\n");
2562		    progresult = XMLLINT_ERR_OUT;
2563		}
2564	    } else if (canonical) {
2565	        xmlChar *result = NULL;
2566		int size;
2567
2568		size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_1_1, NULL, 1, &result);
2569		if (size >= 0) {
2570		    if (write(1, result, size) == -1) {
2571		        fprintf(stderr, "Can't write data\n");
2572		    }
2573		    xmlFree(result);
2574		} else {
2575		    fprintf(stderr, "Failed to canonicalize\n");
2576		    progresult = XMLLINT_ERR_OUT;
2577		}
2578	    } else
2579            if (exc_canonical) {
2580	        xmlChar *result = NULL;
2581		int size;
2582
2583		size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_EXCLUSIVE_1_0, NULL, 1, &result);
2584		if (size >= 0) {
2585		    if (write(1, result, size) == -1) {
2586		        fprintf(stderr, "Can't write data\n");
2587		    }
2588		    xmlFree(result);
2589		} else {
2590		    fprintf(stderr, "Failed to canonicalize\n");
2591		    progresult = XMLLINT_ERR_OUT;
2592		}
2593	    } else
2594#endif
2595#ifdef HAVE_MMAP
2596	    if (memory) {
2597		xmlChar *result;
2598		int len;
2599
2600		if (encoding != NULL) {
2601		    if (format == 1) {
2602		        xmlDocDumpFormatMemoryEnc(doc, &result, &len, encoding, 1);
2603		    } else {
2604			xmlDocDumpMemoryEnc(doc, &result, &len, encoding);
2605		    }
2606		} else {
2607		    if (format == 1)
2608			xmlDocDumpFormatMemory(doc, &result, &len, 1);
2609		    else
2610			xmlDocDumpMemory(doc, &result, &len);
2611		}
2612		if (result == NULL) {
2613		    fprintf(stderr, "Failed to save\n");
2614		    progresult = XMLLINT_ERR_OUT;
2615		} else {
2616		    if (write(1, result, len) == -1) {
2617		        fprintf(stderr, "Can't write data\n");
2618		    }
2619		    xmlFree(result);
2620		}
2621
2622	    } else
2623#endif /* HAVE_MMAP */
2624	    if (compress) {
2625		xmlSaveFile(output ? output : "-", doc);
2626	    } else if (oldout) {
2627	        if (encoding != NULL) {
2628		    if (format == 1) {
2629			ret = xmlSaveFormatFileEnc(output ? output : "-", doc,
2630						   encoding, 1);
2631		    }
2632		    else {
2633			ret = xmlSaveFileEnc(output ? output : "-", doc,
2634			                     encoding);
2635		    }
2636		    if (ret < 0) {
2637			fprintf(stderr, "failed save to %s\n",
2638				output ? output : "-");
2639			progresult = XMLLINT_ERR_OUT;
2640		    }
2641		} else if (format == 1) {
2642		    ret = xmlSaveFormatFile(output ? output : "-", doc, 1);
2643		    if (ret < 0) {
2644			fprintf(stderr, "failed save to %s\n",
2645				output ? output : "-");
2646			progresult = XMLLINT_ERR_OUT;
2647		    }
2648		} else {
2649		    FILE *out;
2650		    if (output == NULL)
2651			out = stdout;
2652		    else {
2653			out = fopen(output,"wb");
2654		    }
2655		    if (out != NULL) {
2656			if (xmlDocDump(out, doc) < 0)
2657			    progresult = XMLLINT_ERR_OUT;
2658
2659			if (output != NULL)
2660			    fclose(out);
2661		    } else {
2662			fprintf(stderr, "failed to open %s\n", output);
2663			progresult = XMLLINT_ERR_OUT;
2664		    }
2665		}
2666	    } else {
2667	        xmlSaveCtxtPtr ctxt;
2668		int saveOpts = 0;
2669
2670                if (format == 1)
2671		    saveOpts |= XML_SAVE_FORMAT;
2672                else if (format == 2)
2673                    saveOpts |= XML_SAVE_WSNONSIG;
2674
2675#if defined(LIBXML_HTML_ENABLED) || defined(LIBXML_VALID_ENABLED)
2676                if (xmlout)
2677                    saveOpts |= XML_SAVE_AS_XML;
2678#endif
2679
2680		if (output == NULL)
2681		    ctxt = xmlSaveToFd(1, encoding, saveOpts);
2682		else
2683		    ctxt = xmlSaveToFilename(output, encoding, saveOpts);
2684
2685		if (ctxt != NULL) {
2686		    if (xmlSaveDoc(ctxt, doc) < 0) {
2687			fprintf(stderr, "failed save to %s\n",
2688				output ? output : "-");
2689			progresult = XMLLINT_ERR_OUT;
2690		    }
2691		    xmlSaveClose(ctxt);
2692		} else {
2693		    progresult = XMLLINT_ERR_OUT;
2694		}
2695	    }
2696	    if ((timing) && (!repeat)) {
2697		endTimer("Saving");
2698	    }
2699#ifdef LIBXML_DEBUG_ENABLED
2700	} else {
2701	    FILE *out;
2702	    if (output == NULL)
2703	        out = stdout;
2704	    else {
2705		out = fopen(output,"wb");
2706	    }
2707	    if (out != NULL) {
2708		xmlDebugDumpDocument(out, doc);
2709
2710		if (output != NULL)
2711		    fclose(out);
2712	    } else {
2713		fprintf(stderr, "failed to open %s\n", output);
2714		progresult = XMLLINT_ERR_OUT;
2715	    }
2716	}
2717#endif
2718    }
2719#endif /* LIBXML_OUTPUT_ENABLED */
2720
2721#ifdef LIBXML_VALID_ENABLED
2722    /*
2723     * A posteriori validation test
2724     */
2725    if ((dtdvalid != NULL) || (dtdvalidfpi != NULL)) {
2726	xmlDtdPtr dtd;
2727
2728	if ((timing) && (!repeat)) {
2729	    startTimer();
2730	}
2731	if (dtdvalid != NULL)
2732	    dtd = xmlParseDTD(NULL, (const xmlChar *)dtdvalid);
2733	else
2734	    dtd = xmlParseDTD((const xmlChar *)dtdvalidfpi, NULL);
2735	if ((timing) && (!repeat)) {
2736	    endTimer("Parsing DTD");
2737	}
2738	if (dtd == NULL) {
2739	    if (dtdvalid != NULL)
2740		xmlGenericError(xmlGenericErrorContext,
2741			"Could not parse DTD %s\n", dtdvalid);
2742	    else
2743		xmlGenericError(xmlGenericErrorContext,
2744			"Could not parse DTD %s\n", dtdvalidfpi);
2745	    progresult = XMLLINT_ERR_DTD;
2746	} else {
2747	    xmlValidCtxtPtr cvp;
2748
2749	    if ((cvp = xmlNewValidCtxt()) == NULL) {
2750		xmlGenericError(xmlGenericErrorContext,
2751			"Couldn't allocate validation context\n");
2752		exit(-1);
2753	    }
2754	    cvp->userData = (void *) stderr;
2755	    cvp->error    = (xmlValidityErrorFunc) fprintf;
2756	    cvp->warning  = (xmlValidityWarningFunc) fprintf;
2757
2758	    if ((timing) && (!repeat)) {
2759		startTimer();
2760	    }
2761	    if (!xmlValidateDtd(cvp, doc, dtd)) {
2762		if (dtdvalid != NULL)
2763		    xmlGenericError(xmlGenericErrorContext,
2764			    "Document %s does not validate against %s\n",
2765			    filename, dtdvalid);
2766		else
2767		    xmlGenericError(xmlGenericErrorContext,
2768			    "Document %s does not validate against %s\n",
2769			    filename, dtdvalidfpi);
2770		progresult = XMLLINT_ERR_VALID;
2771	    }
2772	    if ((timing) && (!repeat)) {
2773		endTimer("Validating against DTD");
2774	    }
2775	    xmlFreeValidCtxt(cvp);
2776	    xmlFreeDtd(dtd);
2777	}
2778    } else if (postvalid) {
2779	xmlValidCtxtPtr cvp;
2780
2781	if ((cvp = xmlNewValidCtxt()) == NULL) {
2782	    xmlGenericError(xmlGenericErrorContext,
2783		    "Couldn't allocate validation context\n");
2784	    exit(-1);
2785	}
2786
2787	if ((timing) && (!repeat)) {
2788	    startTimer();
2789	}
2790	cvp->userData = (void *) stderr;
2791	cvp->error    = (xmlValidityErrorFunc) fprintf;
2792	cvp->warning  = (xmlValidityWarningFunc) fprintf;
2793	if (!xmlValidateDocument(cvp, doc)) {
2794	    xmlGenericError(xmlGenericErrorContext,
2795		    "Document %s does not validate\n", filename);
2796	    progresult = XMLLINT_ERR_VALID;
2797	}
2798	if ((timing) && (!repeat)) {
2799	    endTimer("Validating");
2800	}
2801	xmlFreeValidCtxt(cvp);
2802    }
2803#endif /* LIBXML_VALID_ENABLED */
2804#ifdef LIBXML_SCHEMATRON_ENABLED
2805    if (wxschematron != NULL) {
2806	xmlSchematronValidCtxtPtr ctxt;
2807	int ret;
2808	int flag;
2809
2810	if ((timing) && (!repeat)) {
2811	    startTimer();
2812	}
2813
2814	if (debug)
2815	    flag = XML_SCHEMATRON_OUT_XML;
2816	else
2817	    flag = XML_SCHEMATRON_OUT_TEXT;
2818	if (noout)
2819	    flag |= XML_SCHEMATRON_OUT_QUIET;
2820	ctxt = xmlSchematronNewValidCtxt(wxschematron, flag);
2821#if 0
2822	xmlSchematronSetValidErrors(ctxt,
2823		(xmlSchematronValidityErrorFunc) fprintf,
2824		(xmlSchematronValidityWarningFunc) fprintf,
2825		stderr);
2826#endif
2827	ret = xmlSchematronValidateDoc(ctxt, doc);
2828	if (ret == 0) {
2829	    fprintf(stderr, "%s validates\n", filename);
2830	} else if (ret > 0) {
2831	    fprintf(stderr, "%s fails to validate\n", filename);
2832	    progresult = XMLLINT_ERR_VALID;
2833	} else {
2834	    fprintf(stderr, "%s validation generated an internal error\n",
2835		   filename);
2836	    progresult = XMLLINT_ERR_VALID;
2837	}
2838	xmlSchematronFreeValidCtxt(ctxt);
2839	if ((timing) && (!repeat)) {
2840	    endTimer("Validating");
2841	}
2842    }
2843#endif
2844#ifdef LIBXML_SCHEMAS_ENABLED
2845    if (relaxngschemas != NULL) {
2846	xmlRelaxNGValidCtxtPtr ctxt;
2847	int ret;
2848
2849	if ((timing) && (!repeat)) {
2850	    startTimer();
2851	}
2852
2853	ctxt = xmlRelaxNGNewValidCtxt(relaxngschemas);
2854	xmlRelaxNGSetValidErrors(ctxt,
2855		(xmlRelaxNGValidityErrorFunc) fprintf,
2856		(xmlRelaxNGValidityWarningFunc) fprintf,
2857		stderr);
2858	ret = xmlRelaxNGValidateDoc(ctxt, doc);
2859	if (ret == 0) {
2860	    fprintf(stderr, "%s validates\n", filename);
2861	} else if (ret > 0) {
2862	    fprintf(stderr, "%s fails to validate\n", filename);
2863	    progresult = XMLLINT_ERR_VALID;
2864	} else {
2865	    fprintf(stderr, "%s validation generated an internal error\n",
2866		   filename);
2867	    progresult = XMLLINT_ERR_VALID;
2868	}
2869	xmlRelaxNGFreeValidCtxt(ctxt);
2870	if ((timing) && (!repeat)) {
2871	    endTimer("Validating");
2872	}
2873    } else if (wxschemas != NULL) {
2874	xmlSchemaValidCtxtPtr ctxt;
2875	int ret;
2876
2877	if ((timing) && (!repeat)) {
2878	    startTimer();
2879	}
2880
2881	ctxt = xmlSchemaNewValidCtxt(wxschemas);
2882	xmlSchemaSetValidErrors(ctxt,
2883		(xmlSchemaValidityErrorFunc) fprintf,
2884		(xmlSchemaValidityWarningFunc) fprintf,
2885		stderr);
2886	ret = xmlSchemaValidateDoc(ctxt, doc);
2887	if (ret == 0) {
2888	    fprintf(stderr, "%s validates\n", filename);
2889	} else if (ret > 0) {
2890	    fprintf(stderr, "%s fails to validate\n", filename);
2891	    progresult = XMLLINT_ERR_VALID;
2892	} else {
2893	    fprintf(stderr, "%s validation generated an internal error\n",
2894		   filename);
2895	    progresult = XMLLINT_ERR_VALID;
2896	}
2897	xmlSchemaFreeValidCtxt(ctxt);
2898	if ((timing) && (!repeat)) {
2899	    endTimer("Validating");
2900	}
2901    }
2902#endif
2903
2904#ifdef LIBXML_DEBUG_ENABLED
2905#if defined(LIBXML_HTML_ENABLED) || defined(LIBXML_VALID_ENABLED)
2906    if ((debugent) && (!html))
2907	xmlDebugDumpEntities(stderr, doc);
2908#endif
2909#endif
2910
2911    /*
2912     * free it.
2913     */
2914    if ((timing) && (!repeat)) {
2915	startTimer();
2916    }
2917    xmlFreeDoc(doc);
2918    if ((timing) && (!repeat)) {
2919	endTimer("Freeing");
2920    }
2921}
2922
2923/************************************************************************
2924 *									*
2925 *			Usage and Main					*
2926 *									*
2927 ************************************************************************/
2928
2929static void showVersion(const char *name) {
2930    fprintf(stderr, "%s: using libxml version %s\n", name, xmlParserVersion);
2931    fprintf(stderr, "   compiled with: ");
2932    if (xmlHasFeature(XML_WITH_THREAD)) fprintf(stderr, "Threads ");
2933    if (xmlHasFeature(XML_WITH_TREE)) fprintf(stderr, "Tree ");
2934    if (xmlHasFeature(XML_WITH_OUTPUT)) fprintf(stderr, "Output ");
2935    if (xmlHasFeature(XML_WITH_PUSH)) fprintf(stderr, "Push ");
2936    if (xmlHasFeature(XML_WITH_READER)) fprintf(stderr, "Reader ");
2937    if (xmlHasFeature(XML_WITH_PATTERN)) fprintf(stderr, "Patterns ");
2938    if (xmlHasFeature(XML_WITH_WRITER)) fprintf(stderr, "Writer ");
2939    if (xmlHasFeature(XML_WITH_SAX1)) fprintf(stderr, "SAXv1 ");
2940    if (xmlHasFeature(XML_WITH_FTP)) fprintf(stderr, "FTP ");
2941    if (xmlHasFeature(XML_WITH_HTTP)) fprintf(stderr, "HTTP ");
2942    if (xmlHasFeature(XML_WITH_VALID)) fprintf(stderr, "DTDValid ");
2943    if (xmlHasFeature(XML_WITH_HTML)) fprintf(stderr, "HTML ");
2944    if (xmlHasFeature(XML_WITH_LEGACY)) fprintf(stderr, "Legacy ");
2945    if (xmlHasFeature(XML_WITH_C14N)) fprintf(stderr, "C14N ");
2946    if (xmlHasFeature(XML_WITH_CATALOG)) fprintf(stderr, "Catalog ");
2947    if (xmlHasFeature(XML_WITH_XPATH)) fprintf(stderr, "XPath ");
2948    if (xmlHasFeature(XML_WITH_XPTR)) fprintf(stderr, "XPointer ");
2949    if (xmlHasFeature(XML_WITH_XINCLUDE)) fprintf(stderr, "XInclude ");
2950    if (xmlHasFeature(XML_WITH_ICONV)) fprintf(stderr, "Iconv ");
2951    if (xmlHasFeature(XML_WITH_ISO8859X)) fprintf(stderr, "ISO8859X ");
2952    if (xmlHasFeature(XML_WITH_UNICODE)) fprintf(stderr, "Unicode ");
2953    if (xmlHasFeature(XML_WITH_REGEXP)) fprintf(stderr, "Regexps ");
2954    if (xmlHasFeature(XML_WITH_AUTOMATA)) fprintf(stderr, "Automata ");
2955    if (xmlHasFeature(XML_WITH_EXPR)) fprintf(stderr, "Expr ");
2956    if (xmlHasFeature(XML_WITH_SCHEMAS)) fprintf(stderr, "Schemas ");
2957    if (xmlHasFeature(XML_WITH_SCHEMATRON)) fprintf(stderr, "Schematron ");
2958    if (xmlHasFeature(XML_WITH_MODULES)) fprintf(stderr, "Modules ");
2959    if (xmlHasFeature(XML_WITH_DEBUG)) fprintf(stderr, "Debug ");
2960    if (xmlHasFeature(XML_WITH_DEBUG_MEM)) fprintf(stderr, "MemDebug ");
2961    if (xmlHasFeature(XML_WITH_DEBUG_RUN)) fprintf(stderr, "RunDebug ");
2962    if (xmlHasFeature(XML_WITH_ZLIB)) fprintf(stderr, "Zlib ");
2963    if (xmlHasFeature(XML_WITH_LZMA)) fprintf(stderr, "Lzma ");
2964    fprintf(stderr, "\n");
2965}
2966
2967static void usage(const char *name) {
2968    printf("Usage : %s [options] XMLfiles ...\n", name);
2969#ifdef LIBXML_OUTPUT_ENABLED
2970    printf("\tParse the XML files and output the result of the parsing\n");
2971#else
2972    printf("\tParse the XML files\n");
2973#endif /* LIBXML_OUTPUT_ENABLED */
2974    printf("\t--version : display the version of the XML library used\n");
2975#ifdef LIBXML_DEBUG_ENABLED
2976    printf("\t--debug : dump a debug tree of the in-memory document\n");
2977    printf("\t--shell : run a navigating shell\n");
2978    printf("\t--debugent : debug the entities defined in the document\n");
2979#else
2980#ifdef LIBXML_READER_ENABLED
2981    printf("\t--debug : dump the nodes content when using --stream\n");
2982#endif /* LIBXML_READER_ENABLED */
2983#endif
2984#ifdef LIBXML_TREE_ENABLED
2985    printf("\t--copy : used to test the internal copy implementation\n");
2986#endif /* LIBXML_TREE_ENABLED */
2987    printf("\t--recover : output what was parsable on broken XML documents\n");
2988    printf("\t--huge : remove any internal arbitrary parser limits\n");
2989    printf("\t--noent : substitute entity references by their value\n");
2990    printf("\t--noenc : ignore any encoding specified inside the document\n");
2991    printf("\t--noout : don't output the result tree\n");
2992    printf("\t--path 'paths': provide a set of paths for resources\n");
2993    printf("\t--load-trace : print trace of all external entites loaded\n");
2994    printf("\t--nonet : refuse to fetch DTDs or entities over network\n");
2995    printf("\t--nocompact : do not generate compact text nodes\n");
2996    printf("\t--htmlout : output results as HTML\n");
2997    printf("\t--nowrap : do not put HTML doc wrapper\n");
2998#ifdef LIBXML_VALID_ENABLED
2999    printf("\t--valid : validate the document in addition to std well-formed check\n");
3000    printf("\t--postvalid : do a posteriori validation, i.e after parsing\n");
3001    printf("\t--dtdvalid URL : do a posteriori validation against a given DTD\n");
3002    printf("\t--dtdvalidfpi FPI : same but name the DTD with a Public Identifier\n");
3003#endif /* LIBXML_VALID_ENABLED */
3004    printf("\t--timing : print some timings\n");
3005    printf("\t--output file or -o file: save to a given file\n");
3006    printf("\t--repeat : repeat 100 times, for timing or profiling\n");
3007    printf("\t--insert : ad-hoc test for valid insertions\n");
3008#ifdef LIBXML_OUTPUT_ENABLED
3009#ifdef HAVE_ZLIB_H
3010    printf("\t--compress : turn on gzip compression of output\n");
3011#endif
3012#endif /* LIBXML_OUTPUT_ENABLED */
3013#ifdef LIBXML_HTML_ENABLED
3014    printf("\t--html : use the HTML parser\n");
3015    printf("\t--xmlout : force to use the XML serializer when using --html\n");
3016    printf("\t--nodefdtd : do not default HTML doctype\n");
3017#endif
3018#ifdef LIBXML_PUSH_ENABLED
3019    printf("\t--push : use the push mode of the parser\n");
3020    printf("\t--pushsmall : use the push mode of the parser using tiny increments\n");
3021#endif /* LIBXML_PUSH_ENABLED */
3022#ifdef HAVE_MMAP
3023    printf("\t--memory : parse from memory\n");
3024#endif
3025    printf("\t--maxmem nbbytes : limits memory allocation to nbbytes bytes\n");
3026    printf("\t--nowarning : do not emit warnings from parser/validator\n");
3027    printf("\t--noblanks : drop (ignorable?) blanks spaces\n");
3028    printf("\t--nocdata : replace cdata section with text nodes\n");
3029#ifdef LIBXML_OUTPUT_ENABLED
3030    printf("\t--format : reformat/reindent the input\n");
3031    printf("\t--encode encoding : output in the given encoding\n");
3032    printf("\t--dropdtd : remove the DOCTYPE of the input docs\n");
3033    printf("\t--pretty STYLE : pretty-print in a particular style\n");
3034    printf("\t                 0 Do not pretty print\n");
3035    printf("\t                 1 Format the XML content, as --format\n");
3036    printf("\t                 2 Add whitespace inside tags, preserving content\n");
3037#endif /* LIBXML_OUTPUT_ENABLED */
3038    printf("\t--c14n : save in W3C canonical format v1.0 (with comments)\n");
3039    printf("\t--c14n11 : save in W3C canonical format v1.1 (with comments)\n");
3040    printf("\t--exc-c14n : save in W3C exclusive canonical format (with comments)\n");
3041#ifdef LIBXML_C14N_ENABLED
3042#endif /* LIBXML_C14N_ENABLED */
3043    printf("\t--nsclean : remove redundant namespace declarations\n");
3044    printf("\t--testIO : test user I/O support\n");
3045#ifdef LIBXML_CATALOG_ENABLED
3046    printf("\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES\n");
3047    printf("\t             otherwise XML Catalogs starting from \n");
3048    printf("\t         %s are activated by default\n", XML_XML_DEFAULT_CATALOG);
3049    printf("\t--nocatalogs: deactivate all catalogs\n");
3050#endif
3051    printf("\t--auto : generate a small doc on the fly\n");
3052#ifdef LIBXML_XINCLUDE_ENABLED
3053    printf("\t--xinclude : do XInclude processing\n");
3054    printf("\t--noxincludenode : same but do not generate XInclude nodes\n");
3055    printf("\t--nofixup-base-uris : do not fixup xml:base uris\n");
3056#endif
3057    printf("\t--loaddtd : fetch external DTD\n");
3058    printf("\t--dtdattr : loaddtd + populate the tree with inherited attributes \n");
3059#ifdef LIBXML_READER_ENABLED
3060    printf("\t--stream : use the streaming interface to process very large files\n");
3061    printf("\t--walker : create a reader and walk though the resulting doc\n");
3062#endif /* LIBXML_READER_ENABLED */
3063#ifdef LIBXML_PATTERN_ENABLED
3064    printf("\t--pattern pattern_value : test the pattern support\n");
3065#endif
3066    printf("\t--chkregister : verify the node registration code\n");
3067#ifdef LIBXML_SCHEMAS_ENABLED
3068    printf("\t--relaxng schema : do RelaxNG validation against the schema\n");
3069    printf("\t--schema schema : do validation against the WXS schema\n");
3070#endif
3071#ifdef LIBXML_SCHEMATRON_ENABLED
3072    printf("\t--schematron schema : do validation against a schematron\n");
3073#endif
3074#ifdef LIBXML_SAX1_ENABLED
3075    printf("\t--sax1: use the old SAX1 interfaces for processing\n");
3076#endif
3077    printf("\t--sax: do not build a tree but work just at the SAX level\n");
3078    printf("\t--oldxml10: use XML-1.0 parsing rules before the 5th edition\n");
3079#ifdef LIBXML_XPATH_ENABLED
3080    printf("\t--xpath expr: evaluate the XPath expression, imply --noout\n");
3081#endif
3082
3083    printf("\nLibxml project home page: http://xmlsoft.org/\n");
3084    printf("To report bugs or get some help check: http://xmlsoft.org/bugs.html\n");
3085}
3086
3087static void registerNode(xmlNodePtr node)
3088{
3089    node->_private = malloc(sizeof(long));
3090    *(long*)node->_private = (long) 0x81726354;
3091    nbregister++;
3092}
3093
3094static void deregisterNode(xmlNodePtr node)
3095{
3096    assert(node->_private != NULL);
3097    assert(*(long*)node->_private == (long) 0x81726354);
3098    free(node->_private);
3099    nbregister--;
3100}
3101
3102int
3103main(int argc, char **argv) {
3104    int i, acount;
3105    int files = 0;
3106    int version = 0;
3107    const char* indent;
3108
3109    if (argc <= 1) {
3110	usage(argv[0]);
3111	return(1);
3112    }
3113    LIBXML_TEST_VERSION
3114    for (i = 1; i < argc ; i++) {
3115	if (!strcmp(argv[i], "-"))
3116	    break;
3117
3118	if (argv[i][0] != '-')
3119	    continue;
3120	if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
3121	    debug++;
3122	else
3123#ifdef LIBXML_DEBUG_ENABLED
3124	if ((!strcmp(argv[i], "-shell")) ||
3125	         (!strcmp(argv[i], "--shell"))) {
3126	    shell++;
3127            noout = 1;
3128        } else
3129#endif
3130#ifdef LIBXML_TREE_ENABLED
3131	if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
3132	    copy++;
3133	else
3134#endif /* LIBXML_TREE_ENABLED */
3135	if ((!strcmp(argv[i], "-recover")) ||
3136	         (!strcmp(argv[i], "--recover"))) {
3137	    recovery++;
3138	    options |= XML_PARSE_RECOVER;
3139	} else if ((!strcmp(argv[i], "-huge")) ||
3140	         (!strcmp(argv[i], "--huge"))) {
3141	    options |= XML_PARSE_HUGE;
3142	} else if ((!strcmp(argv[i], "-noent")) ||
3143	         (!strcmp(argv[i], "--noent"))) {
3144	    noent++;
3145	    options |= XML_PARSE_NOENT;
3146	} else if ((!strcmp(argv[i], "-noenc")) ||
3147	         (!strcmp(argv[i], "--noenc"))) {
3148	    noenc++;
3149	    options |= XML_PARSE_IGNORE_ENC;
3150	} else if ((!strcmp(argv[i], "-nsclean")) ||
3151	         (!strcmp(argv[i], "--nsclean"))) {
3152	    options |= XML_PARSE_NSCLEAN;
3153	} else if ((!strcmp(argv[i], "-nocdata")) ||
3154	         (!strcmp(argv[i], "--nocdata"))) {
3155	    options |= XML_PARSE_NOCDATA;
3156	} else if ((!strcmp(argv[i], "-nodict")) ||
3157	         (!strcmp(argv[i], "--nodict"))) {
3158	    options |= XML_PARSE_NODICT;
3159	} else if ((!strcmp(argv[i], "-version")) ||
3160	         (!strcmp(argv[i], "--version"))) {
3161	    showVersion(argv[0]);
3162	    version = 1;
3163	} else if ((!strcmp(argv[i], "-noout")) ||
3164	         (!strcmp(argv[i], "--noout")))
3165	    noout++;
3166#ifdef LIBXML_OUTPUT_ENABLED
3167	else if ((!strcmp(argv[i], "-o")) ||
3168	         (!strcmp(argv[i], "-output")) ||
3169	         (!strcmp(argv[i], "--output"))) {
3170	    i++;
3171	    output = argv[i];
3172	}
3173#endif /* LIBXML_OUTPUT_ENABLED */
3174	else if ((!strcmp(argv[i], "-htmlout")) ||
3175	         (!strcmp(argv[i], "--htmlout")))
3176	    htmlout++;
3177	else if ((!strcmp(argv[i], "-nowrap")) ||
3178	         (!strcmp(argv[i], "--nowrap")))
3179	    nowrap++;
3180#ifdef LIBXML_HTML_ENABLED
3181	else if ((!strcmp(argv[i], "-html")) ||
3182	         (!strcmp(argv[i], "--html"))) {
3183	    html++;
3184        }
3185	else if ((!strcmp(argv[i], "-xmlout")) ||
3186	         (!strcmp(argv[i], "--xmlout"))) {
3187	    xmlout++;
3188	} else if ((!strcmp(argv[i], "-nodefdtd")) ||
3189	         (!strcmp(argv[i], "--nodefdtd"))) {
3190            nodefdtd++;
3191	    options |= HTML_PARSE_NODEFDTD;
3192        }
3193#endif /* LIBXML_HTML_ENABLED */
3194	else if ((!strcmp(argv[i], "-loaddtd")) ||
3195	         (!strcmp(argv[i], "--loaddtd"))) {
3196	    loaddtd++;
3197	    options |= XML_PARSE_DTDLOAD;
3198	} else if ((!strcmp(argv[i], "-dtdattr")) ||
3199	         (!strcmp(argv[i], "--dtdattr"))) {
3200	    loaddtd++;
3201	    dtdattrs++;
3202	    options |= XML_PARSE_DTDATTR;
3203	}
3204#ifdef LIBXML_VALID_ENABLED
3205	else if ((!strcmp(argv[i], "-valid")) ||
3206	         (!strcmp(argv[i], "--valid"))) {
3207	    valid++;
3208	    options |= XML_PARSE_DTDVALID;
3209	} else if ((!strcmp(argv[i], "-postvalid")) ||
3210	         (!strcmp(argv[i], "--postvalid"))) {
3211	    postvalid++;
3212	    loaddtd++;
3213	    options |= XML_PARSE_DTDLOAD;
3214	} else if ((!strcmp(argv[i], "-dtdvalid")) ||
3215	         (!strcmp(argv[i], "--dtdvalid"))) {
3216	    i++;
3217	    dtdvalid = argv[i];
3218	    loaddtd++;
3219	    options |= XML_PARSE_DTDLOAD;
3220	} else if ((!strcmp(argv[i], "-dtdvalidfpi")) ||
3221	         (!strcmp(argv[i], "--dtdvalidfpi"))) {
3222	    i++;
3223	    dtdvalidfpi = argv[i];
3224	    loaddtd++;
3225	    options |= XML_PARSE_DTDLOAD;
3226        }
3227#endif /* LIBXML_VALID_ENABLED */
3228	else if ((!strcmp(argv[i], "-dropdtd")) ||
3229	         (!strcmp(argv[i], "--dropdtd")))
3230	    dropdtd++;
3231	else if ((!strcmp(argv[i], "-insert")) ||
3232	         (!strcmp(argv[i], "--insert")))
3233	    insert++;
3234	else if ((!strcmp(argv[i], "-timing")) ||
3235	         (!strcmp(argv[i], "--timing")))
3236	    timing++;
3237	else if ((!strcmp(argv[i], "-auto")) ||
3238	         (!strcmp(argv[i], "--auto")))
3239	    generate++;
3240	else if ((!strcmp(argv[i], "-repeat")) ||
3241	         (!strcmp(argv[i], "--repeat"))) {
3242	    if (repeat)
3243	        repeat *= 10;
3244	    else
3245	        repeat = 100;
3246	}
3247#ifdef LIBXML_PUSH_ENABLED
3248	else if ((!strcmp(argv[i], "-push")) ||
3249	         (!strcmp(argv[i], "--push")))
3250	    push++;
3251	else if ((!strcmp(argv[i], "-pushsmall")) ||
3252	         (!strcmp(argv[i], "--pushsmall"))) {
3253	    push++;
3254            pushsize = 10;
3255        }
3256#endif /* LIBXML_PUSH_ENABLED */
3257#ifdef HAVE_MMAP
3258	else if ((!strcmp(argv[i], "-memory")) ||
3259	         (!strcmp(argv[i], "--memory")))
3260	    memory++;
3261#endif
3262	else if ((!strcmp(argv[i], "-testIO")) ||
3263	         (!strcmp(argv[i], "--testIO")))
3264	    testIO++;
3265#ifdef LIBXML_XINCLUDE_ENABLED
3266	else if ((!strcmp(argv[i], "-xinclude")) ||
3267	         (!strcmp(argv[i], "--xinclude"))) {
3268	    xinclude++;
3269	    options |= XML_PARSE_XINCLUDE;
3270	}
3271	else if ((!strcmp(argv[i], "-noxincludenode")) ||
3272	         (!strcmp(argv[i], "--noxincludenode"))) {
3273	    xinclude++;
3274	    options |= XML_PARSE_XINCLUDE;
3275	    options |= XML_PARSE_NOXINCNODE;
3276	}
3277	else if ((!strcmp(argv[i], "-nofixup-base-uris")) ||
3278	         (!strcmp(argv[i], "--nofixup-base-uris"))) {
3279	    xinclude++;
3280	    options |= XML_PARSE_XINCLUDE;
3281	    options |= XML_PARSE_NOBASEFIX;
3282	}
3283#endif
3284#ifdef LIBXML_OUTPUT_ENABLED
3285#ifdef HAVE_ZLIB_H
3286	else if ((!strcmp(argv[i], "-compress")) ||
3287	         (!strcmp(argv[i], "--compress"))) {
3288	    compress++;
3289	    xmlSetCompressMode(9);
3290        }
3291#endif
3292#endif /* LIBXML_OUTPUT_ENABLED */
3293	else if ((!strcmp(argv[i], "-nowarning")) ||
3294	         (!strcmp(argv[i], "--nowarning"))) {
3295	    xmlGetWarningsDefaultValue = 0;
3296	    xmlPedanticParserDefault(0);
3297	    options |= XML_PARSE_NOWARNING;
3298        }
3299	else if ((!strcmp(argv[i], "-pedantic")) ||
3300	         (!strcmp(argv[i], "--pedantic"))) {
3301	    xmlGetWarningsDefaultValue = 1;
3302	    xmlPedanticParserDefault(1);
3303	    options |= XML_PARSE_PEDANTIC;
3304        }
3305#ifdef LIBXML_DEBUG_ENABLED
3306	else if ((!strcmp(argv[i], "-debugent")) ||
3307		 (!strcmp(argv[i], "--debugent"))) {
3308	    debugent++;
3309	    xmlParserDebugEntities = 1;
3310	}
3311#endif
3312#ifdef LIBXML_C14N_ENABLED
3313	else if ((!strcmp(argv[i], "-c14n")) ||
3314		 (!strcmp(argv[i], "--c14n"))) {
3315	    canonical++;
3316	    options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD;
3317	}
3318	else if ((!strcmp(argv[i], "-c14n11")) ||
3319		 (!strcmp(argv[i], "--c14n11"))) {
3320	    canonical_11++;
3321	    options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD;
3322	}
3323	else if ((!strcmp(argv[i], "-exc-c14n")) ||
3324		 (!strcmp(argv[i], "--exc-c14n"))) {
3325	    exc_canonical++;
3326	    options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD;
3327	}
3328#endif
3329#ifdef LIBXML_CATALOG_ENABLED
3330	else if ((!strcmp(argv[i], "-catalogs")) ||
3331		 (!strcmp(argv[i], "--catalogs"))) {
3332	    catalogs++;
3333	} else if ((!strcmp(argv[i], "-nocatalogs")) ||
3334		 (!strcmp(argv[i], "--nocatalogs"))) {
3335	    nocatalogs++;
3336	}
3337#endif
3338	else if ((!strcmp(argv[i], "-encode")) ||
3339	         (!strcmp(argv[i], "--encode"))) {
3340	    i++;
3341	    encoding = argv[i];
3342	    /*
3343	     * OK it's for testing purposes
3344	     */
3345	    xmlAddEncodingAlias("UTF-8", "DVEnc");
3346        }
3347	else if ((!strcmp(argv[i], "-noblanks")) ||
3348	         (!strcmp(argv[i], "--noblanks"))) {
3349	    noblanks++;
3350	    xmlKeepBlanksDefault(0);
3351	    options |= XML_PARSE_NOBLANKS;
3352        }
3353	else if ((!strcmp(argv[i], "-maxmem")) ||
3354	         (!strcmp(argv[i], "--maxmem"))) {
3355	     i++;
3356	     if (sscanf(argv[i], "%d", &maxmem) == 1) {
3357	         xmlMemSetup(myFreeFunc, myMallocFunc, myReallocFunc,
3358		             myStrdupFunc);
3359	     } else {
3360	         maxmem = 0;
3361	     }
3362        }
3363	else if ((!strcmp(argv[i], "-format")) ||
3364	         (!strcmp(argv[i], "--format"))) {
3365	     noblanks++;
3366#ifdef LIBXML_OUTPUT_ENABLED
3367	     format = 1;
3368#endif /* LIBXML_OUTPUT_ENABLED */
3369	     xmlKeepBlanksDefault(0);
3370	}
3371	else if ((!strcmp(argv[i], "-pretty")) ||
3372	         (!strcmp(argv[i], "--pretty"))) {
3373	     i++;
3374#ifdef LIBXML_OUTPUT_ENABLED
3375	     format = atoi(argv[i]);
3376	     if (format == 1) {
3377	         noblanks++;
3378	         xmlKeepBlanksDefault(0);
3379	     }
3380#endif /* LIBXML_OUTPUT_ENABLED */
3381	}
3382#ifdef LIBXML_READER_ENABLED
3383	else if ((!strcmp(argv[i], "-stream")) ||
3384	         (!strcmp(argv[i], "--stream"))) {
3385	     stream++;
3386	}
3387	else if ((!strcmp(argv[i], "-walker")) ||
3388	         (!strcmp(argv[i], "--walker"))) {
3389	     walker++;
3390             noout++;
3391	}
3392#endif /* LIBXML_READER_ENABLED */
3393#ifdef LIBXML_SAX1_ENABLED
3394	else if ((!strcmp(argv[i], "-sax1")) ||
3395	         (!strcmp(argv[i], "--sax1"))) {
3396	    sax1++;
3397	    options |= XML_PARSE_SAX1;
3398	}
3399#endif /* LIBXML_SAX1_ENABLED */
3400	else if ((!strcmp(argv[i], "-sax")) ||
3401	         (!strcmp(argv[i], "--sax"))) {
3402	    sax++;
3403	}
3404	else if ((!strcmp(argv[i], "-chkregister")) ||
3405	         (!strcmp(argv[i], "--chkregister"))) {
3406	    chkregister++;
3407#ifdef LIBXML_SCHEMAS_ENABLED
3408	} else if ((!strcmp(argv[i], "-relaxng")) ||
3409	         (!strcmp(argv[i], "--relaxng"))) {
3410	    i++;
3411	    relaxng = argv[i];
3412	    noent++;
3413	    options |= XML_PARSE_NOENT;
3414	} else if ((!strcmp(argv[i], "-schema")) ||
3415	         (!strcmp(argv[i], "--schema"))) {
3416	    i++;
3417	    schema = argv[i];
3418	    noent++;
3419#endif
3420#ifdef LIBXML_SCHEMATRON_ENABLED
3421	} else if ((!strcmp(argv[i], "-schematron")) ||
3422	         (!strcmp(argv[i], "--schematron"))) {
3423	    i++;
3424	    schematron = argv[i];
3425	    noent++;
3426#endif
3427        } else if ((!strcmp(argv[i], "-nonet")) ||
3428                   (!strcmp(argv[i], "--nonet"))) {
3429	    options |= XML_PARSE_NONET;
3430	    xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader);
3431        } else if ((!strcmp(argv[i], "-nocompact")) ||
3432                   (!strcmp(argv[i], "--nocompact"))) {
3433	    options &= ~XML_PARSE_COMPACT;
3434	} else if ((!strcmp(argv[i], "-load-trace")) ||
3435	           (!strcmp(argv[i], "--load-trace"))) {
3436	    load_trace++;
3437        } else if ((!strcmp(argv[i], "-path")) ||
3438                   (!strcmp(argv[i], "--path"))) {
3439	    i++;
3440	    parsePath(BAD_CAST argv[i]);
3441#ifdef LIBXML_PATTERN_ENABLED
3442        } else if ((!strcmp(argv[i], "-pattern")) ||
3443                   (!strcmp(argv[i], "--pattern"))) {
3444	    i++;
3445	    pattern = argv[i];
3446#endif
3447#ifdef LIBXML_XPATH_ENABLED
3448        } else if ((!strcmp(argv[i], "-xpath")) ||
3449                   (!strcmp(argv[i], "--xpath"))) {
3450	    i++;
3451	    noout++;
3452	    xpathquery = argv[i];
3453#endif
3454	} else if ((!strcmp(argv[i], "-oldxml10")) ||
3455	           (!strcmp(argv[i], "--oldxml10"))) {
3456	    oldxml10++;
3457	    options |= XML_PARSE_OLD10;
3458	} else {
3459	    fprintf(stderr, "Unknown option %s\n", argv[i]);
3460	    usage(argv[0]);
3461	    return(1);
3462	}
3463    }
3464
3465#ifdef LIBXML_CATALOG_ENABLED
3466    if (nocatalogs == 0) {
3467	if (catalogs) {
3468	    const char *catal;
3469
3470	    catal = getenv("SGML_CATALOG_FILES");
3471	    if (catal != NULL) {
3472		xmlLoadCatalogs(catal);
3473	    } else {
3474		fprintf(stderr, "Variable $SGML_CATALOG_FILES not set\n");
3475	    }
3476	}
3477    }
3478#endif
3479
3480#ifdef LIBXML_SAX1_ENABLED
3481    if (sax1)
3482        xmlSAXDefaultVersion(1);
3483    else
3484        xmlSAXDefaultVersion(2);
3485#endif /* LIBXML_SAX1_ENABLED */
3486
3487    if (chkregister) {
3488	xmlRegisterNodeDefault(registerNode);
3489	xmlDeregisterNodeDefault(deregisterNode);
3490    }
3491
3492    indent = getenv("XMLLINT_INDENT");
3493    if(indent != NULL) {
3494	xmlTreeIndentString = indent;
3495    }
3496
3497
3498    defaultEntityLoader = xmlGetExternalEntityLoader();
3499    xmlSetExternalEntityLoader(xmllintExternalEntityLoader);
3500
3501    xmlLineNumbersDefault(1);
3502    if (loaddtd != 0)
3503	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
3504    if (dtdattrs)
3505	xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
3506    if (noent != 0) xmlSubstituteEntitiesDefault(1);
3507#ifdef LIBXML_VALID_ENABLED
3508    if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
3509#endif /* LIBXML_VALID_ENABLED */
3510    if ((htmlout) && (!nowrap)) {
3511	xmlGenericError(xmlGenericErrorContext,
3512         "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
3513	xmlGenericError(xmlGenericErrorContext,
3514		"\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
3515	xmlGenericError(xmlGenericErrorContext,
3516	 "<html><head><title>%s output</title></head>\n",
3517		argv[0]);
3518	xmlGenericError(xmlGenericErrorContext,
3519	 "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\n",
3520		argv[0]);
3521    }
3522
3523#ifdef LIBXML_SCHEMATRON_ENABLED
3524    if ((schematron != NULL) && (sax == 0)
3525#ifdef LIBXML_READER_ENABLED
3526        && (stream == 0)
3527#endif /* LIBXML_READER_ENABLED */
3528	) {
3529	xmlSchematronParserCtxtPtr ctxt;
3530
3531        /* forces loading the DTDs */
3532        xmlLoadExtDtdDefaultValue |= 1;
3533	options |= XML_PARSE_DTDLOAD;
3534	if (timing) {
3535	    startTimer();
3536	}
3537	ctxt = xmlSchematronNewParserCtxt(schematron);
3538#if 0
3539	xmlSchematronSetParserErrors(ctxt,
3540		(xmlSchematronValidityErrorFunc) fprintf,
3541		(xmlSchematronValidityWarningFunc) fprintf,
3542		stderr);
3543#endif
3544	wxschematron = xmlSchematronParse(ctxt);
3545	if (wxschematron == NULL) {
3546	    xmlGenericError(xmlGenericErrorContext,
3547		    "Schematron schema %s failed to compile\n", schematron);
3548            progresult = XMLLINT_ERR_SCHEMACOMP;
3549	    schematron = NULL;
3550	}
3551	xmlSchematronFreeParserCtxt(ctxt);
3552	if (timing) {
3553	    endTimer("Compiling the schemas");
3554	}
3555    }
3556#endif
3557#ifdef LIBXML_SCHEMAS_ENABLED
3558    if ((relaxng != NULL) && (sax == 0)
3559#ifdef LIBXML_READER_ENABLED
3560        && (stream == 0)
3561#endif /* LIBXML_READER_ENABLED */
3562	) {
3563	xmlRelaxNGParserCtxtPtr ctxt;
3564
3565        /* forces loading the DTDs */
3566        xmlLoadExtDtdDefaultValue |= 1;
3567	options |= XML_PARSE_DTDLOAD;
3568	if (timing) {
3569	    startTimer();
3570	}
3571	ctxt = xmlRelaxNGNewParserCtxt(relaxng);
3572	xmlRelaxNGSetParserErrors(ctxt,
3573		(xmlRelaxNGValidityErrorFunc) fprintf,
3574		(xmlRelaxNGValidityWarningFunc) fprintf,
3575		stderr);
3576	relaxngschemas = xmlRelaxNGParse(ctxt);
3577	if (relaxngschemas == NULL) {
3578	    xmlGenericError(xmlGenericErrorContext,
3579		    "Relax-NG schema %s failed to compile\n", relaxng);
3580            progresult = XMLLINT_ERR_SCHEMACOMP;
3581	    relaxng = NULL;
3582	}
3583	xmlRelaxNGFreeParserCtxt(ctxt);
3584	if (timing) {
3585	    endTimer("Compiling the schemas");
3586	}
3587    } else if ((schema != NULL)
3588#ifdef LIBXML_READER_ENABLED
3589		&& (stream == 0)
3590#endif
3591	) {
3592	xmlSchemaParserCtxtPtr ctxt;
3593
3594	if (timing) {
3595	    startTimer();
3596	}
3597	ctxt = xmlSchemaNewParserCtxt(schema);
3598	xmlSchemaSetParserErrors(ctxt,
3599		(xmlSchemaValidityErrorFunc) fprintf,
3600		(xmlSchemaValidityWarningFunc) fprintf,
3601		stderr);
3602	wxschemas = xmlSchemaParse(ctxt);
3603	if (wxschemas == NULL) {
3604	    xmlGenericError(xmlGenericErrorContext,
3605		    "WXS schema %s failed to compile\n", schema);
3606            progresult = XMLLINT_ERR_SCHEMACOMP;
3607	    schema = NULL;
3608	}
3609	xmlSchemaFreeParserCtxt(ctxt);
3610	if (timing) {
3611	    endTimer("Compiling the schemas");
3612	}
3613    }
3614#endif /* LIBXML_SCHEMAS_ENABLED */
3615#ifdef LIBXML_PATTERN_ENABLED
3616    if ((pattern != NULL)
3617#ifdef LIBXML_READER_ENABLED
3618        && (walker == 0)
3619#endif
3620	) {
3621        patternc = xmlPatterncompile((const xmlChar *) pattern, NULL, 0, NULL);
3622	if (patternc == NULL) {
3623	    xmlGenericError(xmlGenericErrorContext,
3624		    "Pattern %s failed to compile\n", pattern);
3625            progresult = XMLLINT_ERR_SCHEMAPAT;
3626	    pattern = NULL;
3627	}
3628    }
3629#endif /* LIBXML_PATTERN_ENABLED */
3630    for (i = 1; i < argc ; i++) {
3631	if ((!strcmp(argv[i], "-encode")) ||
3632	         (!strcmp(argv[i], "--encode"))) {
3633	    i++;
3634	    continue;
3635        } else if ((!strcmp(argv[i], "-o")) ||
3636                   (!strcmp(argv[i], "-output")) ||
3637                   (!strcmp(argv[i], "--output"))) {
3638            i++;
3639	    continue;
3640        }
3641#ifdef LIBXML_VALID_ENABLED
3642	if ((!strcmp(argv[i], "-dtdvalid")) ||
3643	         (!strcmp(argv[i], "--dtdvalid"))) {
3644	    i++;
3645	    continue;
3646        }
3647	if ((!strcmp(argv[i], "-path")) ||
3648                   (!strcmp(argv[i], "--path"))) {
3649            i++;
3650	    continue;
3651        }
3652	if ((!strcmp(argv[i], "-dtdvalidfpi")) ||
3653	         (!strcmp(argv[i], "--dtdvalidfpi"))) {
3654	    i++;
3655	    continue;
3656        }
3657#endif /* LIBXML_VALID_ENABLED */
3658	if ((!strcmp(argv[i], "-relaxng")) ||
3659	         (!strcmp(argv[i], "--relaxng"))) {
3660	    i++;
3661	    continue;
3662        }
3663	if ((!strcmp(argv[i], "-maxmem")) ||
3664	         (!strcmp(argv[i], "--maxmem"))) {
3665	    i++;
3666	    continue;
3667        }
3668	if ((!strcmp(argv[i], "-pretty")) ||
3669	         (!strcmp(argv[i], "--pretty"))) {
3670	    i++;
3671	    continue;
3672        }
3673	if ((!strcmp(argv[i], "-schema")) ||
3674	         (!strcmp(argv[i], "--schema"))) {
3675	    i++;
3676	    continue;
3677        }
3678	if ((!strcmp(argv[i], "-schematron")) ||
3679	         (!strcmp(argv[i], "--schematron"))) {
3680	    i++;
3681	    continue;
3682        }
3683#ifdef LIBXML_PATTERN_ENABLED
3684        if ((!strcmp(argv[i], "-pattern")) ||
3685	    (!strcmp(argv[i], "--pattern"))) {
3686	    i++;
3687	    continue;
3688	}
3689#endif
3690#ifdef LIBXML_XPATH_ENABLED
3691        if ((!strcmp(argv[i], "-xpath")) ||
3692	    (!strcmp(argv[i], "--xpath"))) {
3693	    i++;
3694	    continue;
3695	}
3696#endif
3697	if ((timing) && (repeat))
3698	    startTimer();
3699	/* Remember file names.  "-" means stdin.  <sven@zen.org> */
3700	if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
3701	    if (repeat) {
3702		xmlParserCtxtPtr ctxt = NULL;
3703
3704		for (acount = 0;acount < repeat;acount++) {
3705#ifdef LIBXML_READER_ENABLED
3706		    if (stream != 0) {
3707			streamFile(argv[i]);
3708		    } else {
3709#endif /* LIBXML_READER_ENABLED */
3710                        if (sax) {
3711			    testSAX(argv[i]);
3712			} else {
3713			    if (ctxt == NULL)
3714				ctxt = xmlNewParserCtxt();
3715			    parseAndPrintFile(argv[i], ctxt);
3716			}
3717#ifdef LIBXML_READER_ENABLED
3718		    }
3719#endif /* LIBXML_READER_ENABLED */
3720		}
3721		if (ctxt != NULL)
3722		    xmlFreeParserCtxt(ctxt);
3723	    } else {
3724		nbregister = 0;
3725
3726#ifdef LIBXML_READER_ENABLED
3727		if (stream != 0)
3728		    streamFile(argv[i]);
3729		else
3730#endif /* LIBXML_READER_ENABLED */
3731                if (sax) {
3732		    testSAX(argv[i]);
3733		} else {
3734		    parseAndPrintFile(argv[i], NULL);
3735		}
3736
3737                if ((chkregister) && (nbregister != 0)) {
3738		    fprintf(stderr, "Registration count off: %d\n", nbregister);
3739		    progresult = XMLLINT_ERR_RDREGIS;
3740		}
3741	    }
3742	    files ++;
3743	    if ((timing) && (repeat)) {
3744		endTimer("%d iterations", repeat);
3745	    }
3746	}
3747    }
3748    if (generate)
3749	parseAndPrintFile(NULL, NULL);
3750    if ((htmlout) && (!nowrap)) {
3751	xmlGenericError(xmlGenericErrorContext, "</body></html>\n");
3752    }
3753    if ((files == 0) && (!generate) && (version == 0)) {
3754	usage(argv[0]);
3755    }
3756#ifdef LIBXML_SCHEMATRON_ENABLED
3757    if (wxschematron != NULL)
3758	xmlSchematronFree(wxschematron);
3759#endif
3760#ifdef LIBXML_SCHEMAS_ENABLED
3761    if (relaxngschemas != NULL)
3762	xmlRelaxNGFree(relaxngschemas);
3763    if (wxschemas != NULL)
3764	xmlSchemaFree(wxschemas);
3765    xmlRelaxNGCleanupTypes();
3766#endif
3767#ifdef LIBXML_PATTERN_ENABLED
3768    if (patternc != NULL)
3769        xmlFreePattern(patternc);
3770#endif
3771    xmlCleanupParser();
3772    xmlMemoryDump();
3773
3774    return(progresult);
3775}
3776
3777