1 #include "precomp.hpp"
2 #include <sstream>
3
4 namespace cv
5 {
6
7 struct CommandLineParserParams
8 {
9 public:
10 String help_message;
11 String def_value;
12 std::vector<String> keys;
13 int number;
14 };
15
16
17 struct CommandLineParser::Impl
18 {
19 bool error;
20 String error_message;
21 String about_message;
22
23 String path_to_app;
24 String app_name;
25
26 std::vector<CommandLineParserParams> data;
27
28 std::vector<String> split_range_string(const String& str, char fs, char ss) const;
29 std::vector<String> split_string(const String& str, char symbol = ' ', bool create_empty_item = false) const;
30 String cat_string(const String& str) const;
31
32 void apply_params(const String& key, const String& value);
33 void apply_params(int i, String value);
34
35 void sort_params();
36 int refcount;
37 };
38
39
get_type_name(int type)40 static String get_type_name(int type)
41 {
42 if( type == Param::INT )
43 return "int";
44 if( type == Param::BOOLEAN )
45 return "bool";
46 if( type == Param::UNSIGNED_INT )
47 return "unsigned";
48 if( type == Param::UINT64 )
49 return "unsigned long long";
50 if( type == Param::FLOAT )
51 return "float";
52 if( type == Param::REAL )
53 return "double";
54 if( type == Param::STRING )
55 return "string";
56 return "unknown";
57 }
58
from_str(const String & str,int type,void * dst)59 static void from_str(const String& str, int type, void* dst)
60 {
61 std::stringstream ss(str.c_str());
62 if( type == Param::INT )
63 ss >> *(int*)dst;
64 else if( type == Param::BOOLEAN )
65 {
66 std::string temp;
67 ss >> temp;
68 *(bool*) dst = temp == "true";
69 }
70 else if( type == Param::UNSIGNED_INT )
71 ss >> *(unsigned*)dst;
72 else if( type == Param::UINT64 )
73 ss >> *(uint64*)dst;
74 else if( type == Param::FLOAT )
75 ss >> *(float*)dst;
76 else if( type == Param::REAL )
77 ss >> *(double*)dst;
78 else if( type == Param::STRING )
79 *(String*)dst = str;
80 else
81 throw cv::Exception(CV_StsBadArg, "unknown/unsupported parameter type", "", __FILE__, __LINE__);
82
83 if (ss.fail())
84 {
85 String err_msg = "can not convert: [" + str +
86 + "] to [" + get_type_name(type) + "]";
87
88 throw cv::Exception(CV_StsBadArg, err_msg, "", __FILE__, __LINE__);
89 }
90 }
91
getByName(const String & name,bool space_delete,int type,void * dst) const92 void CommandLineParser::getByName(const String& name, bool space_delete, int type, void* dst) const
93 {
94 try
95 {
96 for (size_t i = 0; i < impl->data.size(); i++)
97 {
98 for (size_t j = 0; j < impl->data[i].keys.size(); j++)
99 {
100 if (name.compare(impl->data[i].keys[j]) == 0)
101 {
102 String v = impl->data[i].def_value;
103 if (space_delete)
104 v = impl->cat_string(v);
105 from_str(v, type, dst);
106 return;
107 }
108 }
109 }
110 impl->error = true;
111 impl->error_message = impl->error_message + "Unknown parameter " + name + "\n";
112 }
113 catch (std::exception& e)
114 {
115 impl->error = true;
116 impl->error_message = impl->error_message + "Exception: " + String(e.what()) + "\n";
117 }
118 }
119
120
getByIndex(int index,bool space_delete,int type,void * dst) const121 void CommandLineParser::getByIndex(int index, bool space_delete, int type, void* dst) const
122 {
123 try
124 {
125 for (size_t i = 0; i < impl->data.size(); i++)
126 {
127 if (impl->data[i].number == index)
128 {
129 String v = impl->data[i].def_value;
130 if (space_delete == true) v = impl->cat_string(v);
131 from_str(v, type, dst);
132 return;
133 }
134 }
135 impl->error = true;
136 impl->error_message = impl->error_message + "Unknown parameter #" + format("%d", index) + "\n";
137 }
138 catch(std::exception & e)
139 {
140 impl->error = true;
141 impl->error_message = impl->error_message + "Exception: " + String(e.what()) + "\n";
142 }
143 }
144
cmp_params(const CommandLineParserParams & p1,const CommandLineParserParams & p2)145 static bool cmp_params(const CommandLineParserParams & p1, const CommandLineParserParams & p2)
146 {
147 if (p1.number < p2.number)
148 return true;
149
150 if (p1.number > p2.number)
151 return false;
152
153 return p1.keys[0].compare(p2.keys[0]) < 0;
154 }
155
CommandLineParser(int argc,const char * const argv[],const String & keys)156 CommandLineParser::CommandLineParser(int argc, const char* const argv[], const String& keys)
157 {
158 impl = new Impl;
159 impl->refcount = 1;
160
161 // path to application
162 size_t pos_s = String(argv[0]).find_last_of("/\\");
163 if (pos_s == String::npos)
164 {
165 impl->path_to_app = "";
166 impl->app_name = String(argv[0]);
167 }
168 else
169 {
170 impl->path_to_app = String(argv[0]).substr(0, pos_s);
171 impl->app_name = String(argv[0]).substr(pos_s + 1, String(argv[0]).length() - pos_s);
172 }
173
174 impl->error = false;
175 impl->error_message = "";
176
177 // parse keys
178 std::vector<String> k = impl->split_range_string(keys, '{', '}');
179
180 int jj = 0;
181 for (size_t i = 0; i < k.size(); i++)
182 {
183 std::vector<String> l = impl->split_string(k[i], '|', true);
184 CommandLineParserParams p;
185 p.keys = impl->split_string(l[0]);
186 p.def_value = l[1];
187 p.help_message = impl->cat_string(l[2]);
188 p.number = -1;
189 if (p.keys.size() <= 0)
190 {
191 impl->error = true;
192 impl->error_message = "Field KEYS could not be empty\n";
193 }
194 else
195 {
196 if (p.keys[0][0] == '@')
197 {
198 p.number = jj;
199 jj++;
200 }
201
202 impl->data.push_back(p);
203 }
204 }
205
206 // parse argv
207 jj = 0;
208 for (int i = 1; i < argc; i++)
209 {
210 String s = String(argv[i]);
211
212 if (s.find('=') != String::npos && s.find('=') < s.length())
213 {
214 std::vector<String> k_v = impl->split_string(s, '=', true);
215 for (int h = 0; h < 2; h++)
216 {
217 if (k_v[0][0] == '-')
218 k_v[0] = k_v[0].substr(1, k_v[0].length() -1);
219 }
220 impl->apply_params(k_v[0], k_v[1]);
221 }
222 else if (s.length() > 2 && s[0] == '-' && s[1] == '-')
223 {
224 impl->apply_params(s.substr(2), "true");
225 }
226 else if (s.length() > 1 && s[0] == '-')
227 {
228 impl->apply_params(s.substr(1), "true");
229 }
230 else
231 {
232 impl->apply_params(jj, s);
233 jj++;
234 }
235 }
236
237 impl->sort_params();
238 }
239
~CommandLineParser()240 CommandLineParser::~CommandLineParser()
241 {
242 if (CV_XADD(&impl->refcount, -1) == 1)
243 delete impl;
244 }
245
CommandLineParser(const CommandLineParser & parser)246 CommandLineParser::CommandLineParser(const CommandLineParser& parser)
247 {
248 impl = parser.impl;
249 CV_XADD(&impl->refcount, 1);
250 }
251
operator =(const CommandLineParser & parser)252 CommandLineParser& CommandLineParser::operator = (const CommandLineParser& parser)
253 {
254 if( this != &parser )
255 {
256 if(CV_XADD(&impl->refcount, -1) == 1)
257 delete impl;
258 impl = parser.impl;
259 CV_XADD(&impl->refcount, 1);
260 }
261 return *this;
262 }
263
about(const String & message)264 void CommandLineParser::about(const String& message)
265 {
266 impl->about_message = message;
267 }
268
apply_params(const String & key,const String & value)269 void CommandLineParser::Impl::apply_params(const String& key, const String& value)
270 {
271 for (size_t i = 0; i < data.size(); i++)
272 {
273 for (size_t k = 0; k < data[i].keys.size(); k++)
274 {
275 if (key.compare(data[i].keys[k]) == 0)
276 {
277 data[i].def_value = value;
278 break;
279 }
280 }
281 }
282 }
283
apply_params(int i,String value)284 void CommandLineParser::Impl::apply_params(int i, String value)
285 {
286 for (size_t j = 0; j < data.size(); j++)
287 {
288 if (data[j].number == i)
289 {
290 data[j].def_value = value;
291 break;
292 }
293 }
294 }
295
sort_params()296 void CommandLineParser::Impl::sort_params()
297 {
298 for (size_t i = 0; i < data.size(); i++)
299 {
300 std::sort(data[i].keys.begin(), data[i].keys.end());
301 }
302
303 std::sort (data.begin(), data.end(), cmp_params);
304 }
305
cat_string(const String & str) const306 String CommandLineParser::Impl::cat_string(const String& str) const
307 {
308 int left = 0, right = (int)str.length();
309 while( left <= right && str[left] == ' ' )
310 left++;
311 while( right > left && str[right-1] == ' ' )
312 right--;
313 return left >= right ? String("") : str.substr(left, right-left);
314 }
315
getPathToApplication() const316 String CommandLineParser::getPathToApplication() const
317 {
318 return impl->path_to_app;
319 }
320
has(const String & name) const321 bool CommandLineParser::has(const String& name) const
322 {
323 for (size_t i = 0; i < impl->data.size(); i++)
324 {
325 for (size_t j = 0; j < impl->data[i].keys.size(); j++)
326 {
327 if (name.compare(impl->data[i].keys[j]) == 0 && String("true").compare(impl->data[i].def_value) == 0)
328 {
329 return true;
330 }
331 }
332 }
333 return false;
334 }
335
check() const336 bool CommandLineParser::check() const
337 {
338 return impl->error == false;
339 }
340
printErrors() const341 void CommandLineParser::printErrors() const
342 {
343 if (impl->error)
344 {
345 printf("\nERRORS:\n%s\n", impl->error_message.c_str());
346 fflush(stdout);
347 }
348 }
349
printMessage() const350 void CommandLineParser::printMessage() const
351 {
352 if (impl->about_message != "")
353 printf("%s\n", impl->about_message.c_str());
354
355 printf("Usage: %s [params] ", impl->app_name.c_str());
356
357 for (size_t i = 0; i < impl->data.size(); i++)
358 {
359 if (impl->data[i].number > -1)
360 {
361 String name = impl->data[i].keys[0].substr(1, impl->data[i].keys[0].length() - 1);
362 printf("%s ", name.c_str());
363 }
364 }
365
366 printf("\n\n");
367
368 for (size_t i = 0; i < impl->data.size(); i++)
369 {
370 if (impl->data[i].number == -1)
371 {
372 printf("\t");
373 for (size_t j = 0; j < impl->data[i].keys.size(); j++)
374 {
375 String k = impl->data[i].keys[j];
376 if (k.length() > 1)
377 {
378 printf("--");
379 }
380 else
381 {
382 printf("-");
383 }
384 printf("%s", k.c_str());
385
386 if (j != impl->data[i].keys.size() - 1)
387 {
388 printf(", ");
389 }
390 }
391 String dv = impl->cat_string(impl->data[i].def_value);
392 if (dv.compare("") != 0)
393 {
394 printf(" (value:%s)", dv.c_str());
395 }
396 printf("\n\t\t%s\n", impl->data[i].help_message.c_str());
397 }
398 }
399 printf("\n");
400
401 for (size_t i = 0; i < impl->data.size(); i++)
402 {
403 if (impl->data[i].number != -1)
404 {
405 printf("\t");
406 String k = impl->data[i].keys[0];
407 k = k.substr(1, k.length() - 1);
408
409 printf("%s", k.c_str());
410
411 String dv = impl->cat_string(impl->data[i].def_value);
412 if (dv.compare("") != 0)
413 {
414 printf(" (value:%s)", dv.c_str());
415 }
416 printf("\n\t\t%s\n", impl->data[i].help_message.c_str());
417 }
418 }
419 }
420
split_range_string(const String & _str,char fs,char ss) const421 std::vector<String> CommandLineParser::Impl::split_range_string(const String& _str, char fs, char ss) const
422 {
423 String str = _str;
424 std::vector<String> vec;
425 String word = "";
426 bool begin = false;
427
428 while (!str.empty())
429 {
430 if (str[0] == fs)
431 {
432 if (begin == true)
433 {
434 throw cv::Exception(CV_StsParseError,
435 String("error in split_range_string(")
436 + str
437 + String(", ")
438 + String(1, fs)
439 + String(", ")
440 + String(1, ss)
441 + String(")"),
442 "", __FILE__, __LINE__
443 );
444 }
445 begin = true;
446 word = "";
447 str = str.substr(1, str.length() - 1);
448 }
449
450 if (str[0] == ss)
451 {
452 if (begin == false)
453 {
454 throw cv::Exception(CV_StsParseError,
455 String("error in split_range_string(")
456 + str
457 + String(", ")
458 + String(1, fs)
459 + String(", ")
460 + String(1, ss)
461 + String(")"),
462 "", __FILE__, __LINE__
463 );
464 }
465 begin = false;
466 vec.push_back(word);
467 }
468
469 if (begin == true)
470 {
471 word = word + str[0];
472 }
473 str = str.substr(1, str.length() - 1);
474 }
475
476 if (begin == true)
477 {
478 throw cv::Exception(CV_StsParseError,
479 String("error in split_range_string(")
480 + str
481 + String(", ")
482 + String(1, fs)
483 + String(", ")
484 + String(1, ss)
485 + String(")"),
486 "", __FILE__, __LINE__
487 );
488 }
489
490 return vec;
491 }
492
split_string(const String & _str,char symbol,bool create_empty_item) const493 std::vector<String> CommandLineParser::Impl::split_string(const String& _str, char symbol, bool create_empty_item) const
494 {
495 String str = _str;
496 std::vector<String> vec;
497 String word = "";
498
499 while (!str.empty())
500 {
501 if (str[0] == symbol)
502 {
503 if (!word.empty() || create_empty_item)
504 {
505 vec.push_back(word);
506 word = "";
507 }
508 }
509 else
510 {
511 word = word + str[0];
512 }
513 str = str.substr(1, str.length() - 1);
514 }
515
516 if (word != "" || create_empty_item)
517 {
518 vec.push_back(word);
519 }
520
521 return vec;
522 }
523
524 }
525