/ libxml2 / testSAX.c
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 */