Sync with tizen 2.4
[platform/upstream/libxml2.git] / testSAX.c
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
53 static int debug = 0;
54 static int copy = 0;
55 static int recovery = 0;
56 static int push = 0;
57 static int speed = 0;
58 static int noent = 0;
59 static int quiet = 0;
60 static int nonull = 0;
61 static int sax2 = 0;
62 static int repeat = 0;
63 static int callbacks = 0;
64 static 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
79 static int
80 my_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)
100 static struct timeval begin, end;
101
102 /*
103  * startTimer: call where you want to start timing
104  */
105 static void
106 startTimer(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  */
116 static void XMLCDECL
117 endTimer(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
146 static clock_t begin, end;
147 static void
148 startTimer(void)
149 {
150     begin = clock();
151 }
152 static void XMLCDECL
153 endTimer(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  */
174 static void
175 startTimer(void)
176 {
177     /*
178      * Do nothing
179      */
180 }
181 static void XMLCDECL
182 endTimer(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  */
203 static 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
238 static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
239 extern 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  */
255 static int
256 isStandaloneDebug(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  */
273 static int
274 hasInternalSubsetDebug(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  */
291 static int
292 hasExternalSubsetDebug(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  */
307 static void
308 internalSubsetDebug(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  */
331 static void
332 externalSubsetDebug(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  */
363 static xmlParserInputPtr
364 resolveEntityDebug(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  */
398 static xmlEntityPtr
399 getEntityDebug(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  */
417 static xmlEntityPtr
418 getParameterEntityDebug(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  */
439 static void
440 entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
441           const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
442 {
443 const 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  */
466 static void
467 attributeDeclDebug(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  */
492 static void
493 elementDeclDebug(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  */
512 static void
513 notationDeclDebug(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  */
533 static void
534 unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
535                    const xmlChar *publicId, const xmlChar *systemId,
536                    const xmlChar *notationName)
537 {
538 const 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  */
562 static void
563 setDocumentLocatorDebug(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  */
577 static void
578 startDocumentDebug(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  */
592 static void
593 endDocumentDebug(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  */
608 static void
609 startElementDebug(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  */
634 static void
635 endElementDebug(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  */
652 static void
653 charactersDebug(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  */
675 static void
676 referenceDebug(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  */
694 static void
695 ignorableWhitespaceDebug(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  */
718 static void
719 processingInstructionDebug(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  */
741 static void
742 cdataBlockDebug(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  */
758 static void
759 commentDebug(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  */
776 static void XMLCDECL
777 warningDebug(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  */
799 static void XMLCDECL
800 errorDebug(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  */
822 static void XMLCDECL
823 fatalErrorDebug(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
836 static 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
871 xmlSAXHandlerPtr 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  */
883 static void
884 startElementNsDebug(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  */
940 static void
941 endElementNsDebug(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
960 static 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
995 static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
996
997 /************************************************************************
998  *                                                                      *
999  *                              Debug                                   *
1000  *                                                                      *
1001  ************************************************************************/
1002
1003 static void
1004 parseAndPrintFile(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
1129 int 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
1194 int 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 */