Newer
Older
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* $Id$
*
* @author Andy Heninger, IBM
*/
James David Berry
committed
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
David Abram Cargill
committed
#include <ctype.h>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
David Abram Cargill
committed
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/Attributes.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
David N Bertoni
committed
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
David Abram Cargill
committed
#include <xercesc/internal/MemoryManagerImpl.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
James David Berry
committed
#ifdef HAVE_PTHREAD
#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;
#if defined(SOLARIS)
// somehow the sleep hangs on Solaris
// so ignore the call
#else
void ThreadFuncs::startThread(ThreadFunc func, void *param)
{
int 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);
David Abram Cargill
committed
} // end of extern "C"
James David Berry
committed
James David Berry
committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//------------------------------------------------------------------------------
//
// Windows specific code for starting threads
//
//------------------------------------------------------------------------------
#include <Windows.h>
#include <process.h>
typedef DWORD (WINAPI *ThreadFunc)(void *);
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);
clearFileInfoMemory();
exit(-1);
}
// Set the priority of the working threads low, so that the UI of the running system will
// remain responsive.
SetThreadPriority(tHandle, THREAD_PRIORITY_IDLE);
}
//------------------------------------------------------------------------------
//
// 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 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
{
David Abram Cargill
committed
bool fHeartBeat; // Set true by the thread each time it finishes
// parsing a file.
bool fInProgress; // Set to false by the thread when parse in progress
unsigned int fParses; // Number of parses completed.
int fThreadNum; // Identifying number for this thread.
fInProgress = false;
fParses = 0;
fThreadNum = -1;
}
};
David Abram Cargill
committed
XERCES_CPP_NAMESPACE_USE
//------------------------------------------------------------------------------
//
// 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
{
bool doGrammarCaching;
David Abram Cargill
committed
bool quiet;
bool verbose;
bool stopNow;
bool dom;
bool sax;
David Abram Cargill
committed
bool reuseParser;
bool inMemory;
bool dumpOnErr;
bool doSchema;
bool schemaFullChecking;
bool doNamespaces;
bool doInitialParse;
bool doNamespacePrefixes; // SAX2
David Abram Cargill
committed
SAXParser::ValSchemes valScheme;
int numThreads;
int totalTime;
int numInputFiles;
unsigned int numParses;
InFileInfo files[MAXINFILES];
};
//
//------------------------------------------------------------------------------
//
// Global Data
//
//------------------------------------------------------------------------------
RunInfo gRunInfo;
ThreadInfo *gThreadInfo;
David Abram Cargill
committed
/** Grammar caching thread testing */
MemoryManager* gpMemMgr = 0;
XMLGrammarPool* gp = 0;
#ifdef HELPER_ROUTINES
David Abram Cargill
committed
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
// Routines which maybe helpful for debugging
static void printString(const XMLCh *str)
{
char *s = XMLString::transcode(str);
printf("%s", s);
delete s;
}
#define CHARS_PER_LINE 40
#define BYTES_PER_LINE 16
/*
* DumpLine: Dump out a buffer (address and length) to stderr.
*/
static void DumpLine(char* address, int length) {
int i, c, charCount=0;
if (length % 4) length += 4;
fprintf(stderr, "%8.8p: ", address);
for (i=0; i < length/4; ++i) {
fprintf(stderr, "%8.8X ", ((int*)address)[i]);
charCount += 9;
}
for (i=charCount; i < CHARS_PER_LINE; ++i) {
putc(' ', stderr);
}
fprintf(stderr, "| ");
for (i=0; i < length; ++i) {
c = address[i];
c = (isprint(c) ? c : '.');
fprintf(stderr, "%c", c);
}
fprintf(stderr, "\n");
}
/*
* dump: dump out a buffer (address and length) to stderr by dumping out
* a line at a time (DumpLine), until the buffer is written out.
*/
static void dump(void* generalAddress, int length) {
int curr = 0;
char* address = (char*) generalAddress;
while (&address[curr] < &address[length-BYTES_PER_LINE]) {
DumpLine(&address[curr], BYTES_PER_LINE);
curr += BYTES_PER_LINE;
}
if (curr < length) {
DumpLine(&address[curr], length-curr);
}
fflush(stderr);
}
#endif
//------------------------------------------------------------------------------
//
// 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.
//
//-------------------------------------------------------------------------------
David Abram Cargill
committed
class ThreadParser
{
public:
class SAXHandler;
class SAX2Handler;
SAXHandler* fSAXHandler;
SAX2Handler* fSAX2Handler;
ErrorHandler* fDOMErrorHandler;
David Abram Cargill
committed
// This is the API used by the rest of the test program
int parse(int fileNum); // Parse the specified file. fileNum is an index
// into the gRunInfo.files array.
// 0 if a parse error occurred.
David Abram Cargill
committed
int getCheckSum() {
return fCheckSum;
David Abram Cargill
committed
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(); // including any children. Default (no param)
void addToCheckSum(const XMLCh *chars, XMLSize_t len=(XMLSize_t)-1);
David Abram Cargill
committed
// These are the SAX call-back functions that this class implements. Can be used
// for SAX and SAX2.
void characters(const XMLCh* const chars, const XMLSize_t length) {
David Abram Cargill
committed
addToCheckSum(chars, length);
void ignorableWhitespace(const XMLCh* const chars, const XMLSize_t length) {
David Abram Cargill
committed
addToCheckSum(chars, length);
David Abram Cargill
committed
void resetDocument() {
void warning(const SAXParseException& exc) {
fprintf(stderr, "*** Warning ");
David Abram Cargill
committed
fflush(stderr);
throw exc;
void error(const SAXParseException& exc) {
fprintf(stderr, "*** Error ");
David Abram Cargill
committed
fflush(stderr);
throw exc;
void fatalError(const SAXParseException& exc) {
fprintf(stderr, "***** Fatal error ");
David Abram Cargill
committed
fflush(stderr);
throw exc;
David Abram Cargill
committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
// Create a nested class that can inherit from HandlerBase
// for SAX startElement callbacks.
class SAXHandler : public HandlerBase
{
public:
ThreadParser* SAXInstance;
void startElement(const XMLCh* const name, AttributeList& attributes);
};
// Create a nested class that can inherit from DefaultHandler
// for SAX2 startElement callbacks.
class SAX2Handler : public DefaultHandler
{
public:
ThreadParser* SAX2Instance;
void startElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const Attributes& attributes);
};
private:
int fCheckSum;
SAXParser* fSAXParser;
SAX2XMLReader* fSAX2Parser;
XercesDOMParser* fXercesDOMParser;
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * fDoc;
David Abram Cargill
committed
ThreadParser(const ThreadParser &); // No copy constructor
const ThreadParser & operator =(const ThreadParser &); // No assignment.
void domCheckSum(const DOMNode *);
};
//
// ThreadParser constructor. Invoked by the threads of the test program
// to create parsers.
//
ThreadParser::ThreadParser()
David Abram Cargill
committed
fSAXParser = 0;
fSAX2Parser = 0;
fXercesDOMParser = 0;
David Abram Cargill
committed
fSAXHandler = 0;
fSAX2Handler = 0;
fDOMErrorHandler = 0;
David Abram Cargill
committed
fDoc = 0;
fCheckSum = 0;
if (gRunInfo.dom) {
// Set up to use a DOM parser
David Abram Cargill
committed
/** Grammar caching thread testing */
if (gp) {
fXercesDOMParser = new XercesDOMParser(0, XMLPlatformUtils::fgMemoryManager, gp);
fXercesDOMParser->cacheGrammarFromParse(true);
fXercesDOMParser->useCachedGrammarInParse(true);
David Abram Cargill
committed
else {
fXercesDOMParser = new XercesDOMParser;
}
switch (gRunInfo.valScheme) {
case SAXParser::Val_Never:
fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Never);
break;
case SAXParser::Val_Auto:
fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Auto);
break;
default: //SAXParser::Val_Always:
fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Always);
break;
fXercesDOMParser->setDoSchema(gRunInfo.doSchema);
fXercesDOMParser->setHandleMultipleImports (true);
fXercesDOMParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
fXercesDOMParser->setDoNamespaces(gRunInfo.doNamespaces);
David Abram Cargill
committed
fDOMErrorHandler = (ErrorHandler*) new HandlerBase();
fXercesDOMParser->setErrorHandler(fDOMErrorHandler);
David Abram Cargill
committed
else if (gRunInfo.sax) {
// Set up to use a SAX1 parser.
/** Grammar caching thread testing */
if (gp) {
fSAXParser = new SAXParser(0, XMLPlatformUtils::fgMemoryManager, gp);
fSAXParser->cacheGrammarFromParse(true);
fSAXParser->useCachedGrammarInParse(true);
David Abram Cargill
committed
else {
fSAXParser = new SAXParser();
}
fSAXParser->setValidationScheme(gRunInfo.valScheme);
fSAXParser->setHandleMultipleImports (true);
fSAXParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
fSAXParser->setDoNamespaces(gRunInfo.doNamespaces);
David Abram Cargill
committed
fSAXHandler = new ThreadParser::SAXHandler();
fSAXHandler->SAXInstance = this;
fSAXParser->setDocumentHandler(fSAXHandler);
fSAXParser->setErrorHandler(fSAXHandler);
David Abram Cargill
committed
// Set up to use a SAX2 parser.
/** Grammar caching thread testing */
David Abram Cargill
committed
fSAX2Parser = XMLReaderFactory::createXMLReader(gpMemMgr, gp);
fSAX2Parser->setFeature(XMLUni::fgXercesCacheGrammarFromParse,true);
fSAX2Parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse,true);
}
else {
fSAX2Parser = XMLReaderFactory::createXMLReader();
}
David Abram Cargill
committed
fSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpaces,(gRunInfo.doNamespaces));
fSAX2Parser->setFeature(XMLUni::fgXercesSchema,(gRunInfo.doSchema));
fSAX2Parser->setFeature(XMLUni::fgXercesHandleMultipleImports, true);
David Abram Cargill
committed
fSAX2Parser->setFeature(XMLUni::fgXercesSchemaFullChecking,(gRunInfo.schemaFullChecking));
switch (gRunInfo.valScheme) {
case SAXParser::Val_Never:
fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, false);
break;
case SAXParser::Val_Auto:
fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
fSAX2Parser->setFeature(XMLUni::fgXercesDynamic, true);
break;
default: //SAXParser::Val_Always:
fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
fSAX2Parser->setFeature(XMLUni::fgXercesDynamic, false);
break;
}
fSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes,(gRunInfo.doNamespacePrefixes));
David Abram Cargill
committed
fSAX2Handler = new ThreadParser::SAX2Handler();
fSAX2Handler->SAX2Instance = this;
fSAX2Parser->setContentHandler(fSAX2Handler);
fSAX2Parser->setErrorHandler(fSAX2Handler);
}
}
delete fSAXParser;
David Abram Cargill
committed
delete fSAX2Parser;
delete fXercesDOMParser;
David Abram Cargill
committed
delete fSAXHandler;
delete fSAX2Handler;
David Abram Cargill
committed
delete fDOMErrorHandler;
//------------------------------------------------------------------------
//
// 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
fXercesDOMParser->resetDocumentPool();
fXercesDOMParser->parse(*mbis);
fXercesDOMParser->parse(fInfo->fileName);
David Abram Cargill
committed
fDoc = fXercesDOMParser->getDocument();
domCheckSum(fDoc);
David Abram Cargill
committed
else if (gRunInfo.sax) {
// Do a SAX1 parse
fSAXParser->parse(*mbis);
else
fSAXParser->parse(fInfo->fileName);
}
David Abram Cargill
committed
else {
// Do a SAX2 parse
if (gRunInfo.inMemory)
fSAX2Parser->parse(*mbis);
else
fSAX2Parser->parse(fInfo->fileName);
}
}
catch (const OutOfMemoryException&)
{
fprintf(stderr, " during parsing: %s\n OutOfMemoryException.\n", fInfo->fileName);
David Abram Cargill
committed
errors = true;
char *exceptionMessage = XMLString::transcode(e.getMessage());
David Abram Cargill
committed
fprintf(stderr, " during parsing: %s\n Exception message is: %s\n",
XMLString::release(&exceptionMessage);
catch (const DOMException& toCatch)
David Abram Cargill
committed
fprintf(stderr, " during parsing: %s\n DOMException code is: %i\n",
fInfo->fileName, toCatch.code);
errors = true;
}
catch (const SAXParseException& e)
{
char *exceptionMessage = XMLString::transcode(e.getMessage());
David Abram Cargill
committed
fprintf(stderr, " during parsing: %s\n Exception message is: %s\n",
XMLString::release(&exceptionMessage);
errors = true;
}
catch (...)
{
fprintf(stderr, "Unexpected exception during parsing\n");
errors = true;
David Abram Cargill
committed
if (errors) {
fflush(stderr);
return 0; // if errors occurred, return zero as if checksum = 0;
David Abram Cargill
committed
}
//
// 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, XMLSize_t len)
{
// Null terminated string.
while (*chars != 0)
{
fCheckSum = fCheckSum*5 + *chars;
chars++;
}
}
else
{
// String with character count.
for (i=0; i<len; i++)
fCheckSum = fCheckSum*5 + chars[i];
}
David Abram Cargill
committed
// startElement - our SAX handler callback function for startElement.
// Update the document checksum with the element name
David Abram Cargill
committed
void ThreadParser::SAXHandler::startElement(const XMLCh *const name, AttributeList &attributes)
David Abram Cargill
committed
SAXInstance->addToCheckSum(name);
XMLSize_t n = attributes.getLength();
XMLSize_t i;
for (i=0; i<n; i++)
{
const XMLCh *attNam = attributes.getName(i);
David Abram Cargill
committed
SAXInstance->addToCheckSum(attNam);
David Abram Cargill
committed
SAXInstance->addToCheckSum(attVal);
David Abram Cargill
committed
//
// startElement - our SAX2 handler callback function for startElement.
// Update the document checksum with the element name
// and any attribute names and values.
//
void ThreadParser::SAX2Handler::startElement(const XMLCh *const /*uri*/,
David Abram Cargill
committed
const XMLCh *const localname,
const XMLCh *const /*qname*/,
David Abram Cargill
committed
const Attributes& attributes)
{
SAX2Instance->addToCheckSum(localname);
XMLSize_t n = attributes.getLength();
XMLSize_t i;
David Abram Cargill
committed
for (i=0; i<n; i++)
{
const XMLCh *attNam = attributes.getQName(i);
SAX2Instance->addToCheckSum(attNam);
const XMLCh *attVal = attributes.getValue(i);
SAX2Instance->addToCheckSum(attVal);
}
}
//
// domCheckSum - Compute the check sum for a DOM node.
// Works recursively - initially called with a document node.
//
void ThreadParser::domCheckSum(const DOMNode *node)
DOMNode *child;
DOMNamedNodeMap *attributes;
case DOMNode::ELEMENT_NODE:
{
s = node->getNodeName(); // the element name
attributes = node->getAttributes(); // Element's attributes
XMLSize_t numAttributes = attributes->getLength();
XMLSize_t i;
domCheckSum(attributes->item(i));
addToCheckSum(s); // Content and Children
for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
domCheckSum(child);
case DOMNode::ATTRIBUTE_NODE:
{
s = node->getNodeName(); // The attribute name
addToCheckSum(s);
s = node->getNodeValue(); // The attribute value
if (s != 0)
addToCheckSum(s);
break;
}
case DOMNode::TEXT_NODE:
case DOMNode::CDATA_SECTION_NODE:
{
s = node->getNodeValue();
addToCheckSum(s);
break;
}
case DOMNode::ENTITY_REFERENCE_NODE:
case DOMNode::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);
case DOMNode::ENTITY_NODE:
case DOMNode::PROCESSING_INSTRUCTION_NODE:
case DOMNode::COMMENT_NODE:
case DOMNode::DOCUMENT_TYPE_NODE:
case DOMNode::DOCUMENT_FRAGMENT_NODE:
case DOMNode::NOTATION_NODE:
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;
// 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()
{
printf("Begin DOMPrint ...\n");
{
try
{
XMLCh tempStr[100];
XMLString::transcode("LS", tempStr, 99);
DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer();
Alberto Massari
committed
DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
XMLFormatTarget *myFormTarget = new StdOutFormatTarget();
Alberto Massari
committed
theOutput->setByteStream(myFormTarget);
DOMNode *doc = fXercesDOMParser->getDocument();
Alberto Massari
committed
theSerializer->write(doc,theOutput);
delete myFormTarget;
theSerializer->release();
theOutput->release();
}
catch (...)
{
// do nothing
}
}
printf("End DOMPrint\n");
//----------------------------------------------------------------------
//
// 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.doGrammarCaching = false;
gRunInfo.quiet = false; // Set up defaults for run.
gRunInfo.verbose = false;
gRunInfo.stopNow = false;
gRunInfo.sax = true;
gRunInfo.inMemory = false;
David Abram Cargill
committed
gRunInfo.doSchema = false;
gRunInfo.schemaFullChecking = false;
gRunInfo.doNamespaces = false;
gRunInfo.doInitialParse = false;
gRunInfo.doNamespacePrefixes = false;
David Abram Cargill
committed
gRunInfo.valScheme = SAXParser::Val_Auto;
gRunInfo.numThreads = 2;
gRunInfo.totalTime = 0;
gRunInfo.numInputFiles = 0;
David Abram Cargill
committed
gRunInfo.numParses = 0;
try // Use exceptions for command line syntax errors.
{
int argnum = 1;
David Abram Cargill
committed
while (argnum < argc) {
if (strcmp(argv[argnum], "-quiet") == 0)
gRunInfo.quiet = true;
else if (strcmp(argv[argnum], "-verbose") == 0)
gRunInfo.verbose = true;
David Abram Cargill
committed
else if (strncmp(argv[argnum], "-v=", 3) == 0) {
const char* const parm = &argv[argnum][3];
if (!strcmp(parm, "never"))
gRunInfo.valScheme = SAXParser::Val_Never;
else if (!strcmp(parm, "auto"))
gRunInfo.valScheme = SAXParser::Val_Auto;
else if (!strcmp(parm, "always"))
gRunInfo.valScheme = SAXParser::Val_Always;
else {
fprintf(stderr, "Unrecognized -v option \"%s\"\n", parm);
David Abram Cargill
committed
throw 1;
}
}
else if (strcmp(argv[argnum], "-v") == 0) {
fprintf(stderr, "Please note the -v option has been changed to -v=[always | never | auto]\n");
fprintf(stderr, "ThreadTest will continue with -v=always\n");
gRunInfo.valScheme = SAXParser::Val_Always;
}
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;
David Abram Cargill
committed
else if (strcmp(argv[argnum], "-p") == 0)
gRunInfo.doNamespacePrefixes = true;
const char* const parm = &argv[argnum][8];
David Abram Cargill
committed
gRunInfo.sax = false;
}
else if (!strcmp(parm, "sax")) {
gRunInfo.dom = false;
gRunInfo.sax = true;
David Abram Cargill
committed
else if (!strcmp(parm, "sax2")) {
gRunInfo.dom = false;
gRunInfo.sax = false;
David Abram Cargill
committed
else {
fprintf(stderr, "Unrecognized -parser option \"%s\"\n", parm);
David Abram Cargill
committed
}
David Abram Cargill
committed
else if (strcmp(argv[argnum], "-init") == 0)
gRunInfo.doInitialParse = true;
else if (strcmp(argv[argnum], "-reuse") == 0)
gRunInfo.reuseParser = true;
else if (strcmp(argv[argnum], "-dump") == 0)
gRunInfo.dumpOnErr = true;
gRunInfo.inMemory = true;
David Abram Cargill
committed
else if (strcmp(argv[argnum], "-threads") == 0) {
David Abram Cargill
committed
if (argnum >= argc) {
fprintf(stderr, "Invalid -threads option (missing # of threads)\n");
David Abram Cargill
committed
}
David Abram Cargill
committed
if (gRunInfo.numThreads < 0) {
fprintf(stderr, "Invalid -threads option (negative # of threads)\n");
David Abram Cargill
committed
}
David Abram Cargill
committed
else if (strcmp(argv[argnum], "-time") == 0) {
David Abram Cargill
committed
if (argnum >= argc) {
fprintf(stderr, "Invalid -time option (missing time value)\n");
David Abram Cargill
committed
}
David Abram Cargill
committed
if (gRunInfo.totalTime < 1) {
fprintf(stderr, "Invalid -time option (time value < 1)\n");
David Abram Cargill
committed
}
David Abram Cargill
committed
else if (strcmp(argv[argnum], "-gc") == 0)
gRunInfo.doGrammarCaching = true;
David Abram Cargill
committed
else if (strcmp(argv[argnum], "-parses") == 0) {
++argnum;
if (argnum >= argc) {
fprintf(stderr, "Invalid -parses option (missing # of parses)\n");
throw 1;
}
int temp = atoi(argv[argnum]);
if (temp < 0) {
fprintf(stderr, "Invalid -parses option (negative # of parses)\n");
throw 1;
}
gRunInfo.numParses = temp;
David Abram Cargill
committed
else if (argv[argnum][0] == '-') {
fprintf(stderr, "Unrecognized command line option. Scanning \"%s\"\n",
argv[argnum]);
throw 1;
}
David Abram Cargill
committed
else {
David Abram Cargill
committed
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];
}
David Abram Cargill
committed
// Verify that at least one input file to be parsed was specified.
if (gRunInfo.numInputFiles == 0) {
fprintf(stderr, "No input XML file specified on command line.\n");
throw 1;
};
David Abram Cargill
committed
if (gRunInfo.numParses && gRunInfo.totalTime) {
fprintf(stderr, "Both -parses nnn and -time nnn were specified. Ignoring -time nnn.\n");
}
fprintf(stderr, "usage: ThreadTest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...\n"
David Abram Cargill
committed
" -v=xxx Validation scheme [always | never | auto]. Default is AUTO.\n"
" -n Enable namespace processing. Defaults to off.\n"
" -s Enable schema processing. Defaults to off.\n"
" -f Enable full schema constraint checking. Defaults to off.\n"
David Abram Cargill
committed
" -parser=xxx Parser Type [dom | sax | sax2]. Default is SAX (SAX1).\n"
" -p Enable namespace prefixes. Defaults to off.\n"
" (Only used with -parser=sax2, ignored otherwise.)\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"
David Abram Cargill
committed
" -parses nnn Run for nnn parses instead of time. Default is to use time\n"
David Abram Cargill
committed
" -mem Read files into memory once only, and parse them from there.\n"
David Abram Cargill
committed
" -gc Enable grammar caching (i.e. grammar cached and used in subsequent parses). Defaults to off.\n"
David Abram Cargill
committed
" -init Perform an initial parse of the file(s) before starting up the individual threads.\n\n"
//---------------------------------------------------------------------------
//