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>
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 Abram Cargill
committed
#include <xercesc/internal/XMLGrammarPoolImpl.hpp>
#include <xercesc/internal/MemoryManagerImpl.hpp>
#include <xercesc/util/OutOfMemoryException.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);
James David Berry
committed
#elif defined (AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) || defined (OS390) || defined(MACOSX) || defined(FREEBSD) || defined(__CYGWIN__) || defined(__QNXNTO__)
#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)
{
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);
David Abram Cargill
committed
} // end of extern "C"
#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 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
243
244
245
246
247
248
249
250
251
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
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;
bool quiet;
bool verbose;
bool stopNow;
bool dom;
bool sax;
bool reuseParser;
bool inMemory;
bool dumpOnErr;
bool doSchema;
bool schemaFullChecking;
bool doNamespaces;
bool doInitialParse;
bool doNamespacePrefixes; // SAX2
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;
David Abram Cargill
committed
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
// 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);
}
//------------------------------------------------------------------------------
//
// 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;
// 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;
};
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, int len=-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 unsigned int length) {
David Abram Cargill
committed
addToCheckSum(chars, length);
};
void ignorableWhitespace(const XMLCh* const chars, const unsigned int length) {
David Abram Cargill
committed
addToCheckSum(chars, length);
};
void resetDocument() {
};
void warning(const SAXParseException& exception) {
fprintf(stderr, "*** Warning ");
David Abram Cargill
committed
fflush(stderr);
throw exception;
};
fprintf(stderr, "*** Error ");
David Abram Cargill
committed
fflush(stderr);
throw exception;
};
void fatalError(const SAXParseException& exception) {
fprintf(stderr, "***** Fatal error ");
David Abram Cargill
committed
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
fflush(stderr);
throw exception;
};
// 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;
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);
}
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->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);
}
else {
fSAXParser = new SAXParser();
}
fSAXParser->setValidationScheme(gRunInfo.valScheme);
fSAXParser->setDoSchema(gRunInfo.doSchema);
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
else {
// Set up to use a SAX2 parser.
/** Grammar caching thread testing */
if (gp) {
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::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));
fSAX2Handler = new ThreadParser::SAX2Handler();
fSAX2Handler->SAX2Instance = this;
fSAX2Parser->setContentHandler(fSAX2Handler);
fSAX2Parser->setErrorHandler(fSAX2Handler);
}
}
David Abram Cargill
committed
delete fSAXParser;
delete fSAX2Parser;
delete fXercesDOMParser;
David Abram Cargill
committed
delete fSAXHandler;
delete fSAX2Handler;
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);
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, 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];
}
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);
int n = attributes.getLength();
int 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,
const XMLCh *const localname,
const XMLCh *const qname,
const Attributes& attributes)
{
SAX2Instance->addToCheckSum(localname);
int n = attributes.getLength();
int i;
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
int numAttributes = attributes->getLength();
int i;
for (i=0; i<numAttributes; 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);
//
// 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);
DOMWriter *theSerializer = ((DOMImplementationLS*)impl)->createDOMWriter();
XMLFormatTarget *myFormTarget = new StdOutFormatTarget();
DOMNode *doc = fXercesDOMParser->getDocument();
theSerializer->writeNode(myFormTarget, *doc);
delete theSerializer;
}
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)
{
David Abram Cargill
committed
gRunInfo.doGrammarCaching = false;
gRunInfo.quiet = false; // Set up defaults for run.
gRunInfo.verbose = false;
David Abram Cargill
committed
gRunInfo.stopNow = false;
David Abram Cargill
committed
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;
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);
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)
David Abram Cargill
committed
gRunInfo.doNamespaces = true;
else if (strcmp(argv[argnum], "-p") == 0)
gRunInfo.doNamespacePrefixes = true;
David Abram Cargill
committed
const char* const parm = &argv[argnum][8];
David Abram Cargill
committed
gRunInfo.sax = false;
}
else if (!strcmp(parm, "sax")) {
gRunInfo.dom = false;
David Abram Cargill
committed
gRunInfo.sax = true;
David Abram Cargill
committed
else if (!strcmp(parm, "sax2")) {
gRunInfo.dom = false;
gRunInfo.sax = false;
}
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
}
}
else if (strcmp(argv[argnum], "-gc") == 0)
gRunInfo.doGrammarCaching = true;
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");
}
David Abram Cargill
committed
fprintf(stderr, "usage: ThreadTest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...\n"
" -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"