Skip to content

Commit af55061

Browse files
committed
add option groups
1 parent b1b6e61 commit af55061

File tree

5 files changed

+66
-20
lines changed

5 files changed

+66
-20
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ifdef ICC
22
CXX = icpc
3-
WARN_FLAGS = -O3 -g -Wall -wd981 -wd383 -Werror # -Weffc++
3+
WARN_FLAGS = -O3 -ipo -g -Wall -wd981 -wd383 -Werror # -Weffc++
44
else
55
CXX = g++
66
WARN_FLAGS = -O3 -g -Wall -Wextra -Wabi -Wctor-dtor-privacy -Wnon-virtual-dtor -Wreorder -Wstrict-null-sentinel -Woverloaded-virtual -Wshadow -Wcast-align -Wpointer-arith -Wwrite-strings -Wundef -Wredundant-decls -Werror # -Weffc++

OptionParser.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static string str_replace(const string& s, const string& patt, const string& rep
5959
str_replace(tmp, patt, repl);
6060
return tmp;
6161
}
62-
static string str_format(const string& s, size_t pre, size_t len, bool indent_first) {
62+
static string str_format(const string& s, size_t pre, size_t len, bool indent_first = true) {
6363
stringstream ss;
6464
string p;
6565
if (indent_first)
@@ -150,6 +150,18 @@ Option& OptionParser::add_option(const vector<string>& v) {
150150
return option;
151151
}
152152

153+
OptionParser& OptionParser::add_option_group(const OptionGroup& group) {
154+
for (list<Option>::const_iterator oit = group._opts.begin(); oit != group._opts.end(); ++oit) {
155+
const Option& option = *oit;
156+
for (set<string>::const_iterator it = option._short_opts.begin(); it != option._short_opts.end(); ++it)
157+
_optmap_s[*it] = &option;
158+
for (set<string>::const_iterator it = option._long_opts.begin(); it != option._long_opts.end(); ++it)
159+
_optmap_l[*it] = &option;
160+
}
161+
_groups.push_back(&group);
162+
return *this;
163+
}
164+
153165
const Option& OptionParser::lookup_short_opt(const string& opt) const {
154166
optMap::const_iterator it = _optmap_s.find(opt);
155167
if (it == _optmap_s.end())
@@ -321,15 +333,14 @@ void OptionParser::process_opt(const Option& o, const string& opt, const string&
321333
}
322334
}
323335

324-
string OptionParser::format_option_help() const {
336+
string OptionParser::format_option_help(unsigned int indent /* = 2 */) const {
325337
stringstream ss;
326338

327339
if (_opts.empty())
328340
return ss.str();
329341

330-
ss << _("Options") << ":" << endl;
331342
for (list<Option>::const_iterator it = _opts.begin(); it != _opts.end(); ++it) {
332-
ss << it->format_help();
343+
ss << it->format_help(indent);
333344
}
334345

335346
return ss.str();
@@ -342,12 +353,21 @@ string OptionParser::format_help() const {
342353
ss << get_usage() << endl;
343354

344355
if (description() != "")
345-
ss << str_format(description(), 0, cols(), true) << endl;
356+
ss << str_format(description(), 0, cols()) << endl;
346357

358+
ss << _("Options") << ":" << endl;
347359
ss << format_option_help();
348360

361+
for (list<OptionGroup const*>::const_iterator it = _groups.begin(); it != _groups.end(); ++it) {
362+
const OptionGroup& group = **it;
363+
ss << endl << " " << group.title() << ":" << endl;
364+
if (group.group_description() != "")
365+
ss << str_format(group.group_description(), 4, cols()) << endl;
366+
ss << group.format_option_help(4);
367+
}
368+
349369
if (epilog() != "")
350-
ss << endl << str_format(epilog(), 0, cols(), true);
370+
ss << endl << str_format(epilog(), 0, cols());
351371

352372
return ss.str();
353373
}
@@ -438,21 +458,21 @@ string Option::check_type(const string& opt, const string& val) const {
438458
return err.str();
439459
}
440460

441-
string Option::format_option_help() const {
461+
string Option::format_option_help(unsigned int indent /* = 2 */) const {
442462

443463
string mvar_short, mvar_long;
444464
if (nargs() == 1) {
445465
string mvar = metavar();
446466
if (mvar == "") {
447467
mvar = type();
448468
transform(mvar.begin(), mvar.end(), mvar.begin(), ::toupper);
449-
}
469+
}
450470
mvar_short = " " + mvar;
451471
mvar_long = "=" + mvar;
452472
}
453473

454474
stringstream ss;
455-
ss << " ";
475+
ss << string(indent, ' ');
456476

457477
if (not _short_opts.empty()) {
458478
ss << str_join_trans(", ", _short_opts.begin(), _short_opts.end(), str_wrap("-", mvar_short));
@@ -465,9 +485,9 @@ string Option::format_option_help() const {
465485
return ss.str();
466486
}
467487

468-
string Option::format_help() const {
488+
string Option::format_help(unsigned int indent /* = 2 */) const {
469489
stringstream ss;
470-
string h = format_option_help();
490+
string h = format_option_help(indent);
471491
size_t width = cols();
472492
size_t opt_width = min(width*3/10, 36u);
473493
bool indent_first = false;

OptionParser.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@
2929
* - similarity to Python desired for faster learning curve
3030
*
3131
* Future work:
32-
* - option groups
3332
* - nargs > 1?
34-
* - code simplification / cleanup
3533
* - comments?
3634
*
3735
* Python only features:
@@ -73,14 +71,15 @@
7371
namespace optparse {
7472

7573
class OptionParser;
74+
class OptionGroup;
7675
class Option;
7776
class Values;
7877
class Value;
7978
class Callback;
8079

8180
typedef std::map<std::string,std::string> strMap;
8281
typedef std::map<std::string,std::list<std::string> > lstMap;
83-
typedef std::map<std::string,Option*> optMap;
82+
typedef std::map<std::string,Option const*> optMap;
8483

8584
//! Class for automatic conversion from string -> anytype
8685
class Value {
@@ -117,6 +116,7 @@ class Values {
117116
class OptionParser {
118117
public:
119118
OptionParser();
119+
virtual ~OptionParser() {}
120120

121121
OptionParser& usage(const std::string& u) { set_usage(u); return *this; }
122122
OptionParser& version(const std::string& v) { _version = v; return *this; }
@@ -130,6 +130,7 @@ class OptionParser {
130130
}
131131
OptionParser& enable_interspersed_args() { _interspersed_args = true; return *this; }
132132
OptionParser& disable_interspersed_args() { _interspersed_args = false; return *this; }
133+
OptionParser& add_option_group(const OptionGroup& group);
133134

134135
const std::string& usage() const { return _usage; }
135136
const std::string& version() const { return _version; }
@@ -158,7 +159,7 @@ class OptionParser {
158159
}
159160

160161
std::string format_help() const;
161-
std::string format_option_help() const;
162+
std::string format_option_help(unsigned int indent = 2) const;
162163
void print_help() const;
163164

164165
void set_usage(const std::string& u);
@@ -199,14 +200,33 @@ class OptionParser {
199200
optMap _optmap_s;
200201
optMap _optmap_l;
201202
strMap _defaults;
203+
std::list<OptionGroup const*> _groups;
202204

203205
std::list<std::string> _remaining;
204206
std::list<std::string> _leftover;
205207
};
206208

209+
class OptionGroup : public OptionParser {
210+
public:
211+
OptionGroup(const OptionParser& p, const std::string& t, const std::string& d = "") :
212+
_parser(p), _title(t), _group_description(d) {}
213+
virtual ~OptionGroup() {}
214+
215+
OptionGroup& title(const std::string& t) { _title = t; return *this; }
216+
OptionGroup& group_description(const std::string& d) { _group_description = d; return *this; }
217+
const std::string& title() const { return _title; }
218+
const std::string& group_description() const { return _group_description; }
219+
220+
private:
221+
const OptionParser& _parser;
222+
std::string _title;
223+
std::string _group_description;
224+
};
225+
207226
class Option {
208227
public:
209228
Option() : _action("store"), _type("string"), _nargs(1), _callback(0) {}
229+
virtual ~Option() {}
210230

211231
Option& action(const std::string& a);
212232
Option& type(const std::string& t) { _type = t; return *this; }
@@ -235,8 +255,8 @@ class Option {
235255

236256
private:
237257
std::string check_type(const std::string& opt, const std::string& val) const;
238-
std::string format_option_help() const;
239-
std::string format_help() const;
258+
std::string format_option_help(unsigned int indent = 2) const;
259+
std::string format_help(unsigned int indent = 2) const;
240260

241261
std::set<std::string> _short_opts;
242262
std::set<std::string> _long_opts;

README

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ Why not use tclap/Opag/Options/CmdLine/Anyoption/Argument_helper/...?
2828
- similarity to Python desired for faster learning curve
2929

3030
Future work:
31-
- option groups
32-
- code simplification / cleanup
31+
- nargs > 1?
3332
- comments?
3433

3534

test.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ int main(int argc, char *argv[])
101101
MyCallback mc;
102102
parser.add_option("-K", "--callback") .action("callback") .callback(mc) .help("callback test");
103103

104+
OptionGroup group = OptionGroup(parser, "Dangerous Options",
105+
"Caution: use these options at your own risk. "
106+
"It is believed that some of them bite.");
107+
group.add_option("-g") .action("store_true") .help("Group option.") .set_default("0");
108+
parser.add_option_group(group);
109+
104110
Values& options = parser.parse_args(argc, argv);
105111
vector<string> args = parser.args();
106112

@@ -128,6 +134,7 @@ int main(int argc, char *argv[])
128134
for (Values::iterator it = options.all("more_milk").begin(); it != options.all("more_milk").end(); ++it)
129135
out(*it);
130136
}
137+
cout << "group: " << (options.get("g") ? "true" : "false") << endl;
131138

132139
cout << endl << "leftover arguments: " << endl;
133140
for (vector<string>::const_iterator it = args.begin(); it != args.end(); ++it) {

0 commit comments

Comments
 (0)