6#include <bond/core/config.h>
8#include <boost/algorithm/string.hpp>
9#include <boost/lexical_cast.hpp>
10#include <boost/tokenizer.hpp>
24std::string ToString(
const T& value)
26 return boost::lexical_cast<std::string>(value);
30std::string ToString(
const uint8_t& value)
32 return boost::lexical_cast<std::string>(
static_cast<int>(value));
35std::string ToString(
const int8_t& value)
37 return boost::lexical_cast<std::string>(
static_cast<int>(value));
40class Metadata : boost::noncopyable
43 Metadata(
const bond::Metadata& metadata)
47 std::string Flag()
const
49 std::string flag(metadata.name);
50 std::replace(flag.begin(), flag.end(),
'_',
'-');
54 std::string Param()
const
57 return boost::to_upper_copy(metadata.name);
59 return Flag() +
"=" + boost::to_upper_copy(metadata.name);
62 std::string Abbr()
const
64 if (HasAttribute(
"abbr"))
65 return "-" + Attribute(
"abbr");
71 std::string Help()
const
75 if (HasAttribute(
"help"))
76 help = Attribute(
"help");
78 help = HelpFromType<T>();
80 std::string default_value = Default<T>();
82 if (!default_value.empty())
87 help +=
"default " + default_value;
93 std::string Help()
const
95 return Attribute(
"help");
100 return HasAttribute(
"naked");
103 bool IsOptional()
const
105 return metadata.modifier == bond::Optional;
109 bool HasAttribute(
const std::string& attr)
const
111 return metadata.attributes.end() != metadata.attributes.find(attr);
114 std::string Attribute(
const std::string& attr)
const
116 std::map<std::string, std::string>::const_iterator it;
118 it = metadata.attributes.find(attr);
120 if (it != metadata.attributes.end())
126 template <
typename T>
127 typename boost::disable_if_c<bond::is_list_container<T>::value
128 || std::is_enum<T>::value, std::string>::type
134 template <
typename T>
135 typename boost::enable_if<std::is_enum<T>, std::string>::type
140 const std::map<std::string, T>& names = bond::GetEnumNames<T>();
142 for (
typename std::map<std::string, T>::const_iterator it = names.begin(); it != names.end(); ++it)
151 template <
typename T>
152 typename boost::enable_if<bond::is_list_container<T>, std::string>::type
155 std::string help = HelpFromType<typename bond::element_type<T>::type>();
158 help =
"comma-separated list of: " + help;
163 template <
typename T>
164 typename boost::disable_if<bond::is_basic_type<T>, std::string>::type
170 template <
typename T>
171 typename boost::enable_if<bond::is_basic_type<T>, std::string>::type
174 if (metadata.modifier == bond::Optional && !metadata.default_value.nothing)
178 bond::detail::VariantGet(metadata.default_value, var);
180 return ToString(var);
186 const bond::Metadata& metadata;
195 Options(
int argc,
char** argv)
197 for (
int i = 1; i < argc; ++i)
199 std::string value = argv[i];
202 if (value[0] ==
'-' && value !=
"-" && value !=
"--")
204 size_t pos = value.find_first_of(
"=:");
206 name = value.substr(0, pos);
211 while(name.length() > 2)
213 params.push_back(Param(name.substr(0, 2),
""));
217 if (pos != std::string::npos)
218 value = value.substr(pos + 1);
223 params.push_back(Param(name, value));
228 bool GetFlag(
const std::string& flag,
const std::string& abbr)
230 Params::iterator it = FindParam(flag, abbr);
232 if (it != params.end())
234 if (!it->value.empty())
235 throw std::runtime_error(
"Invalid parameter(s):\n " + it->value);
244 bool GetParam(std::string& value)
246 return GetParam(
"",
"", value);
250 bool GetParam(
const std::string& flag,
const std::string& abbr, std::string& value)
252 Params::iterator it = FindParam(flag, abbr);
254 if (it != params.end())
258 if(value.empty() && ++it != params.end() && !it->used && it->name.empty())
271 std::string Leftovers()
273 std::string leftovers;
275 for (Params::iterator it = params.begin(); it != params.end(); ++it)
278 leftovers +=
" " + it->name;
280 if (!it->name.empty() && !it->value.empty())
283 leftovers += it->value +
"\n";
292 Param(
const std::string& name,
const std::string& value)
303 typedef std::list<Param> Params;
305 Params::iterator FindParam(
const std::string& flag,
const std::string& abbr)
309 for (it = params.begin(); it != params.end(); ++it)
310 if (!it->used && (it->name == flag || (it->name == abbr && !abbr.empty())))
328 CmdArg(
int argc,
char** argv,
bool partial =
false)
329 : options(boost::make_shared<Options>(argc, argv)),
333 CmdArg(
const boost::shared_ptr<Options>& options,
bool partial =
false)
338 void Begin(
const detail::Metadata& )
const
345 std::string leftovers = options->Leftovers();
347 if (!leftovers.empty())
348 throw std::runtime_error(
"Invalid parameter(s):\n" + leftovers);
352 template <
typename T>
353 bool Base(T& value)
const
355 return bond::Apply(CmdArg(options,
true), value);
358 template <
typename T>
359 typename boost::enable_if<bond::is_list_container<T>,
bool>::type
360 Field(uint16_t ,
const detail::Metadata& metadata, T& var)
const
362 while(GetParam(metadata, var));
366 template <
typename T>
367 typename boost::disable_if<bond::is_list_container<T>,
bool>::type
368 Field(uint16_t ,
const detail::Metadata& metadata, T& var)
const
370 GetParam(metadata, var);
376 template <
typename T>
377 typename boost::enable_if<std::is_enum<T> >::type
378 Parse(
const std::string& value, T& var)
const
380 if (!ToEnum(var, value.c_str()))
381 throw std::runtime_error(
"Invalid parameter(s):\n " + value);
385 template <
typename T>
386 typename boost::enable_if<std::is_arithmetic<T> >::type
387 Parse(
const std::string& value, T& var)
const
391 var = boost::lexical_cast<T>(value);
393 catch(
const std::exception&)
395 throw std::runtime_error(
"Invalid parameter(s):\n " + value);
400 void Parse(
const std::string& value, std::string& var)
const
406 template <
typename T>
407 typename boost::enable_if<bond::is_list_container<T> >::type
408 Parse(
const std::string& value, T& var)
const
410 typedef boost::tokenizer<boost::escaped_list_separator<char> > tokenizer;
412 tokenizer tok(value);
414 for(tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
416 typename bond::element_type<T>::type tmp;
423 template <
typename T>
424 void Parse(
const std::string& value, maybe<T>& var)
const
426 Parse(value, var.set_value());
431 bool GetParam(
const detail::Metadata& metadata,
bool& var)
const
434 BOOST_ASSERT(metadata.IsOptional());
435 BOOST_ASSERT(!metadata.IsNaked());
437 return (var = options->GetFlag(metadata.Flag(), metadata.Abbr()));
442 template <
typename T>
443 bool GetParam(
const detail::Metadata& metadata, T& var)
const
447 if (metadata.IsNaked())
448 options->GetParam(value);
450 options->GetParam(metadata.Flag(), metadata.Abbr(), value);
454 if(!metadata.IsOptional())
455 throw std::runtime_error(
"Required parameter " + metadata.Param() +
" missing.");
465 boost::shared_ptr<Options> options;
474 Usage(
const char* program, std::ostream& out = std::cerr)
479 void Begin(
const detail::Metadata& metadata)
const
481 std::string help = metadata.Help();
484 out << std::endl <<
"Usage: " << program <<
" " << help << std::endl << std::endl;
490 template <
typename T>
491 bool Base(
const T& value)
const
493 bond::Apply(*
this, value);
497 bool Field(uint16_t ,
const detail::Metadata& metadata,
const bool& )
const
499 Print(metadata.Flag(), metadata.Abbr(), metadata.Help());
503 template <
typename T>
504 bool Field(uint16_t ,
const detail::Metadata& metadata,
const bond::maybe<T>& )
const
506 std::string help = metadata.Help<T>();
508 Print(metadata.Param(), metadata.Abbr(), help);
512 template <
typename T>
513 bool Field(uint16_t ,
const detail::Metadata& metadata,
const T& )
const
515 std::string help = metadata.Help<T>();
517 Print(metadata.Param(), metadata.Abbr(), help);
522 void Print(
const std::string& arg,
const std::string& abbr,
const std::string& help)
const
524 int indent = (std::max)(30,
static_cast<int>(arg.size()) + 5);
525 std::string formated = FormatHelp(help, indent);
529 out.setf(std::ios::left, std::ios::adjustfield);
530 out.width(indent - 4);
531 out << arg << formated << std::endl;
534 std::string FormatHelp(
const std::string& help,
int indent)
const
536 std::string formated = help;
539 for (
int begin = 0; i < static_cast<int>(formated.length()); begin += 80, i = begin + 79 - indent)
541 while (i >= begin && !isspace(
static_cast<int>(formated[i])))
544 while (i <
static_cast<int>(formated.length()) && isspace(
static_cast<int>(formated[i])))
547 formated.insert(i, begin + 80 - i,
' ');
548 formated[i + begin + 79 - i - indent] =
'\n';
namespace bond
Definition: apply.h:17