Skip to content

Commit 762f7b1

Browse files
committed
Don't force bool value string to "0" or "1" until after all transform actions have run.
1 parent b47e77e commit 762f7b1

3 files changed

Lines changed: 32 additions & 40 deletions

File tree

docs/guide.adoc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,15 +1202,14 @@ Action to take immediately before each source value is parsed. Any
12021202
number of transform actions can be added.
12031203

12041204
The function should:
1205-
* Inspect, and/or change the source value via cli.newValue().
1205+
* Inspect, then optionally change the source value via cli.newValue().
12061206
* Call cli.badUsage() with an error message if there's a problem.
12071207
* Call cli.parseExit() if the program should stop without an error. This could
12081208
be due to an early out like "--version" and "--help".
12091209

12101210
The argument is set, so you can use opt.from() and opt.pos() to get the
12111211
option name that the value was matched with on the command line and its
1212-
position in argv[]. For bool arguments the val string will always be
1213-
either "0" or "1".
1212+
position in argv[].
12141213

12151214
allow
12161215
deny

libs/dimcli/cli.cpp

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ struct RawValue {
167167
enum Type { kOperand, kOption, kCommand } type;
168168
Cli::OptBase * opt;
169169
string name;
170+
unsigned nameFlags;
170171
size_t pos;
171172
const char * ptr;
172173
Cli::ArgSrc src;
@@ -776,17 +777,7 @@ void Cli::newValue(const string & value) {
776777
assert(!"Bad context, not called from transform action callback.");
777778
return;
778779
}
779-
auto & opt = *m_cfg->curOpt;
780-
if (!opt.m_bool) {
781-
m_cfg->newValue = value;
782-
} else {
783-
bool v;
784-
if (parseBool(v, value)) {
785-
m_cfg->newValue = v ? "1" : "0";
786-
} else {
787-
badUsage(opt);
788-
}
789-
}
780+
m_cfg->newValue = value;
790781
}
791782

792783
//===========================================================================
@@ -2147,6 +2138,7 @@ static bool matchOperands(
21472138
}
21482139
auto & oprName = ndx.m_oprNames[ipos];
21492140
val->opt = oprName.opt;
2141+
val->nameFlags = oprName.flags;
21502142
val->name = oprName.name;
21512143
imatch += 1;
21522144
}
@@ -2222,8 +2214,9 @@ bool Cli::OptIndex::parseOperandValue(
22222214
st.numOprs += 1;
22232215
out->push_back({
22242216
RawValue::kOperand,
2225-
nullptr,
2226-
string{},
2217+
nullptr, // opt
2218+
string{}, // opt name
2219+
0, // opt name flags
22272220
st.argPos,
22282221
st.ptr,
22292222
*args[st.argPos].src
@@ -2246,6 +2239,7 @@ static void addOptionMatch(
22462239
RawValue::kOption,
22472240
st.optName.opt,
22482241
st.name,
2242+
st.optName.flags,
22492243
st.argPos,
22502244
ptr,
22512245
ptr ? *args[st.argPos].src : src
@@ -2361,12 +2355,7 @@ bool Cli::OptIndex::parseToRawValues(
23612355

23622356
// Found bool short name, record and continue processing any
23632357
// additional short names in this same argument.
2364-
addOptionMatch(
2365-
out,
2366-
st,
2367-
(st.optName.flags & fNameInvert) ? "0" : "1",
2368-
args
2369-
);
2358+
addOptionMatch(out, st, "1", args);
23702359
}
23712360
if (!*st.ptr) {
23722361
NEXT_ARG:
@@ -2411,22 +2400,13 @@ bool Cli::OptIndex::parseToRawValues(
24112400
}
24122401

24132402
// Found bool long name.
2414-
auto val = true;
2415-
if (st.ptr
2416-
&& (st.optName.opt->m_flagValue || !parseBool(val, st.ptr))
2417-
) {
2418-
// Only regular bool opts support values, and those values
2419-
// must be valid: true, false, 1, 0, y, n, etc.
2403+
if (st.ptr && st.optName.opt->m_flagValue) {
2404+
// Only regular bool opts support values.
24202405
cli.badUsage("Invalid '" + st.name + "' value", st.ptr);
24212406
return false;
24222407
}
24232408
// Record and advance to the next argument.
2424-
addOptionMatch(
2425-
out,
2426-
st,
2427-
val == bool(st.optName.flags & fNameInvert) ? "0" : "1",
2428-
args
2429-
);
2409+
addOptionMatch(out, st, st.ptr ? st.ptr : "1", args);
24302410
continue;
24312411
}
24322412

@@ -2577,6 +2557,7 @@ static bool parse(Cli & cli, vector<string> & rawArgs) {
25772557
if (!cli.parseValue(
25782558
*val.opt,
25792559
val.name,
2560+
val.nameFlags,
25802561
val.pos,
25812562
val.src.type,
25822563
val.src.name,
@@ -2755,7 +2736,7 @@ bool Cli::parseValue(
27552736
size_t pos,
27562737
const char ptr[]
27572738
) {
2758-
return parseValue(opt, name, pos, ArgSrc::kArgv, {}, ptr);
2739+
return parseValue(opt, name, 0, pos, ArgSrc::kArgv, {}, ptr);
27592740
}
27602741

27612742
//===========================================================================
@@ -2765,13 +2746,14 @@ bool Cli::parseValue(
27652746
const std::string & srcName, // use {} if unsure
27662747
const char ptr[]
27672748
) {
2768-
return parseValue(opt, opt.defaultFrom(), 0, srcType, srcName, ptr);
2749+
return parseValue(opt, opt.defaultFrom(), 0, 0, srcType, srcName, ptr);
27692750
}
27702751

27712752
//===========================================================================
27722753
bool Cli::parseValue(
27732754
OptBase & opt,
27742755
const string & name,
2756+
unsigned nameFlags,
27752757
size_t pos,
27762758
ArgSrc::Type srcType,
27772759
const string & srcName,
@@ -2795,8 +2777,19 @@ bool Cli::parseValue(
27952777
m_cfg->curOpt = &opt;
27962778
opt.doTransforms(*this);
27972779
m_cfg->curOpt = {};
2798-
if (!parseAborted())
2780+
if (!parseAborted()) {
2781+
if (opt.m_bool) {
2782+
bool val = false;
2783+
if (!parseBool(val, newValue())) {
2784+
badUsage(opt);
2785+
return false;
2786+
}
2787+
if (nameFlags & fNameInvert)
2788+
val = !val;
2789+
m_cfg->newValue = val ? "1" : "0";
2790+
}
27992791
opt.doParse(*this);
2792+
}
28002793
if (!parseAborted())
28012794
opt.doChecks(*this);
28022795
} else {

libs/dimcli/cli.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ class DIMCLI_LIB_DECL Cli {
692692
[[nodiscard]] bool parseValue(
693693
OptBase & out,
694694
const std::string & name, // use opt.defaultFrom() if unsure
695+
unsigned nameFlags, // use 0 if unsure
695696
size_t pos, // use 0 if unsure
696697
ArgSrc::Type srcType, // use kArgv if unsure (not kNone!)
697698
const std::string & srcName, // use {} if unsure
@@ -2005,8 +2006,7 @@ class Cli::OptShim : public OptBase {
20052006
//
20062007
// The argument is set, so you can use opt.from() and opt.pos() to get the
20072008
// option name that the value was matched with on the command line and its
2008-
// position in argv[]. For bool arguments the val string will always be
2009-
// either "0" or "1".
2009+
// position in argv[].
20102010
A & transform(std::function<ActionFn> fn, int priority = 1);
20112011

20122012
// Action to update the option value from a string taken from the
@@ -2022,7 +2022,7 @@ class Cli::OptShim : public OptBase {
20222022
// All opt.from(), opt.pos(), opt.srcType(), opt.srcName() are available.
20232023
// For bool arguments the val string will always be either "0" or "1".
20242024
//
2025-
// You could use this action to combined values into the final result, such
2025+
// You can use this action to combined values into the final result, such
20262026
// as via addition or appending to a string, instead of replacing it by
20272027
// assignment.
20282028
//

0 commit comments

Comments
 (0)