1/*
2 * testHTML.c : a small tester program for HTML input.
3 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9#include "libxml.h"
10
11#ifdef LIBXML_HTML_ENABLED
12
13#include <string.h>
14#include <stdarg.h>
15
16
17#ifdef HAVE_SYS_TYPES_H
18#include <sys/types.h>
19#endif
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#ifdef HAVE_FCNTL_H
24#include <fcntl.h>
25#endif
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29#ifdef HAVE_STDLIB_H
30#include <stdlib.h>
31#endif
32
33#include <libxml/xmlmemory.h>
34#include <libxml/HTMLparser.h>
35#include <libxml/HTMLtree.h>
36#include <libxml/debugXML.h>
37#include <libxml/xmlerror.h>
38#include <libxml/globals.h>
39
40#ifdef LIBXML_DEBUG_ENABLED
41static int debug = 0;
42#endif
43static int copy = 0;
44static int sax = 0;
45static int repeat = 0;
46static int noout = 0;
47#ifdef LIBXML_PUSH_ENABLED
48static int push = 0;
49#endif /* LIBXML_PUSH_ENABLED */
50static char *encoding = NULL;
51static int options = 0;
52
53static xmlSAXHandler emptySAXHandlerStruct = {
54    NULL, /* internalSubset */
55    NULL, /* isStandalone */
56    NULL, /* hasInternalSubset */
57    NULL, /* hasExternalSubset */
58    NULL, /* resolveEntity */
59    NULL, /* getEntity */
60    NULL, /* entityDecl */
61    NULL, /* notationDecl */
62    NULL, /* attributeDecl */
63    NULL, /* elementDecl */
64    NULL, /* unparsedEntityDecl */
65    NULL, /* setDocumentLocator */
66    NULL, /* startDocument */
67    NULL, /* endDocument */
68    NULL, /* startElement */
69    NULL, /* endElement */
70    NULL, /* reference */
71    NULL, /* characters */
72    NULL, /* ignorableWhitespace */
73    NULL, /* processingInstruction */
74    NULL, /* comment */
75    NULL, /* xmlParserWarning */
76    NULL, /* xmlParserError */
77    NULL, /* xmlParserError */
78    NULL, /* getParameterEntity */
79    NULL, /* cdataBlock */
80    NULL, /* externalSubset */
81    1,    /* initialized */
82    NULL, /* private */
83    NULL, /* startElementNsSAX2Func */
84    NULL, /* endElementNsSAX2Func */
85    NULL  /* xmlStructuredErrorFunc */
86};
87
88static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
89extern xmlSAXHandlerPtr debugSAXHandler;
90
91/************************************************************************
92 *									*
93 *				Debug Handlers				*
94 *									*
95 ************************************************************************/
96
97/**
98 * isStandaloneDebug:
99 * @ctxt:  An XML parser context
100 *
101 * Is this document tagged standalone ?
102 *
103 * Returns 1 if true
104 */
105static int
106isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
107{
108    fprintf(stdout, "SAX.isStandalone()\n");
109    return(0);
110}
111
112/**
113 * hasInternalSubsetDebug:
114 * @ctxt:  An XML parser context
115 *
116 * Does this document has an internal subset
117 *
118 * Returns 1 if true
119 */
120static int
121hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
122{
123    fprintf(stdout, "SAX.hasInternalSubset()\n");
124    return(0);
125}
126
127/**
128 * hasExternalSubsetDebug:
129 * @ctxt:  An XML parser context
130 *
131 * Does this document has an external subset
132 *
133 * Returns 1 if true
134 */
135static int
136hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
137{
138    fprintf(stdout, "SAX.hasExternalSubset()\n");
139    return(0);
140}
141
142/**
143 * hasInternalSubsetDebug:
144 * @ctxt:  An XML parser context
145 *
146 * Does this document has an internal subset
147 */
148static void
149internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
150	       const xmlChar *ExternalID, const xmlChar *SystemID)
151{
152    fprintf(stdout, "SAX.internalSubset(%s,", name);
153    if (ExternalID == NULL)
154	fprintf(stdout, " ,");
155    else
156	fprintf(stdout, " %s,", ExternalID);
157    if (SystemID == NULL)
158	fprintf(stdout, " )\n");
159    else
160	fprintf(stdout, " %s)\n", SystemID);
161}
162
163/**
164 * resolveEntityDebug:
165 * @ctxt:  An XML parser context
166 * @publicId: The public ID of the entity
167 * @systemId: The system ID of the entity
168 *
169 * Special entity resolver, better left to the parser, it has
170 * more context than the application layer.
171 * The default behaviour is to NOT resolve the entities, in that case
172 * the ENTITY_REF nodes are built in the structure (and the parameter
173 * values).
174 *
175 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
176 */
177static xmlParserInputPtr
178resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
179{
180    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
181
182
183    fprintf(stdout, "SAX.resolveEntity(");
184    if (publicId != NULL)
185	fprintf(stdout, "%s", (char *)publicId);
186    else
187	fprintf(stdout, " ");
188    if (systemId != NULL)
189	fprintf(stdout, ", %s)\n", (char *)systemId);
190    else
191	fprintf(stdout, ", )\n");
192/*********
193    if (systemId != NULL) {
194        return(xmlNewInputFromFile(ctxt, (char *) systemId));
195    }
196 *********/
197    return(NULL);
198}
199
200/**
201 * getEntityDebug:
202 * @ctxt:  An XML parser context
203 * @name: The entity name
204 *
205 * Get an entity by name
206 *
207 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
208 */
209static xmlEntityPtr
210getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
211{
212    fprintf(stdout, "SAX.getEntity(%s)\n", name);
213    return(NULL);
214}
215
216/**
217 * getParameterEntityDebug:
218 * @ctxt:  An XML parser context
219 * @name: The entity name
220 *
221 * Get a parameter entity by name
222 *
223 * Returns the xmlParserInputPtr
224 */
225static xmlEntityPtr
226getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
227{
228    fprintf(stdout, "SAX.getParameterEntity(%s)\n", name);
229    return(NULL);
230}
231
232
233/**
234 * entityDeclDebug:
235 * @ctxt:  An XML parser context
236 * @name:  the entity name
237 * @type:  the entity type
238 * @publicId: The public ID of the entity
239 * @systemId: The system ID of the entity
240 * @content: the entity value (without processing).
241 *
242 * An entity definition has been parsed
243 */
244static void
245entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
246          const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
247{
248    fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
249            name, type, publicId, systemId, content);
250}
251
252/**
253 * attributeDeclDebug:
254 * @ctxt:  An XML parser context
255 * @name:  the attribute name
256 * @type:  the attribute type
257 *
258 * An attribute definition has been parsed
259 */
260static void
261attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *elem, const xmlChar *name,
262              int type, int def, const xmlChar *defaultValue,
263	      xmlEnumerationPtr tree ATTRIBUTE_UNUSED)
264{
265    fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
266            elem, name, type, def, defaultValue);
267}
268
269/**
270 * elementDeclDebug:
271 * @ctxt:  An XML parser context
272 * @name:  the element name
273 * @type:  the element type
274 * @content: the element value (without processing).
275 *
276 * An element definition has been parsed
277 */
278static void
279elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
280	    xmlElementContentPtr content ATTRIBUTE_UNUSED)
281{
282    fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n",
283            name, type);
284}
285
286/**
287 * notationDeclDebug:
288 * @ctxt:  An XML parser context
289 * @name: The name of the notation
290 * @publicId: The public ID of the entity
291 * @systemId: The system ID of the entity
292 *
293 * What to do when a notation declaration has been parsed.
294 */
295static void
296notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
297	     const xmlChar *publicId, const xmlChar *systemId)
298{
299    fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n",
300            (char *) name, (char *) publicId, (char *) systemId);
301}
302
303/**
304 * unparsedEntityDeclDebug:
305 * @ctxt:  An XML parser context
306 * @name: The name of the entity
307 * @publicId: The public ID of the entity
308 * @systemId: The system ID of the entity
309 * @notationName: the name of the notation
310 *
311 * What to do when an unparsed entity declaration is parsed
312 */
313static void
314unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
315		   const xmlChar *publicId, const xmlChar *systemId,
316		   const xmlChar *notationName)
317{
318    fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
319            (char *) name, (char *) publicId, (char *) systemId,
320	    (char *) notationName);
321}
322
323/**
324 * setDocumentLocatorDebug:
325 * @ctxt:  An XML parser context
326 * @loc: A SAX Locator
327 *
328 * Receive the document locator at startup, actually xmlDefaultSAXLocator
329 * Everything is available on the context, so this is useless in our case.
330 */
331static void
332setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
333{
334    fprintf(stdout, "SAX.setDocumentLocator()\n");
335}
336
337/**
338 * startDocumentDebug:
339 * @ctxt:  An XML parser context
340 *
341 * called when the document start being processed.
342 */
343static void
344startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
345{
346    fprintf(stdout, "SAX.startDocument()\n");
347}
348
349/**
350 * endDocumentDebug:
351 * @ctxt:  An XML parser context
352 *
353 * called when the document end has been detected.
354 */
355static void
356endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
357{
358    fprintf(stdout, "SAX.endDocument()\n");
359}
360
361/**
362 * startElementDebug:
363 * @ctxt:  An XML parser context
364 * @name:  The element name
365 *
366 * called when an opening tag has been processed.
367 */
368static void
369startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
370{
371    int i;
372
373    fprintf(stdout, "SAX.startElement(%s", (char *) name);
374    if (atts != NULL) {
375        for (i = 0;(atts[i] != NULL);i++) {
376	    fprintf(stdout, ", %s", atts[i++]);
377	    if (atts[i] != NULL) {
378		unsigned char output[40];
379		const unsigned char *att = atts[i];
380		int outlen, attlen;
381	        fprintf(stdout, "='");
382		while ((attlen = strlen((char*)att)) > 0) {
383		    outlen = sizeof output - 1;
384		    htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
385		    output[outlen] = 0;
386		    fprintf(stdout, "%s", (char *) output);
387		    att += attlen;
388		}
389		fprintf(stdout, "'");
390	    }
391	}
392    }
393    fprintf(stdout, ")\n");
394}
395
396/**
397 * endElementDebug:
398 * @ctxt:  An XML parser context
399 * @name:  The element name
400 *
401 * called when the end of an element has been detected.
402 */
403static void
404endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
405{
406    fprintf(stdout, "SAX.endElement(%s)\n", (char *) name);
407}
408
409/**
410 * charactersDebug:
411 * @ctxt:  An XML parser context
412 * @ch:  a xmlChar string
413 * @len: the number of xmlChar
414 *
415 * receiving some chars from the parser.
416 * Question: how much at a time ???
417 */
418static void
419charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
420{
421    unsigned char output[40];
422    int inlen = len, outlen = 30;
423
424    htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
425    output[outlen] = 0;
426
427    fprintf(stdout, "SAX.characters(%s, %d)\n", output, len);
428}
429
430/**
431 * cdataDebug:
432 * @ctxt:  An XML parser context
433 * @ch:  a xmlChar string
434 * @len: the number of xmlChar
435 *
436 * receiving some cdata chars from the parser.
437 * Question: how much at a time ???
438 */
439static void
440cdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
441{
442    unsigned char output[40];
443    int inlen = len, outlen = 30;
444
445    htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
446    output[outlen] = 0;
447
448    fprintf(stdout, "SAX.cdata(%s, %d)\n", output, len);
449}
450
451/**
452 * referenceDebug:
453 * @ctxt:  An XML parser context
454 * @name:  The entity name
455 *
456 * called when an entity reference is detected.
457 */
458static void
459referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
460{
461    fprintf(stdout, "SAX.reference(%s)\n", name);
462}
463
464/**
465 * ignorableWhitespaceDebug:
466 * @ctxt:  An XML parser context
467 * @ch:  a xmlChar string
468 * @start: the first char in the string
469 * @len: the number of xmlChar
470 *
471 * receiving some ignorable whitespaces from the parser.
472 * Question: how much at a time ???
473 */
474static void
475ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
476{
477    char output[40];
478    int i;
479
480    for (i = 0;(i<len) && (i < 30);i++)
481	output[i] = ch[i];
482    output[i] = 0;
483
484    fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
485}
486
487/**
488 * processingInstructionDebug:
489 * @ctxt:  An XML parser context
490 * @target:  the target name
491 * @data: the PI data's
492 * @len: the number of xmlChar
493 *
494 * A processing instruction has been parsed.
495 */
496static void
497processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
498                      const xmlChar *data)
499{
500    fprintf(stdout, "SAX.processingInstruction(%s, %s)\n",
501            (char *) target, (char *) data);
502}
503
504/**
505 * commentDebug:
506 * @ctxt:  An XML parser context
507 * @value:  the comment content
508 *
509 * A comment has been parsed.
510 */
511static void
512commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
513{
514    fprintf(stdout, "SAX.comment(%s)\n", value);
515}
516
517/**
518 * warningDebug:
519 * @ctxt:  An XML parser context
520 * @msg:  the message to display/transmit
521 * @...:  extra parameters for the message display
522 *
523 * Display and format a warning messages, gives file, line, position and
524 * extra parameters.
525 */
526static void XMLCDECL
527warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
528{
529    va_list args;
530
531    va_start(args, msg);
532    fprintf(stdout, "SAX.warning: ");
533    vfprintf(stdout, msg, args);
534    va_end(args);
535}
536
537/**
538 * errorDebug:
539 * @ctxt:  An XML parser context
540 * @msg:  the message to display/transmit
541 * @...:  extra parameters for the message display
542 *
543 * Display and format a error messages, gives file, line, position and
544 * extra parameters.
545 */
546static void XMLCDECL
547errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
548{
549    va_list args;
550
551    va_start(args, msg);
552    fprintf(stdout, "SAX.error: ");
553    vfprintf(stdout, msg, args);
554    va_end(args);
555}
556
557/**
558 * fatalErrorDebug:
559 * @ctxt:  An XML parser context
560 * @msg:  the message to display/transmit
561 * @...:  extra parameters for the message display
562 *
563 * Display and format a fatalError messages, gives file, line, position and
564 * extra parameters.
565 */
566static void XMLCDECL
567fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
568{
569    va_list args;
570
571    va_start(args, msg);
572    fprintf(stdout, "SAX.fatalError: ");
573    vfprintf(stdout, msg, args);
574    va_end(args);
575}
576
577static xmlSAXHandler debugSAXHandlerStruct = {
578    internalSubsetDebug,
579    isStandaloneDebug,
580    hasInternalSubsetDebug,
581    hasExternalSubsetDebug,
582    resolveEntityDebug,
583    getEntityDebug,
584    entityDeclDebug,
585    notationDeclDebug,
586    attributeDeclDebug,
587    elementDeclDebug,
588    unparsedEntityDeclDebug,
589    setDocumentLocatorDebug,
590    startDocumentDebug,
591    endDocumentDebug,
592    startElementDebug,
593    endElementDebug,
594    referenceDebug,
595    charactersDebug,
596    ignorableWhitespaceDebug,
597    processingInstructionDebug,
598    commentDebug,
599    warningDebug,
600    errorDebug,
601    fatalErrorDebug,
602    getParameterEntityDebug,
603    cdataDebug,
604    NULL,
605    1,
606    NULL,
607    NULL,
608    NULL,
609    NULL
610};
611
612xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
613/************************************************************************
614 *									*
615 *				Debug					*
616 *									*
617 ************************************************************************/
618
619static void
620parseSAXFile(char *filename) {
621    htmlDocPtr doc = NULL;
622
623    /*
624     * Empty callbacks for checking
625     */
626#ifdef LIBXML_PUSH_ENABLED
627    if (push) {
628	FILE *f;
629
630#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
631	f = fopen(filename, "rb");
632#else
633	f = fopen(filename, "r");
634#endif
635	if (f != NULL) {
636	    int res, size = 3;
637	    char chars[4096];
638	    htmlParserCtxtPtr ctxt;
639
640	    /* if (repeat) */
641		size = 4096;
642	    res = fread(chars, 1, 4, f);
643	    if (res > 0) {
644		ctxt = htmlCreatePushParserCtxt(emptySAXHandler, NULL,
645			    chars, res, filename, XML_CHAR_ENCODING_NONE);
646		while ((res = fread(chars, 1, size, f)) > 0) {
647		    htmlParseChunk(ctxt, chars, res, 0);
648		}
649		htmlParseChunk(ctxt, chars, 0, 1);
650		doc = ctxt->myDoc;
651		htmlFreeParserCtxt(ctxt);
652	    }
653	    if (doc != NULL) {
654		fprintf(stdout, "htmlSAXParseFile returned non-NULL\n");
655		xmlFreeDoc(doc);
656	    }
657	    fclose(f);
658	}
659	if (!noout) {
660#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
661		f = fopen(filename, "rb");
662#else
663		f = fopen(filename, "r");
664#endif
665	    if (f != NULL) {
666		int res, size = 3;
667		char chars[4096];
668		htmlParserCtxtPtr ctxt;
669
670		/* if (repeat) */
671		    size = 4096;
672		res = fread(chars, 1, 4, f);
673		if (res > 0) {
674		    ctxt = htmlCreatePushParserCtxt(debugSAXHandler, NULL,
675				chars, res, filename, XML_CHAR_ENCODING_NONE);
676		    while ((res = fread(chars, 1, size, f)) > 0) {
677			htmlParseChunk(ctxt, chars, res, 0);
678		    }
679		    htmlParseChunk(ctxt, chars, 0, 1);
680		    doc = ctxt->myDoc;
681		    htmlFreeParserCtxt(ctxt);
682		}
683		if (doc != NULL) {
684		    fprintf(stdout, "htmlSAXParseFile returned non-NULL\n");
685		    xmlFreeDoc(doc);
686		}
687		fclose(f);
688	    }
689	}
690    } else {
691#endif /* LIBXML_PUSH_ENABLED */
692	doc = htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
693	if (doc != NULL) {
694	    fprintf(stdout, "htmlSAXParseFile returned non-NULL\n");
695	    xmlFreeDoc(doc);
696	}
697
698	if (!noout) {
699	    /*
700	     * Debug callback
701	     */
702	    doc = htmlSAXParseFile(filename, NULL, debugSAXHandler, NULL);
703	    if (doc != NULL) {
704		fprintf(stdout, "htmlSAXParseFile returned non-NULL\n");
705		xmlFreeDoc(doc);
706	    }
707	}
708#ifdef LIBXML_PUSH_ENABLED
709    }
710#endif /* LIBXML_PUSH_ENABLED */
711}
712
713static void
714parseAndPrintFile(char *filename) {
715    htmlDocPtr doc = NULL;
716
717    /*
718     * build an HTML tree from a string;
719     */
720#ifdef LIBXML_PUSH_ENABLED
721    if (push) {
722	FILE *f;
723
724#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
725	f = fopen(filename, "rb");
726#else
727	f = fopen(filename, "r");
728#endif
729	if (f != NULL) {
730	    int res, size = 3;
731	    char chars[4096];
732	    htmlParserCtxtPtr ctxt;
733
734	    /* if (repeat) */
735		size = 4096;
736	    res = fread(chars, 1, 4, f);
737	    if (res > 0) {
738		ctxt = htmlCreatePushParserCtxt(NULL, NULL,
739			    chars, res, filename, XML_CHAR_ENCODING_NONE);
740		while ((res = fread(chars, 1, size, f)) > 0) {
741		    htmlParseChunk(ctxt, chars, res, 0);
742		}
743		htmlParseChunk(ctxt, chars, 0, 1);
744		doc = ctxt->myDoc;
745		htmlFreeParserCtxt(ctxt);
746	    }
747	    fclose(f);
748	}
749    } else {
750	doc = htmlReadFile(filename, NULL, options);
751    }
752#else
753	doc = htmlReadFile(filename,NULL,options);
754#endif
755    if (doc == NULL) {
756        xmlGenericError(xmlGenericErrorContext,
757		"Could not parse %s\n", filename);
758    }
759
760#ifdef LIBXML_TREE_ENABLED
761    /*
762     * test intermediate copy if needed.
763     */
764    if (copy) {
765        htmlDocPtr tmp;
766
767        tmp = doc;
768	doc = xmlCopyDoc(doc, 1);
769	xmlFreeDoc(tmp);
770    }
771#endif
772
773#ifdef LIBXML_OUTPUT_ENABLED
774    /*
775     * print it.
776     */
777    if (!noout) {
778#ifdef LIBXML_DEBUG_ENABLED
779	if (!debug) {
780	    if (encoding)
781		htmlSaveFileEnc("-", doc, encoding);
782	    else
783		htmlDocDump(stdout, doc);
784	} else
785	    xmlDebugDumpDocument(stdout, doc);
786#else
787	if (encoding)
788	    htmlSaveFileEnc("-", doc, encoding);
789	else
790	    htmlDocDump(stdout, doc);
791#endif
792    }
793#endif /* LIBXML_OUTPUT_ENABLED */
794
795    /*
796     * free it.
797     */
798    xmlFreeDoc(doc);
799}
800
801int main(int argc, char **argv) {
802    int i, count;
803    int files = 0;
804
805    for (i = 1; i < argc ; i++) {
806#ifdef LIBXML_DEBUG_ENABLED
807	if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
808	    debug++;
809	else
810#endif
811	    if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
812	    copy++;
813#ifdef LIBXML_PUSH_ENABLED
814	else if ((!strcmp(argv[i], "-push")) || (!strcmp(argv[i], "--push")))
815	    push++;
816#endif /* LIBXML_PUSH_ENABLED */
817	else if ((!strcmp(argv[i], "-sax")) || (!strcmp(argv[i], "--sax")))
818	    sax++;
819	else if ((!strcmp(argv[i], "-noout")) || (!strcmp(argv[i], "--noout")))
820	    noout++;
821	else if ((!strcmp(argv[i], "-repeat")) ||
822	         (!strcmp(argv[i], "--repeat")))
823	    repeat++;
824	else if ((!strcmp(argv[i], "-encode")) ||
825	         (!strcmp(argv[i], "--encode"))) {
826	    i++;
827	    encoding = argv[i];
828        }
829    }
830    for (i = 1; i < argc ; i++) {
831	if ((!strcmp(argv[i], "-encode")) ||
832	         (!strcmp(argv[i], "--encode"))) {
833	    i++;
834	    continue;
835        }
836	if (argv[i][0] != '-') {
837	    if (repeat) {
838		for (count = 0;count < 100 * repeat;count++) {
839		    if (sax)
840			parseSAXFile(argv[i]);
841		    else
842			parseAndPrintFile(argv[i]);
843		}
844	    } else {
845		if (sax)
846		    parseSAXFile(argv[i]);
847		else
848		    parseAndPrintFile(argv[i]);
849	    }
850	    files ++;
851	}
852    }
853    if (files == 0) {
854	printf("Usage : %s [--debug] [--copy] [--copy] HTMLfiles ...\n",
855	       argv[0]);
856	printf("\tParse the HTML files and output the result of the parsing\n");
857#ifdef LIBXML_DEBUG_ENABLED
858	printf("\t--debug : dump a debug tree of the in-memory document\n");
859#endif
860	printf("\t--copy : used to test the internal copy implementation\n");
861	printf("\t--sax : debug the sequence of SAX callbacks\n");
862	printf("\t--repeat : parse the file 100 times, for timing\n");
863	printf("\t--noout : do not print the result\n");
864#ifdef LIBXML_PUSH_ENABLED
865	printf("\t--push : use the push mode parser\n");
866#endif /* LIBXML_PUSH_ENABLED */
867	printf("\t--encode encoding : output in the given encoding\n");
868    }
869    xmlCleanupParser();
870    xmlMemoryDump();
871
872    return(0);
873}
874#else /* !LIBXML_HTML_ENABLED */
875#include <stdio.h>
876int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
877    printf("%s : HTML support not compiled in\n", argv[0]);
878    return(0);
879}
880#endif
881