2323#include < iostream>
2424#include < optional>
2525#include < stdexcept>
26- #include < string>
2726#include < string_view>
2827#include < unordered_map>
2928#include < variant>
3231namespace scl {
3332
3433/* *
35- * @brief Simple command line argument parser .
34+ * @brief Container for arguments and flags parsed by ProgramOptions::Parser .
3635 *
37- * ProgramOptions allows defining and parsing options for a program in a limited
38- * manner using a builder pattern. For example:
36+ * ProgramOptions holds the result after parsing the stuff in <code>argv</code>;
37+ * typically, this would be options, flags and so on.
3938 *
39+ * The interface of ProgramOptions is pretty intuitive
4040 * @code
41- * auto p = ProgramOptions::Parser("some description")
42- * .add(ProgramArg::required("foo", "int", "foo description"))
43- * .add(ProgramArg::optional("bar", "bool", "123"))
44- * .add(ProgramFlag("flag"))
45- * .parse(argc, argv);
41+ * ProgramOptions opts = ... //
42+ *
43+ * // check if "-foo 123" was passed in argv
44+ * opts.has("foo");
45+ * int foo = opts.get<int>("foo");
46+ * assert(foo == 123);
47+ *
48+ * // the non templated version of get simply returns the argument as
49+ * // an std::string_view
50+ * std::string_view foo_str = opts.get("foo");
51+ * assert(foo_str == "123");
52+ *
53+ * // check if "-some_flag" was passed in argv
54+ * opts.flagSet("some_flag");
4655 * @endcode
4756 *
48- * The above snippet will parse the <code>argv</code> argument vector passed to
49- * a program looking for arguments <code>-foo value</code> and
50- * <code>flag</code>. The <code>bar</code> is optional and if not explicitly
51- * supplied, gets the default value <code>"123"</code>.
57+ * ProgramOptions::get stores argument values internally as
58+ * strings. Specialization is, of course, allowed.
59+ *
60+ * @code
61+ * struct FooStruct {
62+ * int x;
63+ * int y;
64+ * };
65+ *
66+ * template <>
67+ * FooStruct scl::ProgramOptions::get<FooStruct>(std::string_view name) const {
68+ * FooStruct r;
69+ * const auto arg_val = m_args.at(name);
70+ * // turn the string arg_val into a FooStruct
71+ * return r;
72+ * }
73+ *
74+ * // this will enable us to write
75+ * FooStruct x = opts.get<FooStruct>();
76+ * @endcode
77+ *
78+ * Specializations exist for <code>int</code>, <code>std::size_t</code> and
79+ * <code>bool</code>. For the latter, the strings "1" and "true" are treated as
80+ * <code>true</code>, while everything else is treated as <code>false</code>.
5281 */
5382class ProgramOptions {
5483 public:
5584 class Parser ;
5685
5786 /* *
5887 * @brief Check if some argument has been provided.
59- * @param name the name of the argument.
60- * @return true if the argument was set, false otherwise.
6188 */
6289 bool has (std::string_view name) const {
6390 return m_args.find (name) != m_args.end ();
6491 }
6592
6693 /* *
6794 * @brief Check if a flag has been set.
68- * @param name the name of the flag.
69- * @return true if the flag was set, false otherwise.
7095 */
7196 bool flagSet (std::string_view name) const {
7297 return m_flags.find (name) != m_flags.end ();
7398 }
7499
75100 /* *
76101 * @brief Get the raw value of an argument.
77- * @param name the name of the argument.
78- * @return the value of the argument, as is.
79102 */
80103 std::string_view get (std::string_view name) const {
81104 return m_args.at (name);
82105 }
83106
84107 /* *
85108 * @brief Get the value of an argument with conversion.
86- * @tparam T the type to convert the argument to.
87- * @param name the name of the argument.
88- * @return the value of the argument after conversion.
89- *
90- * Specializations exist for this function for <code>bool</code>,
91- * <code>int</code> and <code>std::size_t</code>. It is possible to provide
92- * custom specializations that can be used to turn a string into any kind of
93- * object.
94109 */
95110 template <typename T>
96111 T get (std::string_view name) const ;
@@ -105,41 +120,27 @@ class ProgramOptions {
105120 std::unordered_map<std::string_view, bool > m_flags;
106121};
107122
108- /* *
109- * @brief Specialization of CmdArgs::Get for <code>bool</code>.
110- */
111123template <>
112- inline bool ProgramOptions::get<bool >(std::string_view name) const {
113- const auto v = m_args.at (name);
114- return v == " 1" || v == " true" ;
115- }
124+ bool ProgramOptions::get<bool >(std::string_view name) const ;
116125
117- /* *
118- * @brief Specialization for CmdArgs::Get for <code>int</code>.
119- */
120126template <>
121- inline int ProgramOptions::get<int >(std::string_view name) const {
122- return std::stoi (m_args.at (name).data ());
123- }
127+ int ProgramOptions::get<int >(std::string_view name) const ;
124128
125- /* *
126- * @brief Specialization of CmdArgs::Get for <code>std::size_t</code>.
127- */
128129template <>
129- inline std::size_t ProgramOptions::get<std::size_t >(
130- std::string_view name) const {
131- return std::stoul (m_args.at (name).data ());
132- }
130+ std::size_t ProgramOptions::get<std::size_t >(std::string_view name) const ;
133131
134132/* *
135133 * @brief An command-line argument definition.
136134 */
137135struct ProgramArg {
138136 /* *
139137 * @brief Create a required command-line argument.
140- * @param name the name.
141- * @param type_hint a string describing the expected type. E.g., "int".
142- * @param description a short description.
138+ *
139+ * This creates a required program argument. Adding a ProgramArg to a
140+ * ProgramOptions::Parser through this call with a \p name value of
141+ * <code>"something"</code> means that the caller of our program must supply
142+ * <code>-something</code> when calling our program. The type hint is purely
143+ * cosmetic.
143144 */
144145 static ProgramArg required (std::string_view name,
145146 std::string_view type_hint,
@@ -149,10 +150,9 @@ struct ProgramArg {
149150
150151 /* *
151152 * @brief Create an optional command-line argument.
152- * @param name the name.
153- * @param type_hint a string describing the expected type. E.g., "int".
154- * @param default_value an optional default value.
155- * @param description a short description.
153+ *
154+ * This creates an optional program argument. In case the argument is not
155+ * supplied by the caller of our program, the \p default_value will be used.
156156 */
157157 static ProgramArg optional (std::string_view name,
158158 std::string_view type_hint,
@@ -193,8 +193,6 @@ struct ProgramArg {
193193struct ProgramFlag {
194194 /* *
195195 * @brief Create a flag argument.
196- * @param name the name of the flag.
197- * @param description a description.
198196 */
199197 ProgramFlag (std::string_view name, std::string_view description = " " )
200198 : name(name), description(description) {}
@@ -211,22 +209,90 @@ struct ProgramFlag {
211209};
212210
213211/* *
214- * @brief Argument parser.
212+ * @brief Argument parser for command-line options .
215213 *
216- * The parser accepts argument defintions (through the Add functions) and
217- * parses the arguments provided to the main function into a CmdArgs object.
214+ * Parser provides a builder for constructing a ProgramOptions object based on
215+ * the stuff in <code>argv</code>.
216+ *
217+ * Parser permits the user to create three different types of program arguments:
218+ * - ProgramArg::required creates an option which accepts one argument, and
219+ * which must be provided for the program to Parser::parse to work.
220+ * - ProgramArg::optional creates an option which accepts one argument, and
221+ * which is optional.
222+ * - ProgramFlag creates a "flag", or toggle argument.
223+ *
224+ * @code
225+ * // example.cc
226+ * #include <scl/cmdline.h>
227+ * #include <iostream>
228+ *
229+ * using namespace scl;
230+ *
231+ * int main(int argc, char** argv) {
232+ * auto parser = ProgramOptions::Parser("super awesome program")
233+ * .add(ProgramArg::required("foo", "int", "foo"))
234+ * .add(ProgramArg::optional("bar", "bool", "true", "bar"))
235+ * .add(ProgramFlag("baz", "baz"));
236+ *
237+ * auto opts = parser.parse(argc, argv);
238+ *
239+ * std::cout << "foo = " << opts.get<int>("foo") << "\n";
240+ * std::cout << "bar = " << std::boolalpha << opts.get<bool>("bar") << "\n";
241+ * std::cout << "baz set? " << std::boolalpha << opts.flagSet("baz") << "\n";
242+ * }
243+ * @endcode
244+ *
245+ * \code{.unparsed}
246+ * $ g++ example.cc -lscl
247+ * $ ./a.out
248+ * ERROR: missing required argument
249+ * Usage: ./a.out -foo int [options ...]
250+ *
251+ * super awesome program
252+ *
253+ * Required arguments
254+ * -foo 'int' foo.
255+ *
256+ * Optional arguments
257+ * -bar 'bool' bar. [default=true]
258+ *
259+ * Flags
260+ * -baz baz.
261+ *
262+ * $ ./a.out -help
263+ * Usage: ./a.out -foo int [options ...]
264+ *
265+ * super awesome program
266+ *
267+ * Required arguments
268+ * -foo 'int' foo.
269+ *
270+ * Optional arguments
271+ * -bar 'bool' bar. [default=true]
272+ *
273+ * Flags
274+ * -baz baz.
275+ *
276+ * $ ./a.out -foo 42
277+ * foo = 42
278+ * bar = true
279+ * baz set? false
280+ * $ ./a.out -foo 100 -bar false -baz
281+ * foo = 100
282+ * bar = false
283+ * baz set? true
284+ * $
285+ * \endcode
218286 */
219287class ProgramOptions ::Parser {
220288 public:
221289 /* *
222290 * @brief Create a command-line argument parser.
223- * @param description a short description of the program.
224291 */
225292 Parser (std::string_view description = " " ) : m_description(description) {}
226293
227294 /* *
228295 * @brief Define an argument.
229- * @param def an argument definition.
230296 */
231297 Parser& add (const ProgramArg& def) {
232298 m_args.emplace_back (def);
@@ -235,7 +301,6 @@ class ProgramOptions::Parser {
235301
236302 /* *
237303 * @brief Define a flag argument.
238- * @param flag a flag definition.
239304 */
240305 Parser& add (const ProgramFlag& flag) {
241306 m_flags.emplace_back (flag);
@@ -244,22 +309,12 @@ class ProgramOptions::Parser {
244309
245310 /* *
246311 * @brief Parse arguments.
247- * @param argc the number of arguments.
248- * @param argv the arguments.
249- * @return the program options, or an error message.
250- *
251- * The \p argc and \p argv are assumed to be the inputs to a programs main
252- * function.
253312 */
254313 std::variant<ProgramOptions, std::string_view> parseArguments (int argc,
255314 char * argv[]);
256315
257316 /* *
258317 * @brief Parse arguments.
259- * @param argc the number of arguments.
260- * @param argv the arguments.
261- * @param exit_on_error whether to std::exit when parsing fails
262- * @return a set of program options.
263318 */
264319 ProgramOptions parse (int argc, char * argv[], bool exit_on_error = true ) {
265320 auto opts = parseArguments (argc, argv);
0 commit comments