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