1/*
2 * testSAX.c : a small tester program for parsing using the SAX API.
3 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9#include "libxml.h"
10
11#ifdef HAVE_SYS_TIME_H
12#include <sys/time.h>
13#endif
14#ifdef HAVE_SYS_TIMEB_H
15#include <sys/timeb.h>
16#endif
17#ifdef HAVE_TIME_H
18#include <time.h>
19#endif
20
21#ifdef LIBXML_SAX1_ENABLED
22#include <string.h>
23#include <stdarg.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_SYS_STAT_H
29#include <sys/stat.h>
30#endif
31#ifdef HAVE_FCNTL_H
32#include <fcntl.h>
33#endif
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37#ifdef HAVE_STDLIB_H
38#include <stdlib.h>
39#endif
40#ifdef HAVE_STRING_H
41#include <string.h>
42#endif
43
44
45#include <libxml/globals.h>
46#include <libxml/xmlerror.h>
47#include <libxml/parser.h>
48#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
49#include <libxml/tree.h>
50#include <libxml/debugXML.h>
51#include <libxml/xmlmemory.h>
52
53static int debug = 0;
54static int copy = 0;
55static int recovery = 0;
56static int push = 0;
57static int speed = 0;
58static int noent = 0;
59static int quiet = 0;
60static int nonull = 0;
61static int sax2 = 0;
62static int repeat = 0;
63static int callbacks = 0;
64static int timing = 0;
65
66/*
67 * Timing routines.
68 */
69/*
70 * Internal timing routines to remove the necessity to have unix-specific
71 * function calls
72 */
73
74#ifndef HAVE_GETTIMEOFDAY
75#ifdef HAVE_SYS_TIMEB_H
76#ifdef HAVE_SYS_TIME_H
77#ifdef HAVE_FTIME
78
79static int
80my_gettimeofday(struct timeval *tvp, void *tzp)
81{
82	struct timeb timebuffer;
83
84	ftime(&timebuffer);
85	if (tvp) {
86		tvp->tv_sec = timebuffer.time;
87		tvp->tv_usec = timebuffer.millitm * 1000L;
88	}
89	return (0);
90}
91#define HAVE_GETTIMEOFDAY 1
92#define gettimeofday my_gettimeofday
93
94#endif /* HAVE_FTIME */
95#endif /* HAVE_SYS_TIME_H */
96#endif /* HAVE_SYS_TIMEB_H */
97#endif /* !HAVE_GETTIMEOFDAY */
98
99#if defined(HAVE_GETTIMEOFDAY)
100static struct timeval begin, end;
101
102/*
103 * startTimer: call where you want to start timing
104 */
105static void
106startTimer(void)
107{
108    gettimeofday(&begin, NULL);
109}
110
111/*
112 * endTimer: call where you want to stop timing and to print out a
113 *           message about the timing performed; format is a printf
114 *           type argument
115 */
116static void XMLCDECL
117endTimer(const char *fmt, ...)
118{
119    long msec;
120    va_list ap;
121
122    gettimeofday(&end, NULL);
123    msec = end.tv_sec - begin.tv_sec;
124    msec *= 1000;
125    msec += (end.tv_usec - begin.tv_usec) / 1000;
126
127#ifndef HAVE_STDARG_H
128#error "endTimer required stdarg functions"
129#endif
130    va_start(ap, fmt);
131    vfprintf(stderr, fmt, ap);
132    va_end(ap);
133
134    fprintf(stderr, " took %ld ms\n", msec);
135}
136#elif defined(HAVE_TIME_H)
137/*
138 * No gettimeofday function, so we have to make do with calling clock.
139 * This is obviously less accurate, but there's little we can do about
140 * that.
141 */
142#ifndef CLOCKS_PER_SEC
143#define CLOCKS_PER_SEC 100
144#endif
145
146static clock_t begin, end;
147static void
148startTimer(void)
149{
150    begin = clock();
151}
152static void XMLCDECL
153endTimer(const char *fmt, ...)
154{
155    long msec;
156    va_list ap;
157
158    end = clock();
159    msec = ((end - begin) * 1000) / CLOCKS_PER_SEC;
160
161#ifndef HAVE_STDARG_H
162#error "endTimer required stdarg functions"
163#endif
164    va_start(ap, fmt);
165    vfprintf(stderr, fmt, ap);
166    va_end(ap);
167    fprintf(stderr, " took %ld ms\n", msec);
168}
169#else
170
171/*
172 * We don't have a gettimeofday or time.h, so we just don't do timing
173 */
174static void
175startTimer(void)
176{
177    /*
178     * Do nothing
179     */
180}
181static void XMLCDECL
182endTimer(char *format, ...)
183{
184    /*
185     * We cannot do anything because we don't have a timing function
186     */
187#ifdef HAVE_STDARG_H
188    va_start(ap, format);
189    vfprintf(stderr, format, ap);
190    va_end(ap);
191    fprintf(stderr, " was not timed\n", msec);
192#else
193    /* We don't have gettimeofday, time or stdarg.h, what crazy world is
194     * this ?!
195     */
196#endif
197}
198#endif
199
200/*
201 * empty SAX block
202 */
203static xmlSAXHandler emptySAXHandlerStruct = {
204    NULL, /* internalSubset */
205    NULL, /* isStandalone */
206    NULL, /* hasInternalSubset */
207    NULL, /* hasExternalSubset */
208    NULL, /* resolveEntity */
209    NULL, /* getEntity */
210    NULL, /* entityDecl */
211    NULL, /* notationDecl */
212    NULL, /* attributeDecl */
213    NULL, /* elementDecl */
214    NULL, /* unparsedEntityDecl */
215    NULL, /* setDocumentLocator */
216    NULL, /* startDocument */
217    NULL, /* endDocument */
218    NULL, /* startElement */
219    NULL, /* endElement */
220    NULL, /* reference */
221    NULL, /* characters */
222    NULL, /* ignorableWhitespace */
223    NULL, /* processingInstruction */
224    NULL, /* comment */
225    NULL, /* xmlParserWarning */
226    NULL, /* xmlParserError */
227    NULL, /* xmlParserError */
228    NULL, /* getParameterEntity */
229    NULL, /* cdataBlock; */
230    NULL, /* externalSubset; */
231    1,
232    NULL,
233    NULL, /* startElementNs */
234    NULL, /* endElementNs */
235    NULL  /* xmlStructuredErrorFunc */
236};
237
238static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
239extern xmlSAXHandlerPtr debugSAXHandler;
240
241/************************************************************************
242 *									*
243 *				Debug Handlers				*
244 *									*
245 ************************************************************************/
246
247/**
248 * isStandaloneDebug:
249 * @ctxt:  An XML parser context
250 *
251 * Is this document tagged standalone ?
252 *
253 * Returns 1 if true
254 */
255static int
256isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
257{
258    callbacks++;
259    if (quiet)
260	return(0);
261    fprintf(stdout, "SAX.isStandalone()\n");
262    return(0);
263}
264
265/**
266 * hasInternalSubsetDebug:
267 * @ctxt:  An XML parser context
268 *
269 * Does this document has an internal subset
270 *
271 * Returns 1 if true
272 */
273static int
274hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
275{
276    callbacks++;
277    if (quiet)
278	return(0);
279    fprintf(stdout, "SAX.hasInternalSubset()\n");
280    return(0);
281}
282
283/**
284 * hasExternalSubsetDebug:
285 * @ctxt:  An XML parser context
286 *
287 * Does this document has an external subset
288 *
289 * Returns 1 if true
290 */
291static int
292hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
293{
294    callbacks++;
295    if (quiet)
296	return(0);
297    fprintf(stdout, "SAX.hasExternalSubset()\n");
298    return(0);
299}
300
301/**
302 * internalSubsetDebug:
303 * @ctxt:  An XML parser context
304 *
305 * Does this document has an internal subset
306 */
307static void
308internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
309	       const xmlChar *ExternalID, const xmlChar *SystemID)
310{
311    callbacks++;
312    if (quiet)
313	return;
314    fprintf(stdout, "SAX.internalSubset(%s,", name);
315    if (ExternalID == NULL)
316	fprintf(stdout, " ,");
317    else
318	fprintf(stdout, " %s,", ExternalID);
319    if (SystemID == NULL)
320	fprintf(stdout, " )\n");
321    else
322	fprintf(stdout, " %s)\n", SystemID);
323}
324
325/**
326 * externalSubsetDebug:
327 * @ctxt:  An XML parser context
328 *
329 * Does this document has an external subset
330 */
331static void
332externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
333	       const xmlChar *ExternalID, const xmlChar *SystemID)
334{
335    callbacks++;
336    if (quiet)
337	return;
338    fprintf(stdout, "SAX.externalSubset(%s,", name);
339    if (ExternalID == NULL)
340	fprintf(stdout, " ,");
341    else
342	fprintf(stdout, " %s,", ExternalID);
343    if (SystemID == NULL)
344	fprintf(stdout, " )\n");
345    else
346	fprintf(stdout, " %s)\n", SystemID);
347}
348
349/**
350 * resolveEntityDebug:
351 * @ctxt:  An XML parser context
352 * @publicId: The public ID of the entity
353 * @systemId: The system ID of the entity
354 *
355 * Special entity resolver, better left to the parser, it has
356 * more context than the application layer.
357 * The default behaviour is to NOT resolve the entities, in that case
358 * the ENTITY_REF nodes are built in the structure (and the parameter
359 * values).
360 *
361 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
362 */
363static xmlParserInputPtr
364resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
365{
366    callbacks++;
367    if (quiet)
368	return(NULL);
369    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
370
371
372    fprintf(stdout, "SAX.resolveEntity(");
373    if (publicId != NULL)
374	fprintf(stdout, "%s", (char *)publicId);
375    else
376	fprintf(stdout, " ");
377    if (systemId != NULL)
378	fprintf(stdout, ", %s)\n", (char *)systemId);
379    else
380	fprintf(stdout, ", )\n");
381/*********
382    if (systemId != NULL) {
383        return(xmlNewInputFromFile(ctxt, (char *) systemId));
384    }
385 *********/
386    return(NULL);
387}
388
389/**
390 * getEntityDebug:
391 * @ctxt:  An XML parser context
392 * @name: The entity name
393 *
394 * Get an entity by name
395 *
396 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
397 */
398static xmlEntityPtr
399getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
400{
401    callbacks++;
402    if (quiet)
403	return(NULL);
404    fprintf(stdout, "SAX.getEntity(%s)\n", name);
405    return(NULL);
406}
407
408/**
409 * getParameterEntityDebug:
410 * @ctxt:  An XML parser context
411 * @name: The entity name
412 *
413 * Get a parameter entity by name
414 *
415 * Returns the xmlParserInputPtr
416 */
417static xmlEntityPtr
418getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
419{
420    callbacks++;
421    if (quiet)
422	return(NULL);
423    fprintf(stdout, "SAX.getParameterEntity(%s)\n", name);
424    return(NULL);
425}
426
427
428/**
429 * entityDeclDebug:
430 * @ctxt:  An XML parser context
431 * @name:  the entity name
432 * @type:  the entity type
433 * @publicId: The public ID of the entity
434 * @systemId: The system ID of the entity
435 * @content: the entity value (without processing).
436 *
437 * An entity definition has been parsed
438 */
439static void
440entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
441          const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
442{
443const xmlChar *nullstr = BAD_CAST "(null)";
444    /* not all libraries handle printing null pointers nicely */
445    if (publicId == NULL)
446        publicId = nullstr;
447    if (systemId == NULL)
448        systemId = nullstr;
449    if (content == NULL)
450        content = (xmlChar *)nullstr;
451    callbacks++;
452    if (quiet)
453	return;
454    fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
455            name, type, publicId, systemId, content);
456}
457
458/**
459 * attributeDeclDebug:
460 * @ctxt:  An XML parser context
461 * @name:  the attribute name
462 * @type:  the attribute type
463 *
464 * An attribute definition has been parsed
465 */
466static void
467attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
468                   const xmlChar * name, int type, int def,
469                   const xmlChar * defaultValue, xmlEnumerationPtr tree)
470{
471    callbacks++;
472    if (quiet)
473        return;
474    if (defaultValue == NULL)
475        fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
476                elem, name, type, def);
477    else
478        fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
479                elem, name, type, def, defaultValue);
480    xmlFreeEnumeration(tree);
481}
482
483/**
484 * elementDeclDebug:
485 * @ctxt:  An XML parser context
486 * @name:  the element name
487 * @type:  the element type
488 * @content: the element value (without processing).
489 *
490 * An element definition has been parsed
491 */
492static void
493elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
494	    xmlElementContentPtr content ATTRIBUTE_UNUSED)
495{
496    callbacks++;
497    if (quiet)
498	return;
499    fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n",
500            name, type);
501}
502
503/**
504 * notationDeclDebug:
505 * @ctxt:  An XML parser context
506 * @name: The name of the notation
507 * @publicId: The public ID of the entity
508 * @systemId: The system ID of the entity
509 *
510 * What to do when a notation declaration has been parsed.
511 */
512static void
513notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
514	     const xmlChar *publicId, const xmlChar *systemId)
515{
516    callbacks++;
517    if (quiet)
518	return;
519    fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n",
520            (char *) name, (char *) publicId, (char *) systemId);
521}
522
523/**
524 * unparsedEntityDeclDebug:
525 * @ctxt:  An XML parser context
526 * @name: The name of the entity
527 * @publicId: The public ID of the entity
528 * @systemId: The system ID of the entity
529 * @notationName: the name of the notation
530 *
531 * What to do when an unparsed entity declaration is parsed
532 */
533static void
534unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
535		   const xmlChar *publicId, const xmlChar *systemId,
536		   const xmlChar *notationName)
537{
538const xmlChar *nullstr = BAD_CAST "(null)";
539
540    if (publicId == NULL)
541        publicId = nullstr;
542    if (systemId == NULL)
543        systemId = nullstr;
544    if (notationName == NULL)
545        notationName = nullstr;
546    callbacks++;
547    if (quiet)
548	return;
549    fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
550            (char *) name, (char *) publicId, (char *) systemId,
551	    (char *) notationName);
552}
553
554/**
555 * setDocumentLocatorDebug:
556 * @ctxt:  An XML parser context
557 * @loc: A SAX Locator
558 *
559 * Receive the document locator at startup, actually xmlDefaultSAXLocator
560 * Everything is available on the context, so this is useless in our case.
561 */
562static void
563setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
564{
565    callbacks++;
566    if (quiet)
567	return;
568    fprintf(stdout, "SAX.setDocumentLocator()\n");
569}
570
571/**
572 * startDocumentDebug:
573 * @ctxt:  An XML parser context
574 *
575 * called when the document start being processed.
576 */
577static void
578startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
579{
580    callbacks++;
581    if (quiet)
582	return;
583    fprintf(stdout, "SAX.startDocument()\n");
584}
585
586/**
587 * endDocumentDebug:
588 * @ctxt:  An XML parser context
589 *
590 * called when the document end has been detected.
591 */
592static void
593endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
594{
595    callbacks++;
596    if (quiet)
597	return;
598    fprintf(stdout, "SAX.endDocument()\n");
599}
600
601/**
602 * startElementDebug:
603 * @ctxt:  An XML parser context
604 * @name:  The element name
605 *
606 * called when an opening tag has been processed.
607 */
608static void
609startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
610{
611    int i;
612
613    callbacks++;
614    if (quiet)
615	return;
616    fprintf(stdout, "SAX.startElement(%s", (char *) name);
617    if (atts != NULL) {
618        for (i = 0;(atts[i] != NULL);i++) {
619	    fprintf(stdout, ", %s='", atts[i++]);
620	    if (atts[i] != NULL)
621	        fprintf(stdout, "%s'", atts[i]);
622	}
623    }
624    fprintf(stdout, ")\n");
625}
626
627/**
628 * endElementDebug:
629 * @ctxt:  An XML parser context
630 * @name:  The element name
631 *
632 * called when the end of an element has been detected.
633 */
634static void
635endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
636{
637    callbacks++;
638    if (quiet)
639	return;
640    fprintf(stdout, "SAX.endElement(%s)\n", (char *) name);
641}
642
643/**
644 * charactersDebug:
645 * @ctxt:  An XML parser context
646 * @ch:  a xmlChar string
647 * @len: the number of xmlChar
648 *
649 * receiving some chars from the parser.
650 * Question: how much at a time ???
651 */
652static void
653charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
654{
655    char output[40];
656    int i;
657
658    callbacks++;
659    if (quiet)
660	return;
661    for (i = 0;(i<len) && (i < 30);i++)
662	output[i] = ch[i];
663    output[i] = 0;
664
665    fprintf(stdout, "SAX.characters(%s, %d)\n", output, len);
666}
667
668/**
669 * referenceDebug:
670 * @ctxt:  An XML parser context
671 * @name:  The entity name
672 *
673 * called when an entity reference is detected.
674 */
675static void
676referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
677{
678    callbacks++;
679    if (quiet)
680	return;
681    fprintf(stdout, "SAX.reference(%s)\n", name);
682}
683
684/**
685 * ignorableWhitespaceDebug:
686 * @ctxt:  An XML parser context
687 * @ch:  a xmlChar string
688 * @start: the first char in the string
689 * @len: the number of xmlChar
690 *
691 * receiving some ignorable whitespaces from the parser.
692 * Question: how much at a time ???
693 */
694static void
695ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
696{
697    char output[40];
698    int i;
699
700    callbacks++;
701    if (quiet)
702	return;
703    for (i = 0;(i<len) && (i < 30);i++)
704	output[i] = ch[i];
705    output[i] = 0;
706    fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
707}
708
709/**
710 * processingInstructionDebug:
711 * @ctxt:  An XML parser context
712 * @target:  the target name
713 * @data: the PI data's
714 * @len: the number of xmlChar
715 *
716 * A processing instruction has been parsed.
717 */
718static void
719processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
720                      const xmlChar *data)
721{
722    callbacks++;
723    if (quiet)
724	return;
725    if (data != NULL)
726	fprintf(stdout, "SAX.processingInstruction(%s, %s)\n",
727		(char *) target, (char *) data);
728    else
729	fprintf(stdout, "SAX.processingInstruction(%s, NULL)\n",
730		(char *) target);
731}
732
733/**
734 * cdataBlockDebug:
735 * @ctx: the user data (XML parser context)
736 * @value:  The pcdata content
737 * @len:  the block length
738 *
739 * called when a pcdata block has been parsed
740 */
741static void
742cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
743{
744    callbacks++;
745    if (quiet)
746	return;
747    fprintf(stdout, "SAX.pcdata(%.20s, %d)\n",
748	    (char *) value, len);
749}
750
751/**
752 * commentDebug:
753 * @ctxt:  An XML parser context
754 * @value:  the comment content
755 *
756 * A comment has been parsed.
757 */
758static void
759commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
760{
761    callbacks++;
762    if (quiet)
763	return;
764    fprintf(stdout, "SAX.comment(%s)\n", value);
765}
766
767/**
768 * warningDebug:
769 * @ctxt:  An XML parser context
770 * @msg:  the message to display/transmit
771 * @...:  extra parameters for the message display
772 *
773 * Display and format a warning messages, gives file, line, position and
774 * extra parameters.
775 */
776static void XMLCDECL
777warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
778{
779    va_list args;
780
781    callbacks++;
782    if (quiet)
783	return;
784    va_start(args, msg);
785    fprintf(stdout, "SAX.warning: ");
786    vfprintf(stdout, msg, args);
787    va_end(args);
788}
789
790/**
791 * errorDebug:
792 * @ctxt:  An XML parser context
793 * @msg:  the message to display/transmit
794 * @...:  extra parameters for the message display
795 *
796 * Display and format a error messages, gives file, line, position and
797 * extra parameters.
798 */
799static void XMLCDECL
800errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
801{
802    va_list args;
803
804    callbacks++;
805    if (quiet)
806	return;
807    va_start(args, msg);
808    fprintf(stdout, "SAX.error: ");
809    vfprintf(stdout, msg, args);
810    va_end(args);
811}
812
813/**
814 * fatalErrorDebug:
815 * @ctxt:  An XML parser context
816 * @msg:  the message to display/transmit
817 * @...:  extra parameters for the message display
818 *
819 * Display and format a fatalError messages, gives file, line, position and
820 * extra parameters.
821 */
822static void XMLCDECL
823fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
824{
825    va_list args;
826
827    callbacks++;
828    if (quiet)
829	return;
830    va_start(args, msg);
831    fprintf(stdout, "SAX.fatalError: ");
832    vfprintf(stdout, msg, args);
833    va_end(args);
834}
835
836static xmlSAXHandler debugSAXHandlerStruct = {
837    internalSubsetDebug,
838    isStandaloneDebug,
839    hasInternalSubsetDebug,
840    hasExternalSubsetDebug,
841    resolveEntityDebug,
842    getEntityDebug,
843    entityDeclDebug,
844    notationDeclDebug,
845    attributeDeclDebug,
846    elementDeclDebug,
847    unparsedEntityDeclDebug,
848    setDocumentLocatorDebug,
849    startDocumentDebug,
850    endDocumentDebug,
851    startElementDebug,
852    endElementDebug,
853    referenceDebug,
854    charactersDebug,
855    ignorableWhitespaceDebug,
856    processingInstructionDebug,
857    commentDebug,
858    warningDebug,
859    errorDebug,
860    fatalErrorDebug,
861    getParameterEntityDebug,
862    cdataBlockDebug,
863    externalSubsetDebug,
864    1,
865    NULL,
866    NULL,
867    NULL,
868    NULL
869};
870
871xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
872
873/*
874 * SAX2 specific callbacks
875 */
876/**
877 * startElementNsDebug:
878 * @ctxt:  An XML parser context
879 * @name:  The element name
880 *
881 * called when an opening tag has been processed.
882 */
883static void
884startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
885                    const xmlChar *localname,
886                    const xmlChar *prefix,
887                    const xmlChar *URI,
888		    int nb_namespaces,
889		    const xmlChar **namespaces,
890		    int nb_attributes,
891		    int nb_defaulted,
892		    const xmlChar **attributes)
893{
894    int i;
895
896    callbacks++;
897    if (quiet)
898	return;
899    fprintf(stdout, "SAX.startElementNs(%s", (char *) localname);
900    if (prefix == NULL)
901	fprintf(stdout, ", NULL");
902    else
903	fprintf(stdout, ", %s", (char *) prefix);
904    if (URI == NULL)
905	fprintf(stdout, ", NULL");
906    else
907	fprintf(stdout, ", '%s'", (char *) URI);
908    fprintf(stdout, ", %d", nb_namespaces);
909
910    if (namespaces != NULL) {
911        for (i = 0;i < nb_namespaces * 2;i++) {
912	    fprintf(stdout, ", xmlns");
913	    if (namespaces[i] != NULL)
914	        fprintf(stdout, ":%s", namespaces[i]);
915	    i++;
916	    fprintf(stdout, "='%s'", namespaces[i]);
917	}
918    }
919    fprintf(stdout, ", %d, %d", nb_attributes, nb_defaulted);
920    if (attributes != NULL) {
921        for (i = 0;i < nb_attributes * 5;i += 5) {
922	    if (attributes[i + 1] != NULL)
923		fprintf(stdout, ", %s:%s='", attributes[i + 1], attributes[i]);
924	    else
925		fprintf(stdout, ", %s='", attributes[i]);
926	    fprintf(stdout, "%.4s...', %d", attributes[i + 3],
927		    (int)(attributes[i + 4] - attributes[i + 3]));
928	}
929    }
930    fprintf(stdout, ")\n");
931}
932
933/**
934 * endElementDebug:
935 * @ctxt:  An XML parser context
936 * @name:  The element name
937 *
938 * called when the end of an element has been detected.
939 */
940static void
941endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
942                  const xmlChar *localname,
943                  const xmlChar *prefix,
944                  const xmlChar *URI)
945{
946    callbacks++;
947    if (quiet)
948	return;
949    fprintf(stdout, "SAX.endElementNs(%s", (char *) localname);
950    if (prefix == NULL)
951	fprintf(stdout, ", NULL");
952    else
953	fprintf(stdout, ", %s", (char *) prefix);
954    if (URI == NULL)
955	fprintf(stdout, ", NULL)\n");
956    else
957	fprintf(stdout, ", '%s')\n", (char *) URI);
958}
959
960static xmlSAXHandler debugSAX2HandlerStruct = {
961    internalSubsetDebug,
962    isStandaloneDebug,
963    hasInternalSubsetDebug,
964    hasExternalSubsetDebug,
965    resolveEntityDebug,
966    getEntityDebug,
967    entityDeclDebug,
968    notationDeclDebug,
969    attributeDeclDebug,
970    elementDeclDebug,
971    unparsedEntityDeclDebug,
972    setDocumentLocatorDebug,
973    startDocumentDebug,
974    endDocumentDebug,
975    NULL,
976    NULL,
977    referenceDebug,
978    charactersDebug,
979    ignorableWhitespaceDebug,
980    processingInstructionDebug,
981    commentDebug,
982    warningDebug,
983    errorDebug,
984    fatalErrorDebug,
985    getParameterEntityDebug,
986    cdataBlockDebug,
987    externalSubsetDebug,
988    XML_SAX2_MAGIC,
989    NULL,
990    startElementNsDebug,
991    endElementNsDebug,
992    NULL
993};
994
995static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
996
997/************************************************************************
998 *									*
999 *				Debug					*
1000 *									*
1001 ************************************************************************/
1002
1003static void
1004parseAndPrintFile(char *filename) {
1005    int res;
1006
1007#ifdef LIBXML_PUSH_ENABLED
1008    if (push) {
1009	FILE *f;
1010
1011        if ((!quiet) && (!nonull)) {
1012	    /*
1013	     * Empty callbacks for checking
1014	     */
1015#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1016	    f = fopen(filename, "rb");
1017#else
1018	    f = fopen(filename, "r");
1019#endif
1020	    if (f != NULL) {
1021		int ret;
1022		char chars[10];
1023		xmlParserCtxtPtr ctxt;
1024
1025		ret = fread(chars, 1, 4, f);
1026		if (ret > 0) {
1027		    ctxt = xmlCreatePushParserCtxt(emptySAXHandler, NULL,
1028				chars, ret, filename);
1029		    while ((ret = fread(chars, 1, 3, f)) > 0) {
1030			xmlParseChunk(ctxt, chars, ret, 0);
1031		    }
1032		    xmlParseChunk(ctxt, chars, 0, 1);
1033		    xmlFreeParserCtxt(ctxt);
1034		}
1035		fclose(f);
1036	    } else {
1037		xmlGenericError(xmlGenericErrorContext,
1038			"Cannot read file %s\n", filename);
1039	    }
1040	}
1041	/*
1042	 * Debug callback
1043	 */
1044#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1045	f = fopen(filename, "rb");
1046#else
1047	f = fopen(filename, "r");
1048#endif
1049	if (f != NULL) {
1050	    int ret;
1051	    char chars[10];
1052	    xmlParserCtxtPtr ctxt;
1053
1054	    ret = fread(chars, 1, 4, f);
1055	    if (ret > 0) {
1056	        if (sax2)
1057		    ctxt = xmlCreatePushParserCtxt(debugSAX2Handler, NULL,
1058				chars, ret, filename);
1059		else
1060		    ctxt = xmlCreatePushParserCtxt(debugSAXHandler, NULL,
1061				chars, ret, filename);
1062		while ((ret = fread(chars, 1, 3, f)) > 0) {
1063		    xmlParseChunk(ctxt, chars, ret, 0);
1064		}
1065		ret = xmlParseChunk(ctxt, chars, 0, 1);
1066		xmlFreeParserCtxt(ctxt);
1067		if (ret != 0) {
1068		    fprintf(stdout,
1069		            "xmlSAXUserParseFile returned error %d\n", ret);
1070		}
1071	    }
1072	    fclose(f);
1073	}
1074    } else {
1075#endif /* LIBXML_PUSH_ENABLED */
1076	if (!speed) {
1077	    /*
1078	     * Empty callbacks for checking
1079	     */
1080	    if ((!quiet) && (!nonull)) {
1081		res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1082		if (res != 0) {
1083		    fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
1084		}
1085	    }
1086
1087	    /*
1088	     * Debug callback
1089	     */
1090	    callbacks = 0;
1091	    if (repeat) {
1092	        int i;
1093		for (i = 0;i < 99;i++) {
1094		    if (sax2)
1095			res = xmlSAXUserParseFile(debugSAX2Handler, NULL,
1096			                          filename);
1097		    else
1098			res = xmlSAXUserParseFile(debugSAXHandler, NULL,
1099			                          filename);
1100		}
1101	    }
1102	    if (sax2)
1103	        res = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename);
1104	    else
1105		res = xmlSAXUserParseFile(debugSAXHandler, NULL, filename);
1106	    if (res != 0) {
1107		fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
1108	    }
1109	    if (quiet)
1110		fprintf(stdout, "%d callbacks generated\n", callbacks);
1111	} else {
1112	    /*
1113	     * test 100x the SAX parse
1114	     */
1115	    int i;
1116
1117	    for (i = 0; i<100;i++)
1118		res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1119	    if (res != 0) {
1120		fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
1121	    }
1122	}
1123#ifdef LIBXML_PUSH_ENABLED
1124    }
1125#endif
1126}
1127
1128
1129int main(int argc, char **argv) {
1130    int i;
1131    int files = 0;
1132
1133    LIBXML_TEST_VERSION	/* be safe, plus calls xmlInitParser */
1134
1135    for (i = 1; i < argc ; i++) {
1136	if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
1137	    debug++;
1138	else if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
1139	    copy++;
1140	else if ((!strcmp(argv[i], "-recover")) ||
1141	         (!strcmp(argv[i], "--recover")))
1142	    recovery++;
1143	else if ((!strcmp(argv[i], "-push")) ||
1144	         (!strcmp(argv[i], "--push")))
1145#ifdef LIBXML_PUSH_ENABLED
1146	    push++;
1147#else
1148	    fprintf(stderr,"'push' not enabled in library - ignoring\n");
1149#endif /* LIBXML_PUSH_ENABLED */
1150	else if ((!strcmp(argv[i], "-speed")) ||
1151	         (!strcmp(argv[i], "--speed")))
1152	    speed++;
1153	else if ((!strcmp(argv[i], "-timing")) ||
1154	         (!strcmp(argv[i], "--timing"))) {
1155	    nonull++;
1156	    timing++;
1157	    quiet++;
1158	} else if ((!strcmp(argv[i], "-repeat")) ||
1159	         (!strcmp(argv[i], "--repeat"))) {
1160	    repeat++;
1161	    quiet++;
1162	} else if ((!strcmp(argv[i], "-noent")) ||
1163	         (!strcmp(argv[i], "--noent")))
1164	    noent++;
1165	else if ((!strcmp(argv[i], "-quiet")) ||
1166	         (!strcmp(argv[i], "--quiet")))
1167	    quiet++;
1168	else if ((!strcmp(argv[i], "-sax2")) ||
1169	         (!strcmp(argv[i], "--sax2")))
1170	    sax2++;
1171	else if ((!strcmp(argv[i], "-nonull")) ||
1172	         (!strcmp(argv[i], "--nonull")))
1173	    nonull++;
1174    }
1175    if (noent != 0) xmlSubstituteEntitiesDefault(1);
1176    for (i = 1; i < argc ; i++) {
1177	if (argv[i][0] != '-') {
1178	    if (timing) {
1179		startTimer();
1180	    }
1181	    parseAndPrintFile(argv[i]);
1182	    if (timing) {
1183		endTimer("Parsing");
1184	    }
1185	    files ++;
1186	}
1187    }
1188    xmlCleanupParser();
1189    xmlMemoryDump();
1190
1191    return(0);
1192}
1193#else
1194int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1195    printf("%s : SAX1 parsing support not compiled in\n", argv[0]);
1196    return(0);
1197}
1198#endif /* LIBXML_SAX1_ENABLED */
1199