Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Tester Core
      3  * ----------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Command line parsing.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "tcuCommandLine.hpp"
     25 #include "tcuPlatform.hpp"
     26 #include "deFilePath.hpp"
     27 #include "deStringUtil.hpp"
     28 #include "deString.h"
     29 #include "deInt32.h"
     30 #include "deCommandLine.h"
     31 #include "qpTestLog.h"
     32 #include "qpDebugOut.h"
     33 
     34 #include <string>
     35 #include <vector>
     36 #include <sstream>
     37 #include <fstream>
     38 #include <iostream>
     39 
     40 using std::string;
     41 using std::vector;
     42 
     43 // OOM tests are enabled by default only on platforms that don't do memory overcommit (Win32)
     44 #if (DE_OS == DE_OS_WIN32)
     45 #	define TEST_OOM_DEFAULT		"enable"
     46 #else
     47 #	define TEST_OOM_DEFAULT		"disable"
     48 #endif
     49 
     50 namespace tcu
     51 {
     52 
     53 namespace opt
     54 {
     55 
     56 DE_DECLARE_COMMAND_LINE_OPT(CasePath,			std::string);
     57 DE_DECLARE_COMMAND_LINE_OPT(CaseList,			std::string);
     58 DE_DECLARE_COMMAND_LINE_OPT(CaseListFile,		std::string);
     59 DE_DECLARE_COMMAND_LINE_OPT(StdinCaseList,		bool);
     60 DE_DECLARE_COMMAND_LINE_OPT(LogFilename,		std::string);
     61 DE_DECLARE_COMMAND_LINE_OPT(RunMode,			tcu::RunMode);
     62 DE_DECLARE_COMMAND_LINE_OPT(WatchDog,			bool);
     63 DE_DECLARE_COMMAND_LINE_OPT(CrashHandler,		bool);
     64 DE_DECLARE_COMMAND_LINE_OPT(BaseSeed,			int);
     65 DE_DECLARE_COMMAND_LINE_OPT(TestIterationCount,	int);
     66 DE_DECLARE_COMMAND_LINE_OPT(Visibility,			WindowVisibility);
     67 DE_DECLARE_COMMAND_LINE_OPT(SurfaceWidth,		int);
     68 DE_DECLARE_COMMAND_LINE_OPT(SurfaceHeight,		int);
     69 DE_DECLARE_COMMAND_LINE_OPT(SurfaceType,		tcu::SurfaceType);
     70 DE_DECLARE_COMMAND_LINE_OPT(ScreenRotation,		tcu::ScreenRotation);
     71 DE_DECLARE_COMMAND_LINE_OPT(GLContextType,		std::string);
     72 DE_DECLARE_COMMAND_LINE_OPT(GLConfigID,			int);
     73 DE_DECLARE_COMMAND_LINE_OPT(GLConfigName,		std::string);
     74 DE_DECLARE_COMMAND_LINE_OPT(GLContextFlags,		std::string);
     75 DE_DECLARE_COMMAND_LINE_OPT(CLPlatformID,		int);
     76 DE_DECLARE_COMMAND_LINE_OPT(CLDeviceIDs,		std::vector<int>);
     77 DE_DECLARE_COMMAND_LINE_OPT(CLBuildOptions,		std::string);
     78 DE_DECLARE_COMMAND_LINE_OPT(EGLDisplayType,		std::string);
     79 DE_DECLARE_COMMAND_LINE_OPT(EGLWindowType,		std::string);
     80 DE_DECLARE_COMMAND_LINE_OPT(EGLPixmapType,		std::string);
     81 DE_DECLARE_COMMAND_LINE_OPT(LogImages,			bool);
     82 DE_DECLARE_COMMAND_LINE_OPT(TestOOM,			bool);
     83 
     84 static void parseIntList (const char* src, std::vector<int>* dst)
     85 {
     86 	std::istringstream	str	(src);
     87 	std::string			val;
     88 
     89 	while (std::getline(str, val, ','))
     90 	{
     91 		int intVal = 0;
     92 		de::cmdline::parseType(val.c_str(), &intVal);
     93 		dst->push_back(intVal);
     94 	}
     95 }
     96 
     97 void registerOptions (de::cmdline::Parser& parser)
     98 {
     99 	using de::cmdline::Option;
    100 	using de::cmdline::NamedValue;
    101 
    102 	static const NamedValue<bool> s_enableNames[] =
    103 	{
    104 		{ "enable",		true	},
    105 		{ "disable",	false	}
    106 	};
    107 	static const NamedValue<tcu::RunMode> s_runModes[] =
    108 	{
    109 		{ "execute",		RUNMODE_EXECUTE				},
    110 		{ "xml-caselist",	RUNMODE_DUMP_XML_CASELIST	},
    111 		{ "txt-caselist",	RUNMODE_DUMP_TEXT_CASELIST	}
    112 	};
    113 	static const NamedValue<WindowVisibility> s_visibilites[] =
    114 	{
    115 		{ "windowed",		WINDOWVISIBILITY_WINDOWED	},
    116 		{ "fullscreen",		WINDOWVISIBILITY_FULLSCREEN	},
    117 		{ "hidden",			WINDOWVISIBILITY_HIDDEN		}
    118 	};
    119 	static const NamedValue<tcu::SurfaceType> s_surfaceTypes[] =
    120 	{
    121 		{ "window",			SURFACETYPE_WINDOW				},
    122 		{ "pixmap",			SURFACETYPE_OFFSCREEN_NATIVE	},
    123 		{ "pbuffer",		SURFACETYPE_OFFSCREEN_GENERIC	},
    124 		{ "fbo",			SURFACETYPE_FBO					}
    125 	};
    126 	static const NamedValue<tcu::ScreenRotation> s_screenRotations[] =
    127 	{
    128 		{ "0",				SCREENROTATION_0			},
    129 		{ "90",				SCREENROTATION_90			},
    130 		{ "180",			SCREENROTATION_180			},
    131 		{ "270",			SCREENROTATION_270			}
    132 	};
    133 
    134 	parser
    135 		<< Option<CasePath>				("n",		"deqp-case",					"Test case(s) to run, supports wildcards (e.g. dEQP-GLES2.info.*)")
    136 		<< Option<CaseList>				(DE_NULL,	"deqp-caselist",				"Case list to run in trie format (e.g. {dEQP-GLES2{info{version,renderer}}})")
    137 		<< Option<CaseListFile>			(DE_NULL,	"deqp-caselist-file",			"Read case list (in trie format) from given file")
    138 		<< Option<StdinCaseList>		(DE_NULL,	"deqp-stdin-caselist",			"Read case list (in trie format) from stdin")
    139 		<< Option<LogFilename>			(DE_NULL,	"deqp-log-filename",			"Write test results to given file",					"TestResults.qpa")
    140 		<< Option<RunMode>				(DE_NULL,	"deqp-runmode",					"Execute tests, or write list of test cases into a file",
    141 																					s_runModes, "execute")
    142 		<< Option<WatchDog>				(DE_NULL,	"deqp-watchdog",				"Enable test watchdog",								s_enableNames,		"disable")
    143 		<< Option<CrashHandler>			(DE_NULL,	"deqp-crashhandler",			"Enable crash handling",							s_enableNames,		"disable")
    144 		<< Option<BaseSeed>				(DE_NULL,	"deqp-base-seed",				"Base seed for test cases that use randomization")
    145 		<< Option<TestIterationCount>	(DE_NULL,	"deqp-test-iteration-count",	"Iteration count for cases that support variable number of iterations")
    146 		<< Option<Visibility>			(DE_NULL,	"deqp-visibility",				"Default test window visibility",					s_visibilites,		"windowed")
    147 		<< Option<SurfaceWidth>			(DE_NULL,	"deqp-surface-width",			"Use given surface width if possible",	"-1")
    148 		<< Option<SurfaceHeight>		(DE_NULL,	"deqp-surface-height",			"Use given surface height if possible",	"-1")
    149 		<< Option<SurfaceType>			(DE_NULL,	"deqp-surface-type",			"Use given surface type",							s_surfaceTypes,		"window")
    150 		<< Option<ScreenRotation>		(DE_NULL,	"deqp-screen-rotation",			"Screen rotation for platforms that support it",	s_screenRotations,	"0")
    151 		<< Option<GLContextType>		(DE_NULL,	"deqp-gl-context-type",			"OpenGL context type for platforms that support multiple")
    152 		<< Option<GLConfigID>			(DE_NULL,	"deqp-gl-config-id",			"OpenGL (ES) render config ID (EGL config id on EGL platforms)",	"-1")
    153 		<< Option<GLConfigName>			(DE_NULL,	"deqp-gl-config-name",			"Symbolic OpenGL (ES) render config name")
    154 		<< Option<GLContextFlags>		(DE_NULL,	"deqp-gl-context-flags",		"OpenGL context flags (comma-separated, supports debug and robust)")
    155 		<< Option<CLPlatformID>			(DE_NULL,	"deqp-cl-platform-id",			"Execute tests on given OpenCL platform (IDs start from 1)",		"1")
    156 		<< Option<CLDeviceIDs>			(DE_NULL,	"deqp-cl-device-ids",			"Execute tests on given CL devices (comma-separated, IDs start from 1)",	parseIntList)
    157 		<< Option<CLBuildOptions>		(DE_NULL,	"deqp-cl-build-options",		"Extra build options for OpenCL compiler")
    158 		<< Option<EGLDisplayType>		(DE_NULL,	"deqp-egl-display-type",		"EGL native display type")
    159 		<< Option<EGLWindowType>		(DE_NULL,	"deqp-egl-window-type",			"EGL native window type")
    160 		<< Option<EGLPixmapType>		(DE_NULL,	"deqp-egl-pixmap-type",			"EGL native pixmap type")
    161 		<< Option<LogImages>			(DE_NULL,	"deqp-log-images",				"Enable or disable logging of result images",		s_enableNames,		"enable")
    162 		<< Option<TestOOM>				(DE_NULL,	"deqp-test-oom",				"Run tests that exhaust memory on purpose",			s_enableNames,		TEST_OOM_DEFAULT);
    163 }
    164 
    165 void registerLegacyOptions (de::cmdline::Parser& parser)
    166 {
    167 	using de::cmdline::Option;
    168 
    169 	parser
    170 		<< Option<GLConfigID>			(DE_NULL,	"deqp-egl-config-id",			"Legacy name for --deqp-gl-config-id",	"-1")
    171 		<< Option<GLConfigName>			(DE_NULL,	"deqp-egl-config-name",			"Legacy name for --deqp-gl-config-name");
    172 }
    173 
    174 } // opt
    175 
    176 // \todo [2014-02-13 pyry] This could be useful elsewhere as well.
    177 class DebugOutStreambuf : public std::streambuf
    178 {
    179 public:
    180 						DebugOutStreambuf	(void);
    181 						~DebugOutStreambuf	(void);
    182 
    183 protected:
    184 	std::streamsize		xsputn				(const char* s, std::streamsize count);
    185 	int					overflow			(int ch = -1);
    186 
    187 private:
    188 	void				flushLine			(void);
    189 
    190 	std::ostringstream	m_curLine;
    191 };
    192 
    193 DebugOutStreambuf::DebugOutStreambuf (void)
    194 {
    195 }
    196 
    197 DebugOutStreambuf::~DebugOutStreambuf (void)
    198 {
    199 	if (m_curLine.tellp() != std::streampos(0))
    200 		flushLine();
    201 }
    202 
    203 std::streamsize DebugOutStreambuf::xsputn (const char* s, std::streamsize count)
    204 {
    205 	for (std::streamsize pos = 0; pos < count; pos++)
    206 	{
    207 		m_curLine.put(s[pos]);
    208 
    209 		if (s[pos] == '\n')
    210 			flushLine();
    211 	}
    212 
    213 	return count;
    214 }
    215 
    216 int DebugOutStreambuf::overflow (int ch)
    217 {
    218 	if (ch == -1)
    219 		return -1;
    220 	else
    221 	{
    222 		DE_ASSERT((ch & 0xff) == ch);
    223 		const char chVal = (char)(deUint8)(ch & 0xff);
    224 		return xsputn(&chVal, 1) == 1 ? ch : -1;
    225 	}
    226 }
    227 
    228 void DebugOutStreambuf::flushLine (void)
    229 {
    230 	qpPrint(m_curLine.str().c_str());
    231 	m_curLine.str("");
    232 }
    233 
    234 class CaseTreeNode
    235 {
    236 public:
    237 										CaseTreeNode		(const std::string& name) : m_name(name) {}
    238 										~CaseTreeNode		(void);
    239 
    240 	void								addChild			(CaseTreeNode* child) { m_children.push_back(child); }
    241 
    242 	const std::string&					getName				(void) const { return m_name;		}
    243 	const std::vector<CaseTreeNode*>&	getChildren			(void) const { return m_children;	}
    244 
    245 private:
    246 										CaseTreeNode		(const CaseTreeNode&);
    247 	CaseTreeNode&						operator=			(const CaseTreeNode&);
    248 
    249 	std::string							m_name;
    250 	std::vector<CaseTreeNode*>			m_children;
    251 };
    252 
    253 CaseTreeNode::~CaseTreeNode (void)
    254 {
    255 	for (vector<CaseTreeNode*>::const_iterator i = m_children.begin(); i != m_children.end(); ++i)
    256 		delete *i;
    257 }
    258 
    259 static CaseTreeNode* parseCaseTree (std::istream& in)
    260 {
    261 	vector<CaseTreeNode*>	nodeStack;
    262 	string					curName;
    263 
    264 	if (in.get() != '{')
    265 		throw std::invalid_argument("Malformed case tree");
    266 
    267 	nodeStack.reserve(1);
    268 	nodeStack.push_back(new CaseTreeNode(""));
    269 
    270 	try
    271 	{
    272 		for (;;)
    273 		{
    274 			const int	curChr	= in.get();
    275 
    276 			if (curChr == std::char_traits<char>::eof() || curChr == 0)
    277 				break;
    278 
    279 			if (nodeStack.empty())
    280 				throw std::invalid_argument("Trailing characters at end of case tree");
    281 
    282 			if (!curName.empty() && (curChr == '{' || curChr == ',' || curChr == '}'))
    283 			{
    284 				// Create child and push to stack.
    285 				nodeStack.reserve(nodeStack.size()+1);
    286 				nodeStack.push_back(new CaseTreeNode(curName));
    287 
    288 				curName.clear();
    289 			}
    290 
    291 			if (curChr == ',' || curChr == '}')
    292 			{
    293 				// Attach to parent
    294 				if (nodeStack.size() < 2)
    295 					throw std::invalid_argument("Malformed case tree");
    296 
    297 				(*(nodeStack.end()-2))->addChild(nodeStack.back());
    298 				nodeStack.pop_back();
    299 			}
    300 			else if (curChr != '{')
    301 				curName += (char)curChr;
    302 		}
    303 
    304 		if (nodeStack.size() != 1 || nodeStack[0]->getName() != "")
    305 			throw std::invalid_argument("Unterminated case tree");
    306 	}
    307 	catch (...)
    308 	{
    309 		// Nodes in stack are not attached to any parents and must be deleted individually.
    310 		for (vector<CaseTreeNode*>::const_iterator i = nodeStack.begin(); i != nodeStack.end(); ++i)
    311 			delete *i;
    312 
    313 		throw;
    314 	}
    315 
    316 	return nodeStack[0];
    317 }
    318 
    319 class CasePaths
    320 {
    321 public:
    322 							CasePaths	(const string& pathList);
    323 	bool					matches		(const string& caseName, bool allowPrefix=false) const;
    324 
    325 private:
    326 	const vector<string>	m_casePatterns;
    327 };
    328 
    329 CasePaths::CasePaths (const string& pathList)
    330 	: m_casePatterns(de::splitString(pathList, ','))
    331 {
    332 }
    333 
    334 // Match a single path component against a pattern component that may contain *-wildcards.
    335 static bool matchWildcards(string::const_iterator	patternStart,
    336 						   string::const_iterator	patternEnd,
    337 						   string::const_iterator	pathStart,
    338 						   string::const_iterator	pathEnd,
    339 						   bool						allowPrefix)
    340 {
    341 	string::const_iterator	pattern	= patternStart;
    342 	string::const_iterator	path	= pathStart;
    343 
    344 	while (pattern != patternEnd && path != pathEnd && *pattern == *path)
    345 	{
    346 		++pattern;
    347 		++path;
    348 	}
    349 
    350 	if (pattern == patternEnd)
    351 		return (path == pathEnd);
    352 	else if (*pattern == '*')
    353 	{
    354 		for (; path != pathEnd; ++path)
    355 		{
    356 			if (matchWildcards(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
    357 				return true;
    358 		}
    359 
    360 		if (matchWildcards(pattern + 1, patternEnd, pathEnd, pathEnd, allowPrefix))
    361 			return true;
    362 	}
    363 	else if (path == pathEnd && allowPrefix)
    364 		return true;
    365 
    366 	return false;
    367 }
    368 
    369 #if defined(TCU_HIERARCHICAL_CASEPATHS)
    370 // Match a list of pattern components to a list of path components. A pattern
    371 // component may contain *-wildcards. A pattern component "**" matches zero or
    372 // more whole path components.
    373 static bool patternMatches(vector<string>::const_iterator	patternStart,
    374 						   vector<string>::const_iterator	patternEnd,
    375 						   vector<string>::const_iterator	pathStart,
    376 						   vector<string>::const_iterator	pathEnd,
    377 						   bool								allowPrefix)
    378 {
    379 	vector<string>::const_iterator	pattern	= patternStart;
    380 	vector<string>::const_iterator	path	= pathStart;
    381 
    382 	while (pattern != patternEnd && path != pathEnd && *pattern != "**" &&
    383 		   (*pattern == *path || matchWildcards(pattern->begin(), pattern->end(),
    384 												path->begin(), path->end(), false)))
    385 	{
    386 		++pattern;
    387 		++path;
    388 	}
    389 
    390 	if (path == pathEnd && (allowPrefix || pattern == patternEnd))
    391 		return true;
    392 	else if (pattern != patternEnd && *pattern == "**")
    393 	{
    394 		for (; path != pathEnd; ++path)
    395 			if (patternMatches(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
    396 				return true;
    397 		if (patternMatches(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
    398 			return true;
    399 	}
    400 
    401 	return false;
    402 }
    403 #endif
    404 
    405 bool CasePaths::matches (const string& caseName, bool allowPrefix) const
    406 {
    407 	const vector<string> components = de::splitString(caseName, '.');
    408 
    409 	for (size_t ndx = 0; ndx < m_casePatterns.size(); ++ndx)
    410 	{
    411 #if defined(TCU_HIERARCHICAL_CASEPATHS)
    412 		const vector<string> patternComponents = de::splitString(m_casePatterns[ndx], '.');
    413 
    414 		if (patternMatches(patternComponents.begin(), patternComponents.end(),
    415 						   components.begin(), components.end(), allowPrefix))
    416 			return true;
    417 #else
    418 		if (matchWildcards(m_casePatterns[ndx].begin(), m_casePatterns[ndx].end(),
    419 						   caseName.begin(), caseName.end(), allowPrefix))
    420 			return true;
    421 #endif
    422 	}
    423 
    424 	return false;
    425 }
    426 
    427 /*--------------------------------------------------------------------*//*!
    428  * \brief Construct command line
    429  * \note CommandLine is not fully initialized until parse() has been called.
    430  *//*--------------------------------------------------------------------*/
    431 CommandLine::CommandLine (void)
    432 	: m_logFlags	(0)
    433 	, m_caseTree	(DE_NULL)
    434 {
    435 }
    436 
    437 /*--------------------------------------------------------------------*//*!
    438  * \brief Construct command line from standard argc, argv pair.
    439  *
    440  * Calls parse() with given arguments
    441  * \param argc Number of arguments
    442  * \param argv Command line arguments
    443  *//*--------------------------------------------------------------------*/
    444 CommandLine::CommandLine (int argc, const char* const* argv)
    445 	: m_logFlags	(0)
    446 	, m_caseTree	(DE_NULL)
    447 {
    448 	if (!parse(argc, argv))
    449 		throw Exception("Failed to parse command line");
    450 }
    451 
    452 /*--------------------------------------------------------------------*//*!
    453  * \brief Construct command line from string.
    454  *
    455  * Calls parse() with given argument.
    456  * \param cmdLine Full command line string.
    457  *//*--------------------------------------------------------------------*/
    458 CommandLine::CommandLine (const std::string& cmdLine)
    459 	: m_logFlags	(0)
    460 	, m_caseTree	(DE_NULL)
    461 {
    462 	if (!parse(cmdLine))
    463 		throw Exception("Failed to parse command line");
    464 }
    465 
    466 CommandLine::~CommandLine (void)
    467 {
    468 	delete m_caseTree;
    469 }
    470 
    471 void CommandLine::clear (void)
    472 {
    473 	m_cmdLine.clear();
    474 	m_logFlags = 0;
    475 
    476 	delete m_caseTree;
    477 	m_caseTree = DE_NULL;
    478 }
    479 
    480 /*--------------------------------------------------------------------*//*!
    481  * \brief Parse command line from standard argc, argv pair.
    482  * \note parse() must be called exactly once.
    483  * \param argc Number of arguments
    484  * \param argv Command line arguments
    485  *//*--------------------------------------------------------------------*/
    486 bool CommandLine::parse (int argc, const char* const* argv)
    487 {
    488 	DebugOutStreambuf	sbuf;
    489 	std::ostream		debugOut	(&sbuf);
    490 	de::cmdline::Parser	parser;
    491 
    492 	opt::registerOptions(parser);
    493 	opt::registerLegacyOptions(parser);
    494 
    495 	clear();
    496 
    497 	if (!parser.parse(argc-1, argv+1, &m_cmdLine, std::cerr))
    498 	{
    499 		debugOut << "\n" << de::FilePath(argv[0]).getBaseName() << " [options]\n\n";
    500 		parser.help(debugOut);
    501 
    502 		clear();
    503 		return false;
    504 	}
    505 
    506 	if (!m_cmdLine.getOption<opt::LogImages>())
    507 		m_logFlags |= QP_TEST_LOG_EXCLUDE_IMAGES;
    508 
    509 	if ((m_cmdLine.getOption<opt::CasePath>().empty()?0:1) +
    510 		(m_cmdLine.getOption<opt::CaseList>().empty()?0:1) +
    511 		(m_cmdLine.getOption<opt::CaseListFile>().empty()?0:1) +
    512 		(m_cmdLine.getOption<opt::StdinCaseList>()?1:0) > 1)
    513 	{
    514 		debugOut << "ERROR: multiple test case list options given!\n" << std::endl;
    515 		clear();
    516 		return false;
    517 	}
    518 
    519 	try
    520 	{
    521 		if (!m_cmdLine.getOption<opt::CaseList>().empty())
    522 		{
    523 			std::istringstream str(m_cmdLine.getOption<opt::CaseList>());
    524 
    525 			m_caseTree = parseCaseTree(str);
    526 		}
    527 		else if (!m_cmdLine.getOption<opt::CaseListFile>().empty())
    528 		{
    529 			std::ifstream in(m_cmdLine.getOption<opt::CaseListFile>().c_str(), std::ios_base::binary);
    530 
    531 			if (!in.is_open() || !in.good())
    532 				throw Exception("Failed to open case list file '" + m_cmdLine.getOption<opt::CaseListFile>() + "'");
    533 
    534 			m_caseTree = parseCaseTree(in);
    535 		}
    536 		else if (m_cmdLine.getOption<opt::StdinCaseList>())
    537 		{
    538 			m_caseTree = parseCaseTree(std::cin);
    539 		}
    540 		else if (!m_cmdLine.getOption<opt::CasePath>().empty())
    541 			m_casePaths = de::MovePtr<const CasePaths>(new CasePaths(m_cmdLine.getOption<opt::CasePath>()));
    542 	}
    543 	catch (const std::exception& e)
    544 	{
    545 		debugOut << "ERROR: Failed to parse test case list: " << e.what() << "\n";
    546 		clear();
    547 		return false;
    548 	}
    549 
    550 	return true;
    551 }
    552 
    553 /*--------------------------------------------------------------------*//*!
    554  * \brief Parse command line from string.
    555  * \note parse() must be called exactly once.
    556  * \param cmdLine Full command line string.
    557  *//*--------------------------------------------------------------------*/
    558 bool CommandLine::parse (const std::string& cmdLine)
    559 {
    560 	deCommandLine* parsedCmdLine = deCommandLine_parse(cmdLine.c_str());
    561 	if (!parsedCmdLine)
    562 		throw std::bad_alloc();
    563 
    564 	bool isOk = false;
    565 	try
    566 	{
    567 		isOk = parse(parsedCmdLine->numArgs, parsedCmdLine->args);
    568 	}
    569 	catch (...)
    570 	{
    571 		deCommandLine_destroy(parsedCmdLine);
    572 		throw;
    573 	}
    574 
    575 	deCommandLine_destroy(parsedCmdLine);
    576 	return isOk;
    577 }
    578 
    579 const char*				CommandLine::getLogFileName				(void) const	{ return m_cmdLine.getOption<opt::LogFilename>().c_str();		}
    580 deUint32				CommandLine::getLogFlags				(void) const	{ return m_logFlags;											}
    581 RunMode					CommandLine::getRunMode					(void) const	{ return m_cmdLine.getOption<opt::RunMode>();					}
    582 WindowVisibility		CommandLine::getVisibility				(void) const	{ return m_cmdLine.getOption<opt::Visibility>();				}
    583 bool					CommandLine::isWatchDogEnabled			(void) const	{ return m_cmdLine.getOption<opt::WatchDog>();					}
    584 bool					CommandLine::isCrashHandlingEnabled		(void) const	{ return m_cmdLine.getOption<opt::CrashHandler>();				}
    585 int						CommandLine::getBaseSeed				(void) const	{ return m_cmdLine.getOption<opt::BaseSeed>();					}
    586 int						CommandLine::getTestIterationCount		(void) const	{ return m_cmdLine.getOption<opt::TestIterationCount>();		}
    587 int						CommandLine::getSurfaceWidth			(void) const	{ return m_cmdLine.getOption<opt::SurfaceWidth>();				}
    588 int						CommandLine::getSurfaceHeight			(void) const	{ return m_cmdLine.getOption<opt::SurfaceHeight>();				}
    589 SurfaceType				CommandLine::getSurfaceType				(void) const	{ return m_cmdLine.getOption<opt::SurfaceType>();				}
    590 ScreenRotation			CommandLine::getScreenRotation			(void) const	{ return m_cmdLine.getOption<opt::ScreenRotation>();			}
    591 int						CommandLine::getGLConfigId				(void) const	{ return m_cmdLine.getOption<opt::GLConfigID>();				}
    592 int						CommandLine::getCLPlatformId			(void) const	{ return m_cmdLine.getOption<opt::CLPlatformID>();				}
    593 const std::vector<int>&	CommandLine::getCLDeviceIds				(void) const	{ return m_cmdLine.getOption<opt::CLDeviceIDs>();				}
    594 const char*				CommandLine::getEGLDisplayType			(void) const	{ return m_cmdLine.getOption<opt::EGLDisplayType>().c_str();	}
    595 const char*				CommandLine::getEGLWindowType			(void) const	{ return m_cmdLine.getOption<opt::EGLWindowType>().c_str();		}
    596 const char*				CommandLine::getEGLPixmapType			(void) const	{ return m_cmdLine.getOption<opt::EGLPixmapType>().c_str();		}
    597 bool					CommandLine::isOutOfMemoryTestEnabled	(void) const	{ return m_cmdLine.getOption<opt::TestOOM>();					}
    598 
    599 const char* CommandLine::getGLContextType (void) const
    600 {
    601 	if (!m_cmdLine.getOption<opt::GLContextType>().empty())
    602 		return m_cmdLine.getOption<opt::GLContextType>().c_str();
    603 	else
    604 		return DE_NULL;
    605 }
    606 const char* CommandLine::getGLConfigName (void) const
    607 {
    608 	if (!m_cmdLine.getOption<opt::GLConfigName>().empty())
    609 		return m_cmdLine.getOption<opt::GLConfigName>().c_str();
    610 	else
    611 		return DE_NULL;
    612 }
    613 
    614 const char* CommandLine::getGLContextFlags (void) const
    615 {
    616 	if (!m_cmdLine.getOption<opt::GLContextFlags>().empty())
    617 		return m_cmdLine.getOption<opt::GLContextFlags>().c_str();
    618 	else
    619 		return DE_NULL;
    620 }
    621 
    622 const char* CommandLine::getCLBuildOptions (void) const
    623 {
    624 	if (!m_cmdLine.getOption<opt::CLBuildOptions>().empty())
    625 		return m_cmdLine.getOption<opt::CLBuildOptions>().c_str();
    626 	else
    627 		return DE_NULL;
    628 }
    629 
    630 static bool checkTestGroupName (const CaseTreeNode* node, const char* groupName)
    631 {
    632 	for (vector<CaseTreeNode*>::const_iterator childIter = node->getChildren().begin(); childIter != node->getChildren().end(); ++childIter)
    633 	{
    634 		const CaseTreeNode* const child = *childIter;
    635 
    636 		if (deStringBeginsWith(groupName, child->getName().c_str()))
    637 		{
    638 			const int prefixLen = (int)child->getName().length();
    639 
    640 			if (groupName[prefixLen] == 0)
    641 				return true;
    642 			else if (groupName[prefixLen] == '.')
    643 				return checkTestGroupName(child, groupName + prefixLen + 1);
    644 		}
    645 	}
    646 
    647 	return false;
    648 }
    649 
    650 static bool checkTestCaseName (const CaseTreeNode* node, const char* caseName)
    651 {
    652 	for (vector<CaseTreeNode*>::const_iterator childIter = node->getChildren().begin(); childIter != node->getChildren().end(); ++childIter)
    653 	{
    654 		const CaseTreeNode* const child = *childIter;
    655 
    656 		if (deStringBeginsWith(caseName, child->getName().c_str()))
    657 		{
    658 			const int prefixLen = (int)child->getName().length();
    659 
    660 			if (caseName[prefixLen] == 0 && child->getChildren().empty())
    661 				return true;
    662 			else if (caseName[prefixLen] == '.')
    663 				return checkTestCaseName(child, caseName + prefixLen + 1);
    664 		}
    665 	}
    666 
    667 	return false;
    668 }
    669 
    670 bool CommandLine::checkTestGroupName (const char* groupName) const
    671 {
    672 	if (m_casePaths)
    673 		return m_casePaths->matches(groupName, true);
    674 	else if (m_caseTree)
    675 		return groupName[0] == 0 || tcu::checkTestGroupName(m_caseTree, groupName);
    676 	else
    677 		return true;
    678 }
    679 
    680 bool CommandLine::checkTestCaseName (const char* caseName) const
    681 {
    682 	if (m_casePaths)
    683 		return m_casePaths->matches(caseName, false);
    684 	else if (m_caseTree)
    685 		return tcu::checkTestCaseName(m_caseTree, caseName);
    686 	else
    687 		return true;
    688 }
    689 
    690 } // tcu
    691