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