• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
parseIntList(const char * src,std::vector<int> * dst)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 
registerOptions(de::cmdline::Parser & parser)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 
registerLegacyOptions(de::cmdline::Parser & parser)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 
DebugOutStreambuf(void)193 DebugOutStreambuf::DebugOutStreambuf (void)
194 {
195 }
196 
~DebugOutStreambuf(void)197 DebugOutStreambuf::~DebugOutStreambuf (void)
198 {
199 	if (m_curLine.tellp() != std::streampos(0))
200 		flushLine();
201 }
202 
xsputn(const char * s,std::streamsize count)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 
overflow(int ch)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 
flushLine(void)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:
CaseTreeNode(const std::string & name)237 										CaseTreeNode		(const std::string& name) : m_name(name) {}
238 										~CaseTreeNode		(void);
239 
addChild(CaseTreeNode * child)240 	void								addChild			(CaseTreeNode* child) { m_children.push_back(child); }
241 
getName(void) const242 	const std::string&					getName				(void) const { return m_name;		}
getChildren(void) const243 	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 
~CaseTreeNode(void)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 
parseCaseTree(std::istream & in)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 
CasePaths(const string & pathList)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.
matchWildcards(string::const_iterator patternStart,string::const_iterator patternEnd,string::const_iterator pathStart,string::const_iterator pathEnd,bool allowPrefix)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.
patternMatches(vector<string>::const_iterator patternStart,vector<string>::const_iterator patternEnd,vector<string>::const_iterator pathStart,vector<string>::const_iterator pathEnd,bool allowPrefix)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 
matches(const string & caseName,bool allowPrefix) const405 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  *//*--------------------------------------------------------------------*/
CommandLine(void)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  *//*--------------------------------------------------------------------*/
CommandLine(int argc,const char * const * argv)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  *//*--------------------------------------------------------------------*/
CommandLine(const std::string & cmdLine)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 
~CommandLine(void)466 CommandLine::~CommandLine (void)
467 {
468 	delete m_caseTree;
469 }
470 
clear(void)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  *//*--------------------------------------------------------------------*/
parse(int argc,const char * const * argv)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  *//*--------------------------------------------------------------------*/
parse(const std::string & cmdLine)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 
getLogFileName(void) const579 const char*				CommandLine::getLogFileName				(void) const	{ return m_cmdLine.getOption<opt::LogFilename>().c_str();		}
getLogFlags(void) const580 deUint32				CommandLine::getLogFlags				(void) const	{ return m_logFlags;											}
getRunMode(void) const581 RunMode					CommandLine::getRunMode					(void) const	{ return m_cmdLine.getOption<opt::RunMode>();					}
getVisibility(void) const582 WindowVisibility		CommandLine::getVisibility				(void) const	{ return m_cmdLine.getOption<opt::Visibility>();				}
isWatchDogEnabled(void) const583 bool					CommandLine::isWatchDogEnabled			(void) const	{ return m_cmdLine.getOption<opt::WatchDog>();					}
isCrashHandlingEnabled(void) const584 bool					CommandLine::isCrashHandlingEnabled		(void) const	{ return m_cmdLine.getOption<opt::CrashHandler>();				}
getBaseSeed(void) const585 int						CommandLine::getBaseSeed				(void) const	{ return m_cmdLine.getOption<opt::BaseSeed>();					}
getTestIterationCount(void) const586 int						CommandLine::getTestIterationCount		(void) const	{ return m_cmdLine.getOption<opt::TestIterationCount>();		}
getSurfaceWidth(void) const587 int						CommandLine::getSurfaceWidth			(void) const	{ return m_cmdLine.getOption<opt::SurfaceWidth>();				}
getSurfaceHeight(void) const588 int						CommandLine::getSurfaceHeight			(void) const	{ return m_cmdLine.getOption<opt::SurfaceHeight>();				}
getSurfaceType(void) const589 SurfaceType				CommandLine::getSurfaceType				(void) const	{ return m_cmdLine.getOption<opt::SurfaceType>();				}
getScreenRotation(void) const590 ScreenRotation			CommandLine::getScreenRotation			(void) const	{ return m_cmdLine.getOption<opt::ScreenRotation>();			}
getGLConfigId(void) const591 int						CommandLine::getGLConfigId				(void) const	{ return m_cmdLine.getOption<opt::GLConfigID>();				}
getCLPlatformId(void) const592 int						CommandLine::getCLPlatformId			(void) const	{ return m_cmdLine.getOption<opt::CLPlatformID>();				}
getCLDeviceIds(void) const593 const std::vector<int>&	CommandLine::getCLDeviceIds				(void) const	{ return m_cmdLine.getOption<opt::CLDeviceIDs>();				}
getEGLDisplayType(void) const594 const char*				CommandLine::getEGLDisplayType			(void) const	{ return m_cmdLine.getOption<opt::EGLDisplayType>().c_str();	}
getEGLWindowType(void) const595 const char*				CommandLine::getEGLWindowType			(void) const	{ return m_cmdLine.getOption<opt::EGLWindowType>().c_str();		}
getEGLPixmapType(void) const596 const char*				CommandLine::getEGLPixmapType			(void) const	{ return m_cmdLine.getOption<opt::EGLPixmapType>().c_str();		}
isOutOfMemoryTestEnabled(void) const597 bool					CommandLine::isOutOfMemoryTestEnabled	(void) const	{ return m_cmdLine.getOption<opt::TestOOM>();					}
598 
getGLContextType(void) const599 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 }
getGLConfigName(void) const606 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 
getGLContextFlags(void) const614 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 
getCLBuildOptions(void) const622 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 
checkTestGroupName(const CaseTreeNode * node,const char * groupName)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 
checkTestCaseName(const CaseTreeNode * node,const char * caseName)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 
checkTestGroupName(const char * groupName) const670 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 
checkTestCaseName(const char * caseName) const680 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