mCRL2
Loading...
Searching...
No Matches
command_line_interface.h
Go to the documentation of this file.
1// Author(s): Jeroen van der Wulp
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
11
12#ifndef MCRL2_UTILITIES_COMMAND_LINE_INTERFACE_H
13#define MCRL2_UTILITIES_COMMAND_LINE_INTERFACE_H
14#include <cstdlib>
15#include <cstring>
16#include <fstream>
17#include <map>
18#include <memory>
19
23
24namespace mcrl2
25{
26namespace utilities
27{
28
29class interface_description;
30class command_line_parser;
31
33inline std::string copyright_period()
34{
35 // We assume that the version number always starts with a four digit year
36 // in which the version was released.
37 if (get_toolset_version().size() >= 4)
38 return get_toolset_version().substr(0, 4);
39 return "Today";
40}
41
124class interface_description
125{
126 friend class command_line_parser;
127
128 public:
129
131
136 class basic_argument
137 {
138
139 protected:
140
142 std::string m_name;
143
145 std::string m_type;
146
147 protected:
148
150 void set_name(std::string const& n)
151 {
152 m_name = n;
153 }
154
156 void set_type(std::string const& t)
157 {
158 m_type = t;
159 }
160
161 public:
162
163 class argument_description
164 {
165 protected:
166 std::string m_long;
167 std::string m_short;
168 std::string m_description;
169
170 public:
171 argument_description(const std::string& long_, const std::string& short_, const std::string& description)
172 : m_long(long_), m_short(short_), m_description(description)
173 {}
174
175 argument_description(const std::string& long_, const std::string& description)
176 : m_long(long_), m_description(description)
177 {}
178
179 const std::string& get_long() const
180 {
181 return m_long;
182 }
183
184 const std::string& get_short() const
185 {
186 return m_short;
187 }
188
189 const std::string& get_description() const
190 {
191 return m_description;
192 }
193 };
194
196 virtual basic_argument* clone() const = 0;
197
199 std::string get_name() const
200 {
201 return m_name;
202 }
203
205 std::string get_type() const
206 {
207 return m_type;
208 }
209
211 virtual bool has_description() const = 0;
212
214 virtual std::vector< argument_description > const& get_description() const = 0;
215
217 virtual std::string const& get_default() const = 0;
218
220 virtual bool validate(std::string const&) const = 0;
221
223 virtual bool is_optional() const = 0;
224
226 virtual bool has_default() const = 0;
227
229 virtual ~basic_argument()
230 {
231 }
232 };
233
235 template < typename T >
236 class typed_argument;
237
239 template < typename T = std::string >
240 class optional_argument;
241
243 template < typename T = std::string >
244 class mandatory_argument;
245
246 template < typename T = std::string >
247 class enum_argument;
248
250 class file_argument;
251
252 private:
253
265 class option_descriptor
266 {
267 friend class command_line_parser;
268 friend class interface_description;
269
270 private:
271
273 std::string m_long;
274
276 std::string m_description;
277
279 std::shared_ptr< basic_argument > m_argument;
280
282 char m_short;
283
285 bool m_show;
286
287 protected:
288
290 std::string textual_description(const std::size_t left_width, const std::size_t right_width) const;
291
293 std::string man_page_description() const;
294
296 std::ostream& xml_page_description(std::ostream& s, const bool is_standard = false, unsigned int indentation = 0) const;
297
298 public:
299
307 option_descriptor(std::string const& l, std::string const& d, const char s) :
308 m_long(l), m_description(d), m_short(s), m_show(true)
309 {
310
311 assert(!l.empty());
312 assert(l.find_first_not_of("_-0123456789abcdefghijklmnopqrstuvwxyz") == std::string::npos);
313 }
314
316 option_descriptor(option_descriptor const& o) : m_long(o.m_long),
317 m_description(o.m_description), m_argument(o.m_argument), m_short(o.m_short), m_show(true)
318 {
319 }
320
321 option_descriptor operator=(option_descriptor const& o)
322 {
323 return option_descriptor(o);
324 }
325
326 basic_argument const& argument() const
327 {
328 return *m_argument;
329 }
330
335 template < typename T >
336 void set_argument(T* a)
337 {
338 m_argument.reset(a);
339 }
340
344 inline const std::string& get_long() const
345 {
346 return m_long;
347 }
348
352 inline std::string const& get_default() const
353 {
354 return m_argument->get_default();
355 }
356
360 inline std::string get_description() const
361 {
362 return m_description;
363 }
364
368 inline bool needs_argument() const
369 {
370 return !(m_argument.get() == nullptr || m_argument->is_optional());
371 }
372
376 inline bool accepts_argument() const
377 {
378 return m_argument.get() != nullptr;
379 }
380 };
381
385 struct option_identifier_less
386 {
387 bool operator()(char const& c1, char const& c2) const
388 {
389 char c1u = toupper(c1);
390 char c2u = toupper(c2);
391
392 return c1u < c2u || (c1u == c2u && c2 < c1);
393 }
394
395 template < typename S >
396 bool operator()(S const& s1, S const& s2) const
397 {
398 std::string s1u = s1;
399 std::string s2u = s2;
400 std::transform(s1u.begin(), s1u.end(), s1u.begin(), ::toupper);
401 std::transform(s2u.begin(), s2u.end(), s2u.begin(), ::toupper);
402
403 return s1u < s2u || (s1u == s2u && s2 < s1);
404 }
405 };
407
408 typedef std::map< std::string, option_descriptor > option_map;
409
410 typedef std::map< const char, std::string, option_identifier_less > short_to_long_map;
411
413 option_map m_options;
414
415 private:
416
418 std::string m_path;
419
421 std::string m_name;
422
424 std::string m_authors;
425
427 std::string m_what_is;
428
430 std::string m_usage;
431
433 std::string m_description;
434
436 std::string m_known_issues;
437
438
439
441 short_to_long_map m_short_to_long;
442
443 private:
444
450 char long_to_short(std::string const& n) const
451 {
452 char result = '\0';
453
454 for (short_to_long_map::const_iterator i = m_short_to_long.begin(); result == '\0' && i != m_short_to_long.end(); ++i)
455 {
456 if (i->second == n)
457 {
458 result = i->first;
459 }
460 }
461
462 return result;
463 }
464
465 option_descriptor const& find_option(std::string const& long_identifier) const;
466
468 static interface_description& get_standard_description();
469
471 template < typename T >
472 inline static void register_initialiser()
473 {
474 T::add_options(get_standard_description());
475 }
476
478 inline interface_description()
479 {
480 }
481
482 public:
483
495 interface_description(std::string const& path, std::string const& name, std::string const& authors,
496 std::string const& what_is, std::string const& synopsis, std::string const& description,
497 std::string const& known_issues = "");
498
503 static std::string copyright_message();
504
529 std::string version_information() const;
530
589 template < typename T >
590 interface_description& add_option(std::string const& long_identifier,
591 typed_argument< T > const& argument_specification,
592 std::string const& description,
593 char const short_identifier = '\0')
594 {
595
596 add_option(long_identifier, description, short_identifier);
597
598 m_options.find(long_identifier)->second.set_argument(argument_specification.clone());
599
600 return *this;
601 }
602
634 interface_description& add_option(std::string const& long_identifier,
635 std::string const& description,
636 char const short_identifier = '\0')
637 {
638
639 if (m_options.find(long_identifier) != m_options.end())
640 {
641 throw std::logic_error("Duplicate long option (--" + long_identifier + "); this is a serious program error!");
642 }
643
644 if (short_identifier != '\0')
645 {
646 if (m_short_to_long.find(short_identifier) != m_short_to_long.end())
647 {
648 throw std::logic_error("Duplicate short option (-" + std::string(1, short_identifier) + "); this is a serious program error!");
649 }
650
651 m_short_to_long[short_identifier] = long_identifier;
652 }
653
654 m_options.insert(std::make_pair(long_identifier, option_descriptor(long_identifier, description, short_identifier)));
655
656 return *this;
657 }
658
668 template < typename T >
669 void add_hidden_option(
670 std::string const& long_identifier,
671 typed_argument< T > const& argument_specification,
672 std::string const& description,
673 char const short_identifier = '\0')
674 {
675
676 add_option(long_identifier, argument_specification, description, short_identifier);
677
678 m_options.find(long_identifier)->second.m_show = false;
679 }
680
686 void add_hidden_option(std::string const& long_identifier,
687 std::string const& description,
688 char const short_identifier = '\0')
689 {
690
691 add_option(long_identifier, description, short_identifier);
692
693 m_options.find(long_identifier)->second.m_show = false;
694 }
695
700 std::string textual_description(bool show_hidden) const;
701
706 std::string man_page() const;
707
712 std::ostream& xml_page(std::ostream&) const;
713
718 std::map<std::string, std::string> get_long_argument_with_description();
719
724 std::string get_toolname()
725 {
726 return m_name;
727 }
728};
729
790class command_line_parser
791{
792 public:
793
795 typedef std::multimap< std::string, std::string > option_map;
796
798 typedef std::vector< std::string > argument_list;
799
800 private:
801
803 option_map m_options;
804
806 argument_list m_arguments;
807
809 interface_description& m_interface;
810
812 bool m_continue;
813
814 public:
815
817 option_map const& options;
818
820 argument_list const& arguments;
821
823 bool has_option(const std::string& option) const
824 {
825 return options.find(option) != options.end();
826 }
827
828 private:
829
831 static std::vector< std::string > parse_command_line(char const* const arguments);
832
834 static std::vector< std::string > convert(const int count, char const* const* const arguments);
835
837 static std::vector< std::string > convert(const int count, wchar_t const* const* const arguments);
838
840 void collect(interface_description& d, std::vector< std::string > const& arguments);
841
843 void process_default_options(interface_description& d);
844
846 static std::vector< bool (*)(command_line_parser&) >& get_registered_actions()
847 {
848 static std::vector< bool (*)(command_line_parser&) > actions;
849
850 return actions;
851 }
852
854 static void register_action(bool (*action)(command_line_parser&))
855 {
856 get_registered_actions().push_back(action);
857 }
858
865 inline void
866 option_argument_as_impl(std::string const& long_identifier, std::string& res) const
867 {
868 res = option_argument(long_identifier);
869 }
870
879 template < typename T >
880 inline void
881 option_argument_as_impl(std::string const& long_identifier, T& result) const
882 {
883 std::istringstream in(option_argument(long_identifier));
884
885 result = T();
886
887 in >> result;
888
889 if (in.fail())
890 {
891 const char short_option(m_interface.long_to_short(long_identifier));
892
893 error("argument `" + option_argument(long_identifier) + "' to option --" + long_identifier +
894 ((short_option == '\0') ? " " : " or -" + std::string(1, short_option)) + " is invalid");
895 }
896 }
897
898 public:
899
907 inline command_line_parser(interface_description& interface_specification, char const* const command_line) :
908 m_interface(interface_specification), m_continue(true), options(m_options), arguments(m_arguments)
909 {
910 collect(interface_specification, parse_command_line(command_line));
911
912 process_default_options(interface_specification);
913 }
914
924 template < typename CharacterType >
925 command_line_parser(interface_description& interface_specification,
926 const int argument_count, CharacterType const* const* const arguments);
927
949 void error(std::string const& message) const
950 {
951 throw mcrl2::command_line_error(m_interface.m_name, message);
952 }
953
957 void check_no_duplicate_arguments() const
958 {
959 for (option_map::const_iterator i = m_options.begin(); i != m_options.end(); ++i)
960 {
961 if (1 < m_options.count(i->first))
962 {
963 error("option -" + (m_interface.long_to_short(i->first) != '\0' ?
964 std::string(1, m_interface.long_to_short(i->first)).append(", --") : "-") + i->first + " specified more than once");
965 }
966 }
967 }
968
985 std::string const& option_argument(std::string const& long_identifier) const;
986
990 inline bool continue_execution() const
991 {
992 return m_continue;
993 }
994
1003 template < typename T >
1004 inline T option_argument_as(std::string const& long_identifier) const
1005 {
1006 T result;
1007 option_argument_as_impl(long_identifier, result);
1008 return result;
1009 }
1010
1011};
1012
1014template < typename ArgumentType >
1015interface_description::optional_argument< ArgumentType > make_optional_argument(std::string const& name, std::string const& default_value)
1016{
1017 return interface_description::optional_argument< ArgumentType >(name, default_value);
1018}
1019
1043interface_description::optional_argument< std::string > make_optional_argument(std::string const& name, std::string const& default_value);
1044
1046template < typename ArgumentType >
1047interface_description::mandatory_argument< ArgumentType > make_mandatory_argument(std::string const& name)
1048{
1049 return interface_description::mandatory_argument< ArgumentType >(name);
1050}
1051
1073interface_description::mandatory_argument< std::string >
1074make_mandatory_argument(std::string const& name);
1075
1080template < typename ArgumentType >
1081interface_description::mandatory_argument< ArgumentType >
1082make_mandatory_argument(std::string const& name, std::string const& standard_value)
1083{
1084 return interface_description::mandatory_argument< ArgumentType >(name, standard_value);
1085}
1086
1111interface_description::mandatory_argument< std::string >
1112make_mandatory_argument(std::string const& name, std::string const& default_value);
1114
1116template < typename ArgumentType >
1117interface_description::enum_argument< ArgumentType > make_enum_argument(std::string const& name)
1118{
1119 return interface_description::enum_argument< ArgumentType >(name);
1120}
1121
1130template < typename T >
1131class interface_description::typed_argument : public basic_argument
1132{
1133
1134 public:
1135 typed_argument()
1136 {
1137 set_type("typed");
1138 }
1139
1141 inline bool validate(std::string const& s) const
1142 {
1143 std::istringstream test(s);
1144
1145 T result;
1146
1147 test >> result;
1148
1149 return !test.fail();
1150 }
1151};
1152
1160template < >
1161inline bool interface_description::typed_argument< std::string >::validate(std::string const&) const
1162{
1163 return true;
1164}
1165
1170template < typename T >
1171class interface_description::enum_argument : public typed_argument< T >
1172{
1173 protected:
1174
1175 std::vector< basic_argument::argument_description > m_enum;
1176
1177 std::string m_default;
1178 bool m_has_default;
1179
1181 enum_argument& add_value_with_short(const std::string& long_arg, const std::string& short_arg, const std::string& description, const bool is_default = false)
1182 {
1183 m_enum.push_back(basic_argument::argument_description(long_arg, short_arg, description));
1184
1185 if(is_default)
1186 {
1187 if(has_default())
1188 {
1189 throw std::runtime_error("cannot define duplicate default value to enum argument");
1190 }
1191 m_default = long_arg;
1192 m_has_default = true;
1193 }
1194
1195 return (*this);
1196 }
1197
1198 public:
1199
1201 enum_argument(std::string const& name) :
1202 m_has_default(false)
1203 {
1204 basic_argument::set_type("enum");
1205 basic_argument::set_name(name);
1206 }
1207
1209 virtual
1210 enum_argument* clone() const
1211 {
1212 return new enum_argument< T >(*this);
1213 }
1214
1216 virtual
1217 bool has_default() const
1218 {
1219 return m_has_default;
1220 }
1221
1223 virtual
1224 const std::string& get_default() const
1225 {
1226 return m_default;
1227 }
1228
1230 virtual
1231 bool is_optional() const
1232 {
1233 return false;
1234 }
1235
1237 inline bool validate(std::string const& s) const
1238 {
1239 for(typename std::vector< basic_argument::argument_description >::const_iterator i = m_enum.begin(); i != m_enum.end(); ++i)
1240 {
1241 if(i->get_long() == s || i->get_short() == s)
1242 {
1243 std::istringstream test(s);
1244 T result;
1245 test >> result;
1246
1247 return !test.fail();
1248 }
1249 }
1250 return false;
1251 }
1252
1264 enum_argument& add_value(const T& arg, const bool is_default = false)
1265 {
1266 return add_value_with_short(to_string(arg), std::string(), description(arg), is_default);
1267 }
1268
1281 enum_argument& add_value_desc(const T& arg, const std::string& description, const bool is_default = false)
1282 {
1283 return add_value_with_short(to_string(arg), std::string(), description, is_default);
1284 }
1285
1298 enum_argument& add_value_short(const T& arg, const std::string& short_argument, const bool is_default = false)
1299 {
1300 return add_value_with_short(to_string(arg), short_argument, description(arg), is_default);
1301 }
1302
1303
1304
1306 virtual bool has_description() const
1307 {
1308 return true;
1309 }
1310
1312 virtual const std::vector< basic_argument::argument_description >& get_description() const
1313 {
1314 return m_enum;
1315 }
1316
1317};
1318
1320template < typename T >
1321class interface_description::optional_argument : public typed_argument< T >
1322{
1323 friend class interface_description;
1324 friend class interface_description::option_descriptor;
1325 friend class command_line_parser;
1326
1327 protected:
1328
1330 std::string m_default;
1331
1333 std::vector< basic_argument::argument_description > m_description;
1334
1335 public:
1336
1337 virtual basic_argument* clone() const
1338 {
1339 return new optional_argument< T >(*this);
1340 }
1341
1347 inline optional_argument(std::string const& name, std::string const& d) : m_default(d)
1348 {
1349 basic_argument::set_type("optional");
1350 basic_argument::set_name(name);
1351 }
1352
1356 inline bool has_default() const
1357 {
1358 return true;
1359 }
1360
1364 inline std::string const& get_default() const
1365 {
1366 return m_default;
1367 }
1368
1370 inline bool is_optional() const
1371 {
1372 return true;
1373 }
1374
1375 inline bool has_description() const
1376 {
1377 return false;
1378 }
1379
1380 inline const std::vector< basic_argument::argument_description >& get_description() const
1381 {
1382 return m_description;
1383 }
1384};
1385
1387template < typename T >
1388class interface_description::mandatory_argument : public typed_argument< T >
1389{
1390
1391 protected:
1392
1394 std::string m_default;
1395
1397 bool m_has_default;
1398
1400 std::vector< basic_argument::argument_description > m_description;
1401
1402 public:
1403
1404 virtual basic_argument* clone() const
1405 {
1406 return new mandatory_argument< T >(*this);
1407 }
1408
1413 inline mandatory_argument(std::string const& name) : m_has_default(false)
1414 {
1415 basic_argument::set_type("mandatory");
1416 basic_argument::set_name(name);
1417 }
1418
1423 inline mandatory_argument(std::string const& name, std::string const& d) : m_default(d), m_has_default(true)
1424 {
1425 basic_argument::set_type("mandatory");
1426 basic_argument::set_name(name);
1427 }
1428
1432 inline std::string const& get_default() const
1433 {
1434 return m_default;
1435 }
1436
1440 inline bool has_default() const
1441 {
1442 return m_has_default;
1443 }
1444
1446 inline bool is_optional() const
1447 {
1448 return false;
1449 }
1450
1451 inline bool has_description() const
1452 {
1453 return false;
1454 }
1455
1456 inline const std::vector< basic_argument::argument_description >& get_description() const
1457 {
1458 return m_description;
1459 }
1460};
1461
1463class interface_description::file_argument : public typed_argument<std::string>
1464{
1465
1466 protected:
1467
1469 std::string m_default;
1470
1472 bool m_has_default;
1473
1475 std::vector< basic_argument::argument_description > m_description;
1476
1477 public:
1478
1479 virtual basic_argument* clone() const
1480 {
1481 return new file_argument(*this);
1482 }
1483
1484
1486 inline bool validate(std::string const& /*s*/) const
1487 {
1488 return true;
1489 }
1490
1495 inline file_argument(std::string const& name) : m_has_default(false)
1496 {
1497 basic_argument::set_type("file");
1498 basic_argument::set_name(name);
1499 }
1500
1504 inline std::string const& get_default() const
1505 {
1506 return m_default;
1507 }
1508
1512 inline bool has_default() const
1513 {
1514 return m_has_default;
1515 }
1516
1518 inline bool is_optional() const
1519 {
1520 return false;
1521 }
1522
1523 inline bool has_description() const
1524 {
1525 return false;
1526 }
1527
1528 inline const std::vector< basic_argument::argument_description >& get_description() const
1529 {
1530 return m_description;
1531 }
1532};
1533
1535inline
1536interface_description::file_argument make_file_argument(std::string const& name)
1537{
1538 return interface_description::file_argument(name);
1539}
1540
1541#if !defined(__COMMAND_LINE_INTERFACE__)
1542
1543template <>
1544inline command_line_parser::command_line_parser(interface_description& d, const int c, char const* const* const a) :
1545 m_interface(d), m_continue(true), options(m_options), arguments(m_arguments)
1546{
1547
1548 collect(d, convert(c, a));
1549
1550 process_default_options(d);
1551}
1552# ifndef __CYGWIN__ // std::wstring is not available for Cygwin
1553template <>
1554inline command_line_parser::command_line_parser(interface_description& d, const int c, wchar_t const* const* const a) :
1555 m_interface(d), m_continue(true), options(m_options), arguments(m_arguments)
1556{
1557
1558 collect(d, convert(c, a));
1559
1560 process_default_options(d);
1561}
1562# endif // __CYGWIN__
1563#endif
1565} // namespace utilities
1566} // namespace mcrl2
1567
1568#endif
Exception class for errors raised by the command-line parser.
Definition exception.h:39
Exception classes for use in libraries and tools.
@ error
Definition linearise.cpp:68
std::string description(const smt_solver_type s)
description of solver type
Definition solver_type.h:79
function_symbol in(const sort_expression &, const sort_expression &s0, const sort_expression &s1)
Definition bag1.h:362
const function_symbol & first()
Constructor for function symbol @first.
Definition nat1.h:1791
const function_symbol & c1()
Constructor for function symbol @c1.
Definition pos1.h:78
std::string to_string(const cs_game_node &n)
interface_description::optional_argument< std::string > make_optional_argument(std::string const &name, std::string const &default_value)
interface_description::mandatory_argument< std::string > make_mandatory_argument(std::string const &name, std::string const &default_value)
std::string get_toolset_version()
Get the toolset revision.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72
STL namespace.
String manipulation functions.
Get the toolset revision.