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