55#include < stdexcept>
66#include < regex>
77#include < memory>
8+ #include < iostream>
89
910namespace cppcommandline
1011{
@@ -40,6 +41,17 @@ class Option
4041 d.reset (option.d .release ()); return *this ;
4142 }
4243
44+ bool operator ==(const Option &other) const
45+ {
46+ return d->defaultStringValue == other.d ->defaultStringValue
47+ && d->description == other.d ->description
48+ && d->longName == other.d ->longName
49+ && d->required == other.d ->required
50+ && d->shortName == other.d ->shortName
51+ && d->type == other.d ->type ;
52+ // TODO: Compare the union values.
53+ }
54+
4355 bool isPositional () const
4456 {
4557 return d->longName .empty ();
@@ -116,7 +128,7 @@ class Option
116128
117129 Option &required ()
118130 {
119- if (d->type == Type::Undefined )
131+ if (! d->defaulted )
120132 d->required = true ;
121133 else
122134 throw std::logic_error (" The option " + getName () + " has default value and cannot be set as required." );
@@ -141,6 +153,7 @@ class Option
141153 {
142154 setDefault (defaultValue);
143155 d->type = getType<T>();
156+ defaulted = true ;
144157 }
145158 return *this ;
146159 }
@@ -155,6 +168,84 @@ class Option
155168 setValueBinding (&value);
156169 }
157170
171+ std::vector<std::string>::const_iterator match (std::vector<std::string>::const_iterator argument, std::vector<std::string>::const_iterator end)
172+ {
173+ std::vector<std::string>::const_iterator returnPosition = argument;
174+ KeyValue keyValue = getKeyValue (*argument);
175+
176+ if (isLongNameArgument (keyValue.key ) || isShortNameArgument (keyValue.key ))
177+ {
178+ ++argument;
179+
180+ if (d->type == Type::Bool)
181+ *d->valueBinding .b = true ;
182+ else
183+ {
184+ if (keyValue.value .empty ())
185+ {
186+ if (argument == end)
187+ throw (std::logic_error (" Missing value for option '" + longName () + " '" ));
188+ else
189+ {
190+ keyValue.value = *argument;
191+ ++argument;
192+ }
193+ }
194+
195+ class ValueParseError : public std ::logic_error
196+ {
197+ public:
198+ ValueParseError () :
199+ std::logic_error (" ..." )
200+ {
201+
202+ }
203+ };
204+
205+ try
206+ {
207+ switch (d->type )
208+ {
209+ case Type::Double:
210+ if (isDouble (*argument))
211+ *d->valueBinding .d = std::stod (*argument);
212+ else
213+ throw (ValueParseError ());
214+ break ;
215+ case Type::Integer:
216+ if (isInteger (*argument))
217+ *d->valueBinding .i = std::stoi (*argument);
218+ else
219+ throw (ValueParseError ());
220+ break ;
221+ case Type::LongLong:
222+ if (isLongLong (*argument))
223+ *d->valueBinding .l = std::stol (*argument);
224+ else
225+ throw (ValueParseError ());
226+ break ;
227+ case Type::String:
228+ *d->valueBinding .s = *argument;
229+ break ;
230+ case Type::Undefined:
231+ throw (std::logic_error (" Bind value is undefined" ));
232+ break ;
233+ case Type::Bool:
234+ throw (std::logic_error (" Bool option should not be handled here" ));
235+ break ;
236+ }
237+
238+ returnPosition = argument;
239+ }
240+ catch (ValueParseError&)
241+ {
242+ }
243+ }
244+ }
245+
246+ return returnPosition;
247+ }
248+
158249private:
159250 enum class Type
160251 {
@@ -199,6 +290,7 @@ class Option
199290 Option::ValueBinding valueBinding;
200291 Option::Type type = Type::Undefined;
201292 bool required = false ;
293+ bool defaulted = false ;
202294 };
203295
204296 template <typename T> T *getBoundValue () const ;
@@ -304,11 +396,11 @@ template<> void Option::setDefault(int defaultValue) { d->defaultValue.i = defau
304396template <> void Option::setDefault (long long defaultValue) { d->defaultValue .l = defaultValue; }
305397template <> void Option::setDefault (double defaultValue) { d->defaultValue .d = defaultValue; }
306398template <> void Option::setDefault (bool defaultValue) { d->defaultValue .b = defaultValue; }
307- template <> void Option::setValueBinding (std::string *binding) { d->valueBinding .s = binding; }
308- template <> void Option::setValueBinding (int *binding) { d->valueBinding .i = binding; }
309- template <> void Option::setValueBinding (long long *binding) { d->valueBinding .l = binding; }
310- template <> void Option::setValueBinding (double *binding) { d->valueBinding .d = binding; }
311- template <> void Option::setValueBinding (bool *binding) { d->valueBinding .b = binding; }
399+ template <> void Option::setValueBinding (std::string *binding) { d->valueBinding .s = binding; if (d-> defaulted ) *binding = d-> defaultStringValue ; }
400+ template <> void Option::setValueBinding (int *binding) { d->valueBinding .i = binding; if (d-> defaulted ) *binding = d-> defaultValue . i ; }
401+ template <> void Option::setValueBinding (long long *binding) { d->valueBinding .l = binding; if (d-> defaulted ) *binding = d-> defaultValue . l ; }
402+ template <> void Option::setValueBinding (double *binding) { d->valueBinding .d = binding; if (d-> defaulted ) *binding = d-> defaultValue . d ; }
403+ template <> void Option::setValueBinding (bool *binding) { d->valueBinding .b = binding; if (d-> defaulted ) *binding = d-> defaultValue . b ; }
312404template <> Option::Type Option::getType<std::string>() const { return Type::String; }
313405template <> Option::Type Option::getType<int >() const { return Type::Integer; }
314406template <> Option::Type Option::getType<long long >() const { return Type::LongLong; }
@@ -332,18 +424,44 @@ class Parser
332424
333425 void parse (int argc, char **argv)
334426 {
335- mArgc = argc;
336- mArgv = argv;
427+ mArgs = std::vector<std::string>();
428+
429+ for (int i = 0 ; i < argc; i++)
430+ mArgs .emplace_back (std::string (argv[i]));
337431
338- for (int i = 0 ; i < mArgc ; ++i)
432+ std::vector<Option*> options;
433+
434+ for (Option &option : mOptions )
435+ options.emplace_back (&option);
436+
437+ for (auto arg = mArgs .cbegin (); arg != mArgs .cend ();)
339438 {
439+ auto start = arg;
440+
441+ for (auto option = options.begin (); option != options.end (); ++option)
442+ {
443+ auto next = (*option)->match (arg, mArgs .cend ());
444+
445+ if (next != arg)
446+ {
447+ options.erase (option);
448+ arg = next;
449+ }
450+ }
340451
452+ if (arg == start)
453+ throw (std::logic_error (" No option set for argument '" + *arg + " '" ));
454+ }
455+
456+ for (Option *option : options)
457+ {
458+ if (option->isRequired ())
459+ throw (std::logic_error (" Option '" + option->longName () + " ' was set as required but did not match any arguments" ));
341460 }
342461 }
343462
344463private:
345- int mArgc = 0 ;
346- char **mArgv = nullptr ;
464+ std::vector<std::string> mArgs ;
347465 std::vector<Option> mOptions ;
348466};
349467
0 commit comments