8#include "wvscatterhash.h"
12#undef __error_t_defined
30 WvArgsOption(
int _short_option,
31 WvStringParm _long_option,
33 : short_option(_short_option), long_option(_long_option), desc(_desc)
37 virtual ~WvArgsOption()
41 virtual WvString process(WvStringParm arg)
43 return WvString::null;
62 void add(WvArgsOption *option);
63 void remove(
char short_option, WvStringParm long_option);
66 void add_required_arg();
67 void subtract_required_arg();
70 static error_t parser(
int key,
char *arg,
argp_state *state);
75 friend class WvArgsOption;
76 friend class WvArgsArgOption;
80 bool argp_add(
const char *name,
int key,
const char *arg,
int flags,
81 const char *doc,
int group);
83 void argp_init(
size_t size = 0);
96 WvArgsOptionList options_list;
97 WvArgsOptionDict options_dict;
100 size_t required_args;
107void WvArgsOption::add_to_argp(
WvArgsData &data)
109 data.argp_add(long_option, short_option, 0, 0, desc, 0);
113class WvArgsNoArgOption :
public WvArgsOption
118 WvArgsNoArgOption(
int _short_option,
119 WvStringParm _long_option,
121 : WvArgsOption(_short_option, _long_option, _desc)
127class WvArgsSetBoolOption :
public WvArgsNoArgOption
136 WvArgsSetBoolOption(
int _short_option,
137 WvStringParm _long_option,
140 : WvArgsNoArgOption(_short_option, _long_option, _desc),
145 virtual WvString process(WvStringParm arg)
148 return WvString::null;
153class WvArgsResetBoolOption :
public WvArgsNoArgOption
162 WvArgsResetBoolOption(
int _short_option,
163 WvStringParm _long_option,
166 : WvArgsNoArgOption(_short_option, _long_option, _desc),
171 virtual WvString process(WvStringParm arg)
174 return WvString::null;
179class WvArgsFlipBoolOption :
public WvArgsNoArgOption
188 WvArgsFlipBoolOption(
int _short_option,
189 WvStringParm _long_option,
192 : WvArgsNoArgOption(_short_option, _long_option, _desc),
197 virtual WvString process(WvStringParm arg)
200 return WvString::null;
205class WvArgsIncIntOption :
public WvArgsNoArgOption
211 WvArgsIncIntOption(
int _short_option,
212 WvStringParm _long_option,
215 : WvArgsNoArgOption(_short_option, _long_option, _desc),
220 virtual WvString process(WvStringParm arg)
223 return WvString::null;
228class WvArgsNoArgCallbackOption :
public WvArgsNoArgOption
238 WvArgsNoArgCallbackOption(
int _short_option,
239 WvStringParm _long_option,
243 : WvArgsNoArgOption(_short_option, _long_option, _desc),
248 virtual WvString process(WvStringParm arg)
251 return WvString::null;
253 return WvString(
"invalid option `%s'", arg);
258class WvArgsArgOption :
public WvArgsOption
266 WvArgsArgOption(
int _short_option,
267 WvStringParm _long_option,
269 WvStringParm _arg_desc)
270 : WvArgsOption(_short_option, _long_option, _desc),
277 data.argp_add(long_option, short_option, arg_desc, 0, desc, 0);
282class WvArgsIntOption :
public WvArgsArgOption
290 WvArgsIntOption(
int _short_option,
291 WvStringParm _long_option,
293 WvStringParm _arg_desc,
295 : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
300 virtual WvString process(WvStringParm arg)
302 char *tailptr = NULL;
304 long int tmp = strtol(arg, &tailptr, 10);
305 if (errno == ERANGE || tmp > INT_MAX || tmp < INT_MIN )
308 return WvString(
"`%s': invalid number.", arg);
313 return WvString(
"`%s': invalid number.", arg);
318 return WvString::null;
324class WvArgsLongOption :
public WvArgsArgOption
332 WvArgsLongOption(
int _short_option,
333 WvStringParm _long_option,
335 WvStringParm _arg_desc,
337 : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
342 virtual WvString process(WvStringParm arg)
344 char *tailptr = NULL;
346 long int tmp = strtol(arg, &tailptr, 10);
350 return WvString(
"`%s': invalid number.", arg);
355 return WvString(
"`%s': invalid number.", arg);
360 return WvString::null;
366class WvArgsFloatOption :
public WvArgsArgOption
374 WvArgsFloatOption(
int _short_option,
375 WvStringParm _long_option,
377 WvStringParm _arg_desc,
379 : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
384 virtual WvString process(WvStringParm arg)
386 char *tailptr = NULL;
388 float tmp = strtof(arg, &tailptr);
392 return WvString(
"`%s': invalid number.", arg);
397 return WvString(
"`%s': invalid number.", arg);
402 return WvString::null;
408class WvArgsDoubleOption :
public WvArgsArgOption
416 WvArgsDoubleOption(
int _short_option,
417 WvStringParm _long_option,
419 WvStringParm _arg_desc,
421 : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
426 virtual WvString process(WvStringParm arg)
428 char *tailptr = NULL;
430 double tmp = strtod(arg, &tailptr);
434 return WvString(
"`%s': invalid number.", arg);
439 return WvString(
"`%s': invalid number.", arg);
444 return WvString::null;
450class WvArgsStringOption :
public WvArgsArgOption
458 WvArgsStringOption(
int _short_option,
459 WvStringParm _long_option,
461 WvStringParm _arg_desc,
463 : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
468 virtual WvString process(WvStringParm arg)
471 return WvString::null;
476class WvArgsStringListAppendOption :
public WvArgsArgOption
484 WvArgsStringListAppendOption(
int _short_option,
485 WvStringParm _long_option,
487 WvStringParm _arg_desc,
489 : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
494 virtual WvString process(WvStringParm arg)
497 return WvString::null;
502class WvArgsArgCallbackOption :
public WvArgsArgOption
511 WvArgsArgCallbackOption(
int _short_option,
512 WvStringParm _long_option,
514 WvStringParm _arg_desc,
517 : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
522 virtual WvString process(WvStringParm arg)
525 return WvString::null;
527 return WvString(
"invalid option: `%s'", arg);
532WvArgsData::WvArgsData()
533 : flags(0), argp_(NULL), argp_index(0), argp_size(0),
534 required_args(0), maximum_args(0), last_no_key(-1)
539WvArgsData::~WvArgsData()
552void *WvArgsData::self()
const
563 if (!option->short_option)
564 option->short_option = last_no_key--;
566 options_list.append(option,
true);
567 options_dict.add(option,
false);
573void WvArgsData::remove(
char short_option, WvStringParm long_option)
577 WvArgsOptionList::Iter i(options_list);
578 for (i.rewind(); i.next(); )
580 bool matches_short =
false;
581 bool matches_long =
false;
583 if (short_option !=
'\0' && i->short_option == short_option)
584 matches_short =
true;
585 if (!long_option.
isnull() && i->long_option == long_option)
588 if ((matches_short && matches_long)
589 || (matches_short && i->long_option.isnull())
590 || (matches_long && i->short_option ==
'\0'))
593 options_dict.remove(i.ptr());
601 else if (matches_short)
605 i->short_option =
'\0';
606 options_dict.remove(i.ptr());
607 options_dict.add(i.ptr(),
false);
609 else if (matches_long)
612 i->long_option = WvString::null;
618void WvArgsData::zap()
631void WvArgsData::argp_init(
size_t size)
638 argp_ = (argp_option *)malloc(argp_size *
sizeof(argp_option));
640 memset(argp_, 0,
sizeof(argp_option));
644void WvArgsData::argp_build()
647 argp_init(options_list.count() + 2);
649 WvArgsOptionList::Iter i(options_list);
650 for (i.rewind(); i.next(); )
651 i->add_to_argp(*
this);
655bool WvArgsData::argp_add(
const argp_option &option)
657 if (argp_index >= (argp_size - 1))
664 memcpy(argp_ + argp_index, &option,
sizeof(argp_option));
667 memset(argp_ + argp_index, 0,
sizeof(argp_option));
672bool WvArgsData::argp_add(
const char *name,
int key,
const char *arg,
673 int flags,
const char *doc,
int group)
675 if (argp_index >= (argp_size - 1))
682 argp_option *option = argp_ + argp_index;
686 option->flags = flags;
688 option->group = group;
691 memset(argp_ + argp_index, 0,
sizeof(argp_option));
696bool WvArgsData::argp_double()
699 void *tmp = realloc(argp_, 2 * argp_size *
sizeof(argp_option));
703 argp_ = (argp_option *)tmp;
709void WvArgsData::add_required_arg()
715void WvArgsData::subtract_required_arg()
727error_t WvArgsData::parser(
int key,
char *arg,
struct argp_state *state)
729 WvArgsData *data = (WvArgsData *)state->input;
734 if (state->arg_num >= data->maximum_args)
739 data->args_.append(arg);
742 case ARGP_KEY_NO_ARGS:
744 if (state->arg_num < data->required_args)
752 WvArgsOption *option = data->options_dict[key];
755 WvString error = option->process(arg);
758 argp_failure(state, argp_err_exit_status, 0,
764 return ARGP_ERR_UNKNOWN;
791 if (header && footer)
792 prog_doc =
WvString(
"%s\v%s", header, footer);
796 prog_doc =
WvString(
" \v%s", footer);
799 argp_program_version = version;
800 argp_program_bug_address = email;
802 struct argp argp = { data->argp(), &WvArgsData::parser, args_doc, prog_doc,
805 bool error = argp_parse(&
argp, argc, argv, data->flags, 0, data->self());
809 remaining_args->zap();
810 WvStringList::Iter i(data->args());
811 for (i.rewind(); i.next(); )
812 remaining_args->add(
new WvString(*i),
true);
821 this->version = version;
833 this->header = header;
839 this->footer = footer;
845 struct argp argp = { data->argp(), 0, 0, 0, 0, 0, 0 };
846 argp_help(&
argp, stdout, ARGP_HELP_STD_USAGE, argv[0]);
852 struct argp argp = { data->argp(), 0, 0, 0, 0, 0, 0 };
853 argp_help(&
argp, stdout, ARGP_HELP_STD_HELP, argv[0]);
857 WvStringParm desc,
bool &val)
859 data->remove(short_option, long_option);
865 WvStringParm desc,
bool &val)
867 data->remove(short_option, long_option);
873 WvStringParm desc,
bool &val)
875 data->remove(short_option, long_option);
883 data->remove(short_option, long_option);
889 WvStringParm desc, WvStringParm arg_desc,
int &val)
891 data->remove(short_option, long_option);
892 data->add(
new WvArgsIntOption(short_option, long_option, desc, arg_desc,
897 WvStringParm desc, WvStringParm arg_desc,
long &val)
899 data->remove(short_option, long_option);
905 WvStringParm desc, WvStringParm arg_desc,
float &val)
907 data->remove(short_option, long_option);
913 WvStringParm desc, WvStringParm arg_desc,
double &val)
915 data->remove(short_option, long_option);
921 WvStringParm desc, WvStringParm arg_desc,
924 data->remove(short_option, long_option);
930 WvStringParm desc, WvStringParm arg_desc,
933 data->remove(short_option, long_option);
935 desc, arg_desc, val));
939 WvStringParm desc, WvStringParm arg_desc,
942 data->remove(short_option, long_option);
950 data->remove(short_option, WvString::null);
956 data->remove(0, long_option);
968 data->add_required_arg();
970 args_doc.append(
" ");
971 args_doc.append(desc);
974 args_doc.append(
"...");
975 data->maximum_args = LONG_MAX;
977 else if (data->maximum_args < LONG_MAX)
978 ++(data->maximum_args);
986 data->subtract_required_arg();
994 case NO_EXIT_ON_ERRORS:
995 return data->flags & ARGP_NO_EXIT;
1002void WvArgs::set_flag(
const flags_t flag,
const bool value)
1004 printf(
"set_flag(%d, %d)\n", flag, value);
1008 case NO_EXIT_ON_ERRORS:
1009 mask = ARGP_NO_EXIT;
1016 data->flags |= mask;
1018 data->flags &= ~mask;
1020 printf(
"set_flag(%d, %d) = %d\n", flag, value, data->flags);
void remove_option(char short_option)
void remove_all_options()
bool get_flag(const flags_t flag) const
wv::function< bool(WvStringParm, void *)> ArgCallback
void add_optional_arg(WvStringParm desc, bool multiple=false)
void set_help_header(WvStringParm header)
Set the introductory help message, printed at the beginning of –help.
bool process(int argc, char **argv, WvStringList *remaining_args=NULL)
void print_usage(int argc, char **argv)
void set_help_footer(WvStringParm footer)
Set the descriptive help message, printed at the end of –help.
wv::function< bool(void *)> NoArgCallback
void set_version(WvStringParm version)
Set the –version string.
void add_option(char short_option, WvStringParm long_option, WvStringParm desc, WvStringParm arg_desc, int &val)
void add_required_arg(WvStringParm desc, bool multiple=false)
void add_reset_bool_option(char short_option, WvStringParm long_option, WvStringParm desc, bool &val)
void set_email(WvStringParm email)
Set the e-mail address for bug reports.
void print_help(int argc, char **argv)
void add_flip_bool_option(char short_option, WvStringParm long_option, WvStringParm desc, bool &val)
void add_set_bool_option(char short_option, WvStringParm long_option, WvStringParm desc, bool &val)
bool isnull() const
returns true if this string is null
const char * cstr() const
return a (const char *) for this string.
This is a WvList of WvStrings, and is a really handy way to parse strings.
WvString is an implementation of a simple and efficient printable-string class.