• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
my_gettimeofday(struct timeval * tvp,void * tzp)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
startTimer(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
endTimer(const char * fmt,...)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
startTimer(void)148  startTimer(void)
149  {
150      begin = clock();
151  }
152  static void XMLCDECL
endTimer(const char * fmt,...)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
startTimer(void)175  startTimer(void)
176  {
177      /*
178       * Do nothing
179       */
180  }
181  static void XMLCDECL
endTimer(char * format,...)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
isStandaloneDebug(void * ctx ATTRIBUTE_UNUSED)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
hasInternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)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
hasExternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)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
internalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)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
externalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)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
resolveEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * publicId,const xmlChar * systemId)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
getEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)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
getParameterEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)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
entityDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,int type,const xmlChar * publicId,const xmlChar * systemId,xmlChar * content)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
attributeDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * elem,const xmlChar * name,int type,int def,const xmlChar * defaultValue,xmlEnumerationPtr tree)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
elementDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,int type,xmlElementContentPtr content ATTRIBUTE_UNUSED)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
notationDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)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
unparsedEntityDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId,const xmlChar * notationName)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
setDocumentLocatorDebug(void * ctx ATTRIBUTE_UNUSED,xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)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
startDocumentDebug(void * ctx ATTRIBUTE_UNUSED)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
endDocumentDebug(void * ctx ATTRIBUTE_UNUSED)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
startElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar ** atts)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
endElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)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
charactersDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)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
referenceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)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
ignorableWhitespaceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)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
processingInstructionDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * target,const xmlChar * data)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
cdataBlockDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value,int len)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
commentDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value)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
warningDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)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
errorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)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
fatalErrorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)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
startElementNsDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI,int nb_namespaces,const xmlChar ** namespaces,int nb_attributes,int nb_defaulted,const xmlChar ** attributes)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
endElementNsDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI)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
parseAndPrintFile(char * filename)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  
main(int argc,char ** argv)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
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)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 */
1199