Home | History | Annotate | Download | only in libxml2
      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 (at) 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 */
   1199