0031189: Draw Harness, ViewerTest - send messages to Message::DefaultMessenger()
[occt.git] / src / ViewerTest / ViewerTest_CmdParser.cxx
... / ...
CommitLineData
1// Created on: 2015-03-15
2// Created by: Danila ULYANOV
3// Copyright (c) 2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16#include <ViewerTest_CmdParser.hxx>
17
18#include <Draw.hxx>
19#include <Message.hxx>
20#include <ViewerTest.hxx>
21
22#include <algorithm>
23#include <iostream>
24
25namespace
26{
27
28 //! Converts the given string to lowercase
29 //! @param theString the string to be converted
30 //! @return a converted string (a string in lowercase)
31 static std::string toLowerCase (std::string theString)
32 {
33 std::transform (theString.begin(), theString.end(), theString.begin(), ::LowerCase);
34 return theString;
35 }
36
37 //! Converts the vector of std::strings to a vector of pointers to its data
38 //! @param theStringList the vector of strings to be converted
39 //! @return a vector of pointers to the data of given strings
40 static std::vector<const char*> convertToRawStringList (const std::vector<std::string>& theStringList)
41 {
42 const std::size_t aListSize = theStringList.size();
43 std::vector<const char*> aRawStringList (aListSize);
44 for (std::size_t anIndex = 0; anIndex < aListSize; ++anIndex)
45 {
46 aRawStringList[anIndex] = theStringList[anIndex].c_str();
47 }
48 return aRawStringList;
49 }
50
51} // namespace
52
53const std::size_t ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY = (std::numeric_limits<std::size_t>::max)();
54
55const std::size_t ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY = 0;
56
57//===============================================================================================
58// function : ViewerTest_CmdParser
59// purpose :
60//===============================================================================================
61ViewerTest_CmdParser::ViewerTest_CmdParser (const std::string& theDescription) : myDescription (theDescription)
62{
63 AddOption ("help|h", "Prints a short description of the command and its options.");
64}
65
66//===============================================================================================
67// function : AddOption
68// purpose :
69//===============================================================================================
70ViewerTest_CommandOptionKey ViewerTest_CmdParser::AddOption (const std::string& theOptionNames,
71 const std::string& theOptionDescription)
72{
73 CommandOption aNewOption;
74
75 // extract option names
76 std::vector<std::string> aNames;
77 std::stringstream aStream (theOptionNames);
78 std::string anItem;
79 while (std::getline (aStream, anItem, '|'))
80 {
81 if (!anItem.empty())
82 {
83 aNames.push_back (anItem);
84 }
85 }
86
87 aNewOption.Name = aNames.front();
88 if (aNames.size() > 1)
89 {
90 const std::size_t aNumberOfAliases = aNames.size() - 1;
91
92 aNewOption.Aliases.reserve (aNumberOfAliases);
93 std::copy (aNames.begin() + 1, aNames.end(), std::back_inserter (aNewOption.Aliases));
94 }
95 aNewOption.Description = theOptionDescription;
96
97 const ViewerTest_CommandOptionKey aNewOptionKey = myOptionStorage.size();
98
99 myOptionStorage.push_back (aNewOption);
100
101 std::vector<std::string>::const_iterator anIt = aNames.begin();
102 for (; anIt != aNames.end(); ++anIt)
103 {
104 const std::string aNameInLowerCase = toLowerCase (*anIt);
105
106 myOptionMap[aNameInLowerCase] = aNewOptionKey;
107 }
108
109 return aNewOptionKey;
110}
111
112//===============================================================================================
113// function : PrintHelp
114// purpose :
115//===============================================================================================
116void ViewerTest_CmdParser::PrintHelp() const
117{
118 std::cout << myDescription << std::endl;
119 std::vector<CommandOption>::const_iterator anIt = myOptionStorage.begin();
120 for (++anIt; anIt != myOptionStorage.end(); ++anIt)
121 {
122 const CommandOption& aCommandOption = *anIt;
123 std::cout << "\n\t-" << aCommandOption.Name;
124 const OptionAliases& anAliases = aCommandOption.Aliases;
125 if (!anAliases.empty())
126 {
127 std::cout << " (-" << anAliases.front();
128 for (OptionAliases::const_iterator anAliasIterator = anAliases.begin() + 1; anAliasIterator != anAliases.end();
129 ++anAliasIterator)
130 {
131 std::cout << ", -" << *anAliasIterator;
132 }
133 std::cout << ")";
134 }
135 std::cout << " : " << aCommandOption.Description;
136 }
137 std::cout << std::endl;
138}
139
140//===============================================================================================
141// function : Parse
142// purpose :
143//===============================================================================================
144void ViewerTest_CmdParser::Parse (const Standard_Integer theArgsNb, const char* const* const theArgVec)
145{
146 std::size_t aCurrentUsedOptionIndex = 0;
147 for (Standard_Integer anIter = 1; anIter < theArgsNb; ++anIter)
148 {
149 const char* const anArgument = theArgVec[anIter];
150 if (anArgument[0] == '-' && !std::isdigit (anArgument[1]))
151 {
152 const std::string anOptionName = toLowerCase (anArgument + 1);
153 OptionMap::iterator aMapIter = myOptionMap.find (anOptionName);
154 if (aMapIter != myOptionMap.end())
155 {
156 const ViewerTest_CommandOptionKey aCurrentUsedOptionKey = aMapIter->second;
157 aCurrentUsedOptionIndex = addUsedOption (aCurrentUsedOptionKey);
158 }
159 else
160 {
161 Message::SendFail() << "Error: unknown argument '" << anOptionName << "'";
162 return;
163 }
164 }
165 else
166 {
167 if (anIter == 1)
168 {
169 aCurrentUsedOptionIndex = addUsedOption (THE_UNNAMED_COMMAND_OPTION_KEY);
170 }
171 myOptionArgumentStorage[aCurrentUsedOptionIndex].push_back (anArgument);
172 }
173 }
174}
175
176//===============================================================================================
177// function : GetOptionNameByKey
178// purpose :
179//===============================================================================================
180std::string ViewerTest_CmdParser::GetOptionNameByKey (const ViewerTest_CommandOptionKey theOptionKey) const
181{
182 if (theOptionKey == THE_UNNAMED_COMMAND_OPTION_KEY)
183 {
184 return "Unnamed";
185 }
186 return myOptionStorage[theOptionKey].Name;
187}
188
189//===============================================================================================
190// function : GetUsedOptions
191// purpose :
192//===============================================================================================
193ViewerTest_CommandOptionKeySet ViewerTest_CmdParser::GetUsedOptions() const
194{
195 ViewerTest_CommandOptionKeySet aUsedOptions;
196 for (UsedOptionMap::const_iterator aUsedOptionMapIterator = myUsedOptionMap.begin();
197 aUsedOptionMapIterator != myUsedOptionMap.end();
198 ++aUsedOptionMapIterator)
199 {
200 aUsedOptions.insert (aUsedOptionMapIterator->first);
201 }
202 return aUsedOptions;
203}
204
205//===============================================================================================
206// function : HasNoOption
207// purpose :
208//===============================================================================================
209bool ViewerTest_CmdParser::HasNoOption() const
210{
211 return myUsedOptionMap.empty();
212}
213
214//===============================================================================================
215// function : HasUnnamedOption
216// purpose :
217//===============================================================================================
218bool ViewerTest_CmdParser::HasUnnamedOption() const
219{
220 return myUsedOptionMap.find (THE_UNNAMED_COMMAND_OPTION_KEY) != myUsedOptionMap.end();
221}
222
223//===============================================================================================
224// function : HasNoUnnamedOption
225// purpose :
226//===============================================================================================
227bool ViewerTest_CmdParser::HasOnlyUnnamedOption() const
228{
229 return HasUnnamedOption() && (myUsedOptionMap.size() == 1);
230}
231
232//===============================================================================================
233// function : HasOption
234// purpose :
235//===============================================================================================
236bool ViewerTest_CmdParser::HasOption (const std::string& theOptionName,
237 const std::size_t theMandatoryArgsNb /* = 0 */,
238 const bool isFatal /* = false */) const
239{
240 ViewerTest_CommandOptionKey anOptionKey;
241 if (!findOptionKey (theOptionName, anOptionKey))
242 {
243 return false;
244 }
245 return HasOption (anOptionKey, theMandatoryArgsNb, isFatal);
246}
247
248//===============================================================================================
249// function : HasOption
250// purpose :
251//===============================================================================================
252bool ViewerTest_CmdParser::HasOption (const ViewerTest_CommandOptionKey theOptionKey,
253 const std::size_t theMandatoryArgsNb /* = 0 */,
254 const bool isFatal /* = false */) const
255{
256 std::size_t aUsedOptionIndex = 0;
257 if (!findUsedOptionIndex (theOptionKey, aUsedOptionIndex))
258 {
259 return false;
260 }
261 const OptionArguments& anOptionArguments = myOptionArgumentStorage[aUsedOptionIndex];
262 const bool aResult = (anOptionArguments.size() >= theMandatoryArgsNb);
263 if (isFatal && !aResult)
264 {
265 Message::SendFail() << "Error: wrong syntax at option '" << myOptionStorage[theOptionKey].Name << "'\n"
266 << "At least " << theMandatoryArgsNb << "expected, but only " << anOptionArguments.size()
267 << "provided.";
268 }
269 return aResult;
270}
271
272//===============================================================================================
273// function : GetNumberOfOptionArguments
274// purpose :
275//===============================================================================================
276Standard_Integer ViewerTest_CmdParser::GetNumberOfOptionArguments (const std::string& theOptionName) const
277{
278 ViewerTest_CommandOptionKey anOptionKey = THE_UNNAMED_COMMAND_OPTION_KEY;
279 if (!findOptionKey (theOptionName, anOptionKey))
280 {
281 return 0;
282 }
283 return GetNumberOfOptionArguments (anOptionKey);
284}
285
286//===============================================================================================
287// function : GetNumberOfOptionArguments
288// purpose :
289//===============================================================================================
290Standard_Integer ViewerTest_CmdParser::GetNumberOfOptionArguments (const ViewerTest_CommandOptionKey theOptionKey) const
291{
292 std::size_t aUsedOptionIndex = 0;
293 if (!findUsedOptionIndex (theOptionKey, aUsedOptionIndex))
294 {
295 return false;
296 }
297 return static_cast<Standard_Integer> (myOptionArgumentStorage[aUsedOptionIndex].size());
298}
299
300//===============================================================================================
301// function : Arg
302// purpose :
303//===============================================================================================
304bool ViewerTest_CmdParser::Arg (const std::string& theOptionName,
305 const Standard_Integer theArgumentIndex,
306 std::string& theOptionArgument) const
307{
308 Standard_ASSERT_RETURN (theArgumentIndex >= 0,
309 "'theArgumentIndex' must be greater than or equal to zero.",
310 false);
311 ViewerTest_CommandOptionKey anOptionKey = THE_UNNAMED_COMMAND_OPTION_KEY;
312 if (!theOptionName.empty() && !findOptionKey (theOptionName, anOptionKey))
313 {
314 return false;
315 }
316 return Arg (anOptionKey, theArgumentIndex, theOptionArgument);
317}
318
319//===============================================================================================
320// function : Arg
321// purpose :
322//===============================================================================================
323bool ViewerTest_CmdParser::Arg (const ViewerTest_CommandOptionKey theOptionKey,
324 const Standard_Integer theArgumentIndex,
325 std::string& theOptionArgument) const
326{
327 Standard_ASSERT_RETURN (theArgumentIndex >= 0,
328 "'theArgumentIndex' must be greater than or equal to zero.",
329 false);
330 std::size_t aUsedOptionIndex = 0;
331 if (!findUsedOptionIndex (theOptionKey, aUsedOptionIndex))
332 {
333 return false;
334 }
335 const OptionArguments& anOptionArguments = myOptionArgumentStorage[aUsedOptionIndex];
336 if (static_cast<std::size_t> (theArgumentIndex) >= anOptionArguments.size())
337 {
338 return false;
339 }
340 theOptionArgument = anOptionArguments[theArgumentIndex];
341 return true;
342}
343
344//===============================================================================================
345// function : Arg
346// purpose :
347//===============================================================================================
348std::string ViewerTest_CmdParser::Arg (const std::string& theOptionName, const Standard_Integer theArgumentIndex) const
349{
350 Standard_ASSERT_RETURN (theArgumentIndex >= 0,
351 "'theArgumentIndex' must be greater than or equal to zero.",
352 std::string());
353 std::string anOptionArgument;
354 if (!Arg (theOptionName, theArgumentIndex, anOptionArgument))
355 {
356 return std::string();
357 }
358 return anOptionArgument;
359}
360
361//===============================================================================================
362// function : Arg
363// purpose :
364//===============================================================================================
365std::string ViewerTest_CmdParser::Arg (const ViewerTest_CommandOptionKey theOptionKey,
366 const Standard_Integer theArgumentIndex) const
367{
368 std::string anOptionArgument;
369 if (!Arg (theOptionKey, theArgumentIndex, anOptionArgument))
370 {
371 return std::string();
372 }
373 return anOptionArgument;
374}
375
376//===============================================================================================
377// function : ArgVec3f
378// purpose :
379//===============================================================================================
380Graphic3d_Vec3 ViewerTest_CmdParser::ArgVec3f (const std::string& theOptionName,
381 Standard_Integer theArgumentIndex) const
382{
383 return Graphic3d_Vec3 (
384 static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str())),
385 static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, theArgumentIndex + 1).c_str())),
386 static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, theArgumentIndex + 2).c_str())));
387}
388
389//===============================================================================================
390// function : ArgVec3d
391// purpose :
392//===============================================================================================
393Graphic3d_Vec3d ViewerTest_CmdParser::ArgVec3d (const std::string& theOptionName,
394 Standard_Integer theArgumentIndex) const
395{
396 return Graphic3d_Vec3d (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()),
397 Draw::Atof (Arg (theOptionName, theArgumentIndex + 1).c_str()),
398 Draw::Atof (Arg (theOptionName, theArgumentIndex + 2).c_str()));
399}
400
401//===============================================================================================
402// function : ArgVec
403// purpose :
404//===============================================================================================
405gp_Vec ViewerTest_CmdParser::ArgVec (const std::string& theOptionName, Standard_Integer theArgumentIndex) const
406{
407 return gp_Vec (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()),
408 Draw::Atof (Arg (theOptionName, theArgumentIndex + 1).c_str()),
409 Draw::Atof (Arg (theOptionName, theArgumentIndex + 2).c_str()));
410}
411
412//===============================================================================================
413// function : ArgPnt
414// purpose :
415//===============================================================================================
416gp_Pnt ViewerTest_CmdParser::ArgPnt (const std::string& theOptionName, Standard_Integer theArgumentIndex) const
417{
418 return gp_Pnt (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()),
419 Draw::Atof (Arg (theOptionName, theArgumentIndex + 1).c_str()),
420 Draw::Atof (Arg (theOptionName, theArgumentIndex + 2).c_str()));
421}
422
423//===============================================================================================
424// function : ArgDouble
425// purpose :
426//===============================================================================================
427Standard_Real ViewerTest_CmdParser::ArgDouble (const std::string& theOptionName,
428 Standard_Integer theArgumentIndex) const
429{
430 return Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str());
431}
432
433//===============================================================================================
434// function : ArgFloat
435// purpose :
436//===============================================================================================
437Standard_ShortReal ViewerTest_CmdParser::ArgFloat (const std::string& theOptionName,
438 Standard_Integer theArgumentIndex) const
439{
440 return static_cast<Standard_ShortReal> (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()));
441}
442
443//===============================================================================================
444// function : ArgInt
445// purpose :
446//===============================================================================================
447Standard_Integer ViewerTest_CmdParser::ArgInt (const std::string& theOptionName,
448 const Standard_Integer theArgumentIndex) const
449{
450 return static_cast<Standard_Integer> (Draw::Atoi (Arg (theOptionName, theArgumentIndex).c_str()));
451}
452
453//===============================================================================================
454// function : ArgBool
455// purpose :
456//===============================================================================================
457bool ViewerTest_CmdParser::ArgBool (const std::string& theOptionName, const Standard_Integer theArgumentIndex) const
458{
459 return Draw::Atoi (Arg (theOptionName, theArgumentIndex).c_str()) != 0;
460}
461
462//===============================================================================================
463// function : ArgColor
464// purpose :
465//===============================================================================================
466template <typename TheColor>
467bool ViewerTest_CmdParser::ArgColor (const std::string& theOptionName,
468 Standard_Integer& theArgumentIndex,
469 TheColor& theColor) const
470{
471 ViewerTest_CommandOptionKey anOptionKey;
472 if (!findOptionKey (theOptionName, anOptionKey))
473 {
474 return false;
475 }
476 return ArgColor (anOptionKey, theArgumentIndex, theColor);
477}
478
479//! ViewerTest_CmdParser::ArgColor() explicit template instantiation definitions
480template bool ViewerTest_CmdParser::ArgColor (const std::string& theOptionName,
481 Standard_Integer& theArgumentIndex,
482 Quantity_Color& theColor) const;
483
484template bool ViewerTest_CmdParser::ArgColor (const std::string& theOptionName,
485 Standard_Integer& theArgumentIndex,
486 Quantity_ColorRGBA& theColor) const;
487
488//===============================================================================================
489// function : ArgColor
490// purpose :
491//===============================================================================================
492template <typename TheColor>
493bool ViewerTest_CmdParser::ArgColor (const ViewerTest_CommandOptionKey theOptionKey,
494 Standard_Integer& theArgumentIndex,
495 TheColor& theColor) const
496{
497 std::size_t aUsedOptionIndex = 0;
498 if (!findUsedOptionIndex (theOptionKey, aUsedOptionIndex))
499 {
500 return false;
501 }
502 const RawStringArguments aRawStringArguments = getRawStringArguments (aUsedOptionIndex);
503 const Standard_Integer aNumberOfArguments = static_cast<Standard_Integer> (aRawStringArguments.size());
504 Standard_ASSERT_RETURN (theArgumentIndex < aNumberOfArguments,
505 "'theArgumentIndex' must be less than the number of command-line arguments "
506 "passed with the option which access key is 'theOptionKey'.",
507 false);
508 const Standard_Integer aNumberOfAvailableArguments = aNumberOfArguments - theArgumentIndex;
509 TheColor aColor;
510 const Standard_Integer aNumberOfParsedArguments = ViewerTest::ParseColor (aNumberOfAvailableArguments,
511 &aRawStringArguments[theArgumentIndex],
512 aColor);
513 if (aNumberOfParsedArguments == 0)
514 {
515 return false;
516 }
517 theArgumentIndex += aNumberOfParsedArguments;
518 theColor = aColor;
519 return true;
520}
521
522//! ViewerTest_CmdParser::ArgColor() explicit template instantiation definitions
523template bool ViewerTest_CmdParser::ArgColor (ViewerTest_CommandOptionKey theOptionKey,
524 Standard_Integer& theArgumentIndex,
525 Quantity_Color& theColor) const;
526
527template bool ViewerTest_CmdParser::ArgColor (ViewerTest_CommandOptionKey theOptionKey,
528 Standard_Integer& theArgumentIndex,
529 Quantity_ColorRGBA& theColor) const;
530
531//===============================================================================================
532// function : findUsedOptionKey
533// purpose :
534//===============================================================================================
535bool ViewerTest_CmdParser::findOptionKey (const std::string& theOptionName,
536 ViewerTest_CommandOptionKey& theOptionKey) const
537{
538 const std::string anOptionNameInLowercase = toLowerCase (theOptionName);
539 const OptionMap::const_iterator aMapIter = myOptionMap.find (anOptionNameInLowercase);
540 if (aMapIter == myOptionMap.end())
541 {
542 return false;
543 }
544 theOptionKey = aMapIter->second;
545 return true;
546}
547
548//===============================================================================================
549// function : findUsedOptionKey
550// purpose :
551//===============================================================================================
552bool ViewerTest_CmdParser::findUsedOptionIndex (const ViewerTest_CommandOptionKey theOptionKey,
553 std::size_t& theUsedOptionIndex) const
554{
555 const UsedOptionMap::const_iterator aUsedOptionIterator = myUsedOptionMap.find (theOptionKey);
556 if (aUsedOptionIterator == myUsedOptionMap.end())
557 {
558 return false;
559 }
560 theUsedOptionIndex = aUsedOptionIterator->second;
561 return true;
562}
563
564//===============================================================================================
565// function : findUsedOptionIndex
566// purpose :
567//===============================================================================================
568bool ViewerTest_CmdParser::findUsedOptionIndex (const std::string& theOptionName, std::size_t& theUsedOptionIndex) const
569{
570 ViewerTest_CommandOptionKey anOptionKey = THE_UNNAMED_COMMAND_OPTION_KEY;
571 if (!findOptionKey (theOptionName, anOptionKey))
572 {
573 return false;
574 }
575 std::size_t aUsedOptionIndex = 0;
576 if (!findUsedOptionIndex (anOptionKey, aUsedOptionIndex))
577 {
578 return false;
579 }
580 theUsedOptionIndex = aUsedOptionIndex;
581 return true;
582}
583
584//===============================================================================================
585// function : addUsedOption
586// purpose :
587//===============================================================================================
588std::size_t ViewerTest_CmdParser::addUsedOption (const ViewerTest_CommandOptionKey theNewUsedOptionKey)
589{
590 const std::size_t aNewUsedOptionIndex = myOptionArgumentStorage.size();
591 myOptionArgumentStorage.push_back (OptionArguments());
592 myUsedOptionMap[theNewUsedOptionKey] = aNewUsedOptionIndex;
593 return aNewUsedOptionIndex;
594}
595
596//===============================================================================================
597// function : getRawStringArguments
598// purpose :
599//===============================================================================================
600ViewerTest_CmdParser::RawStringArguments ViewerTest_CmdParser::getRawStringArguments (
601 const std::size_t theUsedOptionIndex) const
602{
603 Standard_ASSERT_RETURN (
604 theUsedOptionIndex < myOptionArgumentStorage.size(),
605 "'theUsedOptionIndex' must be less than the size of 'myOptionArgumentStorage'.",
606 RawStringArguments());
607 const OptionArguments& anOptionArguments = myOptionArgumentStorage[theUsedOptionIndex];
608 return convertToRawStringList (anOptionArguments);
609}