Newer
Older
* Copyright (c) 1999-2000 The Apache Software Foundation. All rights
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation, and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.ibm.com . For more information
* on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
* $Id$
*
* @author Andy Heninger, IBM
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/parsers/DOMParser.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
//------------------------------------------------------------------------------
//
// Windows specific code for starting threads
//
//------------------------------------------------------------------------------
#ifdef PLATFORM_WIN32
#include "Windows.h"
#include "process.h"
class ThreadFuncs // This class isolates OS dependent threading
{ // functions from the rest of ThreadTest program.
public:
static void Sleep(int millis) {::Sleep(millis);};
static void startThread(ThreadFunc, void *param);
};
void ThreadFuncs::startThread(ThreadFunc func, void *param)
{
HANDLE tHandle;
DWORD threadID;
tHandle = CreateThread(0, // Security Attributes,
0x10000, // Stack Size,
func, // Starting Address.
param, // Parmeters
0, // Creation Flags,
&threadID); // Thread ID (Can not be null on 95/98)
if (tHandle == 0)
{
fprintf(stderr, "Error starting thread. Errno = %d\n", errno);
// Set the priority of the working threads low, so that the UI of the running system will
// remain responsive.
SetThreadPriority(tHandle, THREAD_PRIORITY_IDLE);
#elif defined (AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) || defined (OS390) || defined(FREEBSD)
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
//------------------------------------------------------------------------------
//
// UNIX specific code for starting threads
//
//------------------------------------------------------------------------------
typedef void (*ThreadFunc)(void *);
typedef void *(*pthreadfunc)(void *);
class ThreadFuncs // This class isolates OS dependent threading
{ // functions from the rest of ThreadTest program.
public:
static void startThread(ThreadFunc, void *param);
};
void ThreadFuncs::Sleep(int millis)
{
int seconds = millis/1000;
if (seconds <= 0) seconds = 1;
::sleep(seconds);
void ThreadFuncs::startThread(ThreadFunc func, void *param)
{
unsigned long x;
pthread_t tId;
//thread_t tId;
#if defined(_HP_UX) && defined(XML_USE_DCE)
x = pthread_create( &tId, pthread_attr_default, (pthreadfunc)func, param);
#else
pthread_attr_t attr;
x = pthread_create( &tId, &attr, (pthreadfunc)func, param);
if (x == -1)
{
fprintf(stderr, "Error starting thread. Errno = %d\n", errno);
#else
#error This platform is not supported
//------------------------------------------------------------------------------
//
// struct InFileInfo One of these structs will be set up for each file listed
// on the command line. Once set, the data is unchanging
// and can safely be referenced by the test threads without
// use of synchronization.
//
//------------------------------------------------------------------------------
struct InFileInfo
{
char *fileName;
XMLCh *uFileName; // When doing an in-memory parse, avoid transcoding file name
// each time through.
char *fileContent; // If doing an in-memory parse, this field points
// to an allocated string containing the entire file
// contents. Otherwise it's 0.
size_t fileSize; // The file length. Only initialized when doing
// an in-memory test.
int checkSum; // The XML checksum. Set up by the main thread for
// each file before the worker threads are started.
};
//------------------------------------------------------------------------------
//
// struct runInfo Holds the info extracted from the command line.
// There is only one of these, and it is static, and
// unchanging once the command line has been parsed.
// During the test, the threads will access this info without
// any synchronization.
//
//------------------------------------------------------------------------------
const int MAXINFILES = 25;
struct RunInfo
{
int numThreads;
bool validating;
bool dom;
bool inMemory;
bool doSchema;
bool schemaFullChecking;
bool doNamespaces;
int totalTime;
int numInputFiles;
InFileInfo files[MAXINFILES];
};
//------------------------------------------------------------------------------
//
// struct threadInfo Holds information specific to an individual thread.
// One of these is set up for each thread in the test.
// The main program monitors the threads by looking
// at the status stored in these structs.
//
//------------------------------------------------------------------------------
struct ThreadInfo
{
bool fHeartBeat; // Set true by the thread each time it finishes
// parsing a file.
unsigned int fParses; // Number of parses completed.
int fThreadNum; // Identifying number for this thread.
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
ThreadInfo() {
fHeartBeat = false;
fParses = 0;
fThreadNum = -1;
}
};
//
//------------------------------------------------------------------------------
//
// Global Data
//
//------------------------------------------------------------------------------
RunInfo gRunInfo;
ThreadInfo *gThreadInfo;
//------------------------------------------------------------------------------
//
// class ThreadParser Bundles together a SAX parser and the SAX handlers
// and contains the API that the rest of this test
// program uses for creating parsers and doing parsing.
//
// Multiple instances of this class can operate concurrently
// in different threads.
//
//-------------------------------------------------------------------------------
class ThreadParser: public HandlerBase
{
private:
int fCheckSum;
SAXParser* fSAXParser;
public: // This is the API used by the rest of the test program
ThreadParser();
~ThreadParser();
int parse(int fileNum); // Parse the specified file. fileNum is an index
// into the gRunInfo.files array.
// return the XML checksum, or
// 0 if a parse error occured.
int reCheck(); // Try to compute the checksum again.
// for DOM, re-walk the tree.
// for SAX, can't do, just return previous value.
void domPrint(const DOM_Node &node); // Dump out the contents of a node,
void domPrint(); // including any children. Default (no param)
// version dumps the entire document.
void idomPrint(const IDOM_Node *node); // Dump out the contents of a node,
void idomPrint(); // including any children. Default (no param)
// version dumps the entire document.
private:
ThreadParser(const ThreadParser &); // No copy constructor
const ThreadParser & operator =(const ThreadParser &); // No assignment.
void addToCheckSum(const XMLCh *chars, int len=-1);
void domCheckSum(const DOM_Node &);
public: // Not really public,
// These are the SAX call-back functions
// that this class implements.
void startElement(const XMLCh* const name, AttributeList& attributes);
void characters(const XMLCh* const chars, const unsigned int length) {
addToCheckSum(chars, length);};
void ignorableWhitespace(const XMLCh* const chars, const unsigned int length) {
addToCheckSum(chars, length);};
void resetDocument() {};
void warning(const SAXParseException& exception) {
fprintf(stderr, "*** Warning ");
fprintf(stderr, "*** Error ");
void fatalError(const SAXParseException& exception) {
fprintf(stderr, "***** Fatal error ");
};
//
// ThreadParser constructor. Invoked by the threads of the test program
// to create parsers.
//
ThreadParser::ThreadParser()
{
fSAXParser = 0;
fDOMParser = 0;
if (gRunInfo.dom) {
// Set up to use a DOM parser
fDOMParser = new DOMParser;
fDOMParser->setDoValidation(gRunInfo.validating);
fDOMParser->setDoSchema(gRunInfo.doSchema);
fDOMParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
fDOMParser->setDoNamespaces(gRunInfo.doNamespaces);
else if (gRunInfo.idom) {
// Set up to use a DOM parser
fIDOMParser = new IDOMParser;
fIDOMParser->setDoValidation(gRunInfo.validating);
fIDOMParser->setDoSchema(gRunInfo.doSchema);
fIDOMParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
fIDOMParser->setDoNamespaces(gRunInfo.doNamespaces);
fIDOMParser->setErrorHandler(this);
}
else
{
// Set up to use a SAX parser.
fSAXParser = new SAXParser;
fSAXParser->setDoValidation(gRunInfo.validating);
fSAXParser->setDoSchema(gRunInfo.doSchema);
fSAXParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
fSAXParser->setDoNamespaces(gRunInfo.doNamespaces);
fSAXParser->setDocumentHandler(this);
fSAXParser->setErrorHandler(this);
}
//------------------------------------------------------------------------
//
// parse - This is the method that is invoked by the rest of
// the test program to actually parse an XML file.
//
//------------------------------------------------------------------------
int ThreadParser::parse(int fileNum)
{
MemBufInputSource *mbis = 0;
InFileInfo *fInfo = &gRunInfo.files[fileNum];
fCheckSum = 0;
if (gRunInfo.inMemory) {
mbis = new MemBufInputSource((const XMLByte *) fInfo->fileContent,
fInfo->fileSize,
try
{
if (gRunInfo.dom) {
// Do a DOM parse
fDOMParser->parse(*mbis);
else
fDOMParser->parse(fInfo->fileName);
DOM_Document doc = fDOMParser->getDocument();
domCheckSum(doc);
}
else if (gRunInfo.idom) {
// Do a IDOM parse
if (gRunInfo.inMemory)
fIDOMParser->parse(*mbis);
else
fIDOMParser->parse(fInfo->fileName);
fDoc = fIDOMParser->getDocument();
idomCheckSum(fDoc);
}
fSAXParser->parse(*mbis);
else
fSAXParser->parse(fInfo->fileName);
}
}
char *exceptionMessage = XMLString::transcode(e.getMessage());
fprintf(stderr, " during parsing: %s \n Exception message is: %s \n",
fInfo->fileName, exceptionMessage);
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
delete [] exceptionMessage;
errors = true;
}
catch (const DOM_DOMException& toCatch)
{
fprintf(stderr, " during parsing: %s \n DOMException code is: %i \n",
fInfo->fileName, toCatch.code);
errors = true;
}
catch (const IDOM_DOMException& toCatch)
{
fprintf(stderr, " during parsing: %s \n IDOMException code is: %i \n",
fInfo->fileName, toCatch.code);
errors = true;
}
catch (const SAXParseException& e)
{
char *exceptionMessage = XMLString::transcode(e.getMessage());
fprintf(stderr, " during parsing: %s \n Exception message is: %s \n",
fInfo->fileName, exceptionMessage);
delete [] exceptionMessage;
errors = true;
}
catch (...)
{
fprintf(stderr, "Unexpected exception during parsing\n");
errors = true;
if (errors)
return 0; // if errors occurred, return zero as if checksum = 0;
//
// addToCheckSum - private function, used within ThreadParser in
// computing the checksum of the XML file.
//
// Unichar Strings to be added to the checksum
// can either be null terminated (omit len param, which
// will then default to -1), or provide an explicit
// length.
//
void ThreadParser::addToCheckSum(const XMLCh *chars, int len)
{
{
// Null terminated string.
while (*chars != 0)
{
fCheckSum = fCheckSum*5 + *chars;
chars++;
}
}
else
{
// String with character count.
int i;
for (i=0; i<len; i++)
fCheckSum = fCheckSum*5 + chars[i];
}
//
// startElement - our SAX handler callback function for element starts.
// update the document checksum with the element name
// and any attribute names and values.
//
void ThreadParser::startElement(const XMLCh *const name, AttributeList &attributes)
{
addToCheckSum(name);
int n = attributes.getLength();
int i;
for (i=0; i<n; i++)
{
const XMLCh *attNam = attributes.getName(i);
addToCheckSum(attNam);
const XMLCh *attVal = attributes.getValue(i);
addToCheckSum(attVal);
}
//
// domCheckSum - Compute the check sum for a DOM node.
// Works recursively - initially called with a document node.
//
void ThreadParser::domCheckSum(const DOM_Node &node)
{
DOMString s;
DOM_Node child;
DOM_NamedNodeMap attributes;
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
{
s = node.getNodeName(); // the element name
attributes = node.getAttributes(); // Element's attributes
int numAttributes = attributes.getLength();
int i;
for (i=0; i<numAttributes; i++)
domCheckSum(attributes.item(i));
addToCheckSum(s.rawBuffer(), s.length()); // Content and Children
for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
domCheckSum(child);
break;
}
case DOM_Node::ATTRIBUTE_NODE:
{
s = node.getNodeName(); // The attribute name
addToCheckSum(s.rawBuffer(), s.length());
s = node.getNodeValue(); // The attribute value
if (s != 0)
addToCheckSum(s.rawBuffer(), s.length());
break;
}
case DOM_Node::TEXT_NODE:
case DOM_Node::CDATA_SECTION_NODE:
{
s = node.getNodeValue();
addToCheckSum(s.rawBuffer(), s.length());
break;
}
case DOM_Node::ENTITY_REFERENCE_NODE:
case DOM_Node::DOCUMENT_NODE:
{
// For entity references and the document, nothing is dirctly
// added to the checksum, but we do want to process the chidren nodes.
//
for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
domCheckSum(child);
break;
}
}
}
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
void ThreadParser::idomCheckSum(const IDOM_Node *node)
{
const XMLCh *s;
IDOM_Node *child;
IDOM_NamedNodeMap *attributes;
switch (node->getNodeType() )
{
case IDOM_Node::ELEMENT_NODE:
{
s = node->getNodeName(); // the element name
attributes = node->getAttributes(); // Element's attributes
int numAttributes = attributes->getLength();
int i;
for (i=0; i<numAttributes; i++)
idomCheckSum(attributes->item(i));
addToCheckSum(s); // Content and Children
for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
idomCheckSum(child);
break;
}
case IDOM_Node::ATTRIBUTE_NODE:
{
s = node->getNodeName(); // The attribute name
addToCheckSum(s);
s = node->getNodeValue(); // The attribute value
if (s != 0)
addToCheckSum(s);
break;
}
case IDOM_Node::TEXT_NODE:
case IDOM_Node::CDATA_SECTION_NODE:
{
s = node->getNodeValue();
addToCheckSum(s);
break;
}
case IDOM_Node::ENTITY_REFERENCE_NODE:
case IDOM_Node::DOCUMENT_NODE:
{
// For entity references and the document, nothing is dirctly
// added to the checksum, but we do want to process the chidren nodes.
//
for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
idomCheckSum(child);
break;
}
}
}
//
// Recompute the checksum. Meaningful only for DOM, will tell us whether
// a failure is transient, or whether the DOM data is permanently corrupted.
//
int ThreadParser::reCheck()
{
if (gRunInfo.dom) {
fCheckSum = 0;
DOM_Document doc = fDOMParser->getDocument();
domCheckSum(doc);
}
else if (gRunInfo.idom) {
fCheckSum = 0;
idomCheckSum(fDoc);
}
// domPrint - Dump the contents of a DOM node.
// For debugging failures, when all else fails.
// Works recursively - initially called with a document node.
//
void ThreadParser::domPrint()
{
DOMString("Begin DOMPrint ...\n").print();
if (gRunInfo.dom)
domPrint(fDOMParser->getDocument());
DOMString("End DOMPrint\n").print();
void ThreadParser::domPrint(const DOM_Node &node)
{
DOMString s;
DOM_Node child;
DOM_NamedNodeMap attributes;
{
DOMString("<").print();
node.getNodeName().print(); // the element name
attributes = node.getAttributes(); // Element's attributes
int numAttributes = attributes.getLength();
int i;
for (i=0; i<numAttributes; i++) {
domPrint(attributes.item(i));
}
DOMString(">").print();
for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
domPrint(child);
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
DOMString("</").print();
node.getNodeName().print();
DOMString(">").print();
break;
}
case DOM_Node::ATTRIBUTE_NODE:
{
DOMString(" ").print();
node.getNodeName().print(); // The attribute name
DOMString("= \"").print();
node.getNodeValue().print(); // The attribute value
DOMString("\"").print();
break;
}
case DOM_Node::TEXT_NODE:
case DOM_Node::CDATA_SECTION_NODE:
{
node.getNodeValue().print();
break;
}
case DOM_Node::ENTITY_REFERENCE_NODE:
case DOM_Node::DOCUMENT_NODE:
{
// For entity references and the document, nothing is dirctly
// printed, but we do want to process the chidren nodes.
//
for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
domPrint(child);
break;
}
}
}
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
void ThreadParser::idomPrint()
{
printf("Begin IDOMPrint ...\n");
if (gRunInfo.idom)
idomPrint(fIDOMParser->getDocument());
printf("End IDOMPrint\n");
}
static void printString(const XMLCh *str)
{
char *s = XMLString::transcode(str);
printf("%s", s);
delete s;
}
void ThreadParser::idomPrint(const IDOM_Node *node)
{
IDOM_Node *child;
IDOM_NamedNodeMap *attributes;
switch (node->getNodeType() )
{
case IDOM_Node::ELEMENT_NODE:
{
printf("<");
printString(node->getNodeName()); // the element name
attributes = node->getAttributes(); // Element's attributes
int numAttributes = attributes->getLength();
int i;
for (i=0; i<numAttributes; i++) {
idomPrint(attributes->item(i));
}
printf(">");
for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
idomPrint(child);
printf("</");
printString(node->getNodeName());
printf(">");
break;
}
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
case IDOM_Node::ATTRIBUTE_NODE:
{
printf(" ");
printString(node->getNodeName()); // The attribute name
printf("= \"");
printString(node->getNodeValue()); // The attribute value
printf("\"");
break;
}
case IDOM_Node::TEXT_NODE:
case IDOM_Node::CDATA_SECTION_NODE:
{
printString(node->getNodeValue());
break;
}
case IDOM_Node::ENTITY_REFERENCE_NODE:
case IDOM_Node::DOCUMENT_NODE:
{
// For entity references and the document, nothing is dirctly
// printed, but we do want to process the chidren nodes.
//
for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
idomPrint(child);
break;
}
}
}
//----------------------------------------------------------------------
//
// parseCommandLine Read through the command line, and save all
// of the options in the gRunInfo struct.
//
// Display the usage message if the command line
// is no good.
//
// Probably ought to be a member function of RunInfo.
//
//----------------------------------------------------------------------
void parseCommandLine(int argc, char **argv)
{
gRunInfo.quiet = false; // Set up defaults for run.
gRunInfo.verbose = false;
gRunInfo.numThreads = 2;
gRunInfo.validating = false;
gRunInfo.doSchema = false;
gRunInfo.schemaFullChecking = false;
gRunInfo.doNamespaces = false;
gRunInfo.inMemory = false;
gRunInfo.dumpOnErr = false;
gRunInfo.totalTime = 0;
gRunInfo.numInputFiles = 0;
try // Use exceptions for command line syntax errors.
{
int argnum = 1;
while (argnum < argc)
{
if (strcmp(argv[argnum], "-quiet") == 0)
gRunInfo.quiet = true;
else if (strcmp(argv[argnum], "-verbose") == 0)
gRunInfo.verbose = true;
else if (strcmp(argv[argnum], "-v") == 0)
gRunInfo.validating = true;
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
else if (strcmp(argv[argnum], "-s") == 0)
gRunInfo.doSchema = true;
else if (strcmp(argv[argnum], "-f") == 0)
gRunInfo.schemaFullChecking = true;
else if (strcmp(argv[argnum], "-n") == 0)
gRunInfo.doNamespaces = true;
else if (!strncmp(argv[argnum], "-parser=", 8)) {
const char* const parm = &argv[argnum][8];
if (!strcmp(parm, "dom")) {
gRunInfo.dom = true;
gRunInfo.idom = false;
}
else if (!strcmp(parm, "idom")) {
gRunInfo.idom = true;
gRunInfo.dom = false;
}
else if (!strcmp(parm, "sax")) {
gRunInfo.idom = false;
gRunInfo.dom = false;
}
else
throw 1;
}
else if (strcmp(argv[argnum], "-dom") == 0) {
if (gRunInfo.idom == true)
throw 1;
}
else if (strcmp(argv[argnum], "-idom") == 0) {
if (gRunInfo.dom == true)
throw 1;
gRunInfo.idom = true;
}
else if (strcmp(argv[argnum], "-reuse") == 0)
gRunInfo.reuseParser = true;
else if (strcmp(argv[argnum], "-dump") == 0)
gRunInfo.dumpOnErr = true;
gRunInfo.inMemory = true;
else if (strcmp(argv[argnum], "-threads") == 0)
{
++argnum;
if (argnum >= argc)
throw 1;
gRunInfo.numThreads = atoi(argv[argnum]);
if (gRunInfo.numThreads < 0)
throw 1;
}
else if (strcmp(argv[argnum], "-time") == 0)
{
++argnum;
if (argnum >= argc)
throw 1;
gRunInfo.totalTime = atoi(argv[argnum]);
if (gRunInfo.totalTime < 1)
throw 1;
}
else if (argv[argnum][0] == '-')
{
fprintf(stderr, "Unrecognized command line option. Scanning \"%s\"\n",
argv[argnum]);
throw 1;
}
else
{
gRunInfo.numInputFiles++;
if (gRunInfo.numInputFiles >= MAXINFILES)
{
fprintf(stderr, "Too many input files. Limit is %d\n", MAXINFILES);
throw 1;
}
gRunInfo.files[gRunInfo.numInputFiles-1].fileName = argv[argnum];
}
// We've made it through the command line.
// Verify that at least one input file to be parsed was specified.
{
fprintf(stderr, "No input XML file specified on command line.\n");
throw 1;
};
}
catch (int)
{
fprintf(stderr, "usage: threadtest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...\n"
" -n Enable namespace processing. Defaults to off.\n"
" -s Enable schema processing. Defaults to off.\n"
" -parser=xxx Parser Type [dom | idom | sax]. Default is SAX.\n"
" -quiet Suppress periodic status display.\n"
" -verbose Display extra messages.\n"
" -reuse Retain and reuse parser. Default creates new for each parse.\n"
" -time nnn Total time to run, in seconds. Default is forever.\n"
" -dump Dump DOM tree on error.\n"
" -mem Read files into memory once only, and parse them from there.\n"
//---------------------------------------------------------------------------
//
// ReadFilesIntoMemory For use when parsing from memory rather than
// reading the files each time, here is the code that
// reads the files into local memory buffers.
//
// This function is only called once, from the main
// thread, before all of the worker threads are started.
//
//---------------------------------------------------------------------------
void ReadFilesIntoMemory()
{
int fileNum;
FILE *fileF;
size_t t;
if (gRunInfo.inMemory)
{
for (fileNum = 0; fileNum <gRunInfo.numInputFiles; fileNum++)