@@ -191,10 +191,12 @@ struct Cli::Config {
191191 shared_ptr<locale> defLoc = make_shared<locale>();
192192 shared_ptr<locale> numLoc = make_shared<locale>(" " );
193193
194- bool parseExit = false ;
194+ Cli::OptBase * curOpt = {};
195+ string newValue;
195196 int exitCode = kExitOk ;
196197 string errMsg;
197198 string errDetail;
199+ bool parseExit = false ;
198200 vector<string> rawArgs;
199201 string progName;
200202 string command;
@@ -443,7 +445,7 @@ static bool equal(
443445 if (args.size () != sargs.size ())
444446 return false ;
445447 for (auto i = 0u ; i < args.size (); ++i) {
446- if (args[i].value != sargs[i])
448+ if (args[i].text != sargs[i])
447449 return false ;
448450 }
449451 return true ;
@@ -550,7 +552,8 @@ bool Cli::Convert::toString_impl<std::wstring>(
550552 size_t mblen = 0 ;
551553
552554 for (auto && w : src) {
553- assert (out.data () + out.size () - dst > MB_LEN_MAX);
555+ assert (out.data () + out.size () - dst > MB_LEN_MAX // LCOV_EXCL_LINE
556+ && " Internal dimcli error: char encoding exceeds MB_LEN_MAX." );
554557 mblen = wcrtomb (dst, w, &state);
555558 if (mblen == -1 ) {
556559 auto bytes = src.size () * sizeof src[0 ];
@@ -763,6 +766,25 @@ string Cli::OptBase::defaultPrompt() const {
763766 return name;
764767}
765768
769+ // ===========================================================================
770+ void Cli::newValue (const string & value) {
771+ if (!m_cfg->curOpt ) {
772+ assert (!" cli.newValue only allowed from transform action callbacks." );
773+ return ;
774+ }
775+ auto & opt = *m_cfg->curOpt ;
776+ if (!opt.m_bool ) {
777+ m_cfg->newValue = value;
778+ } else {
779+ bool v;
780+ if (parseBool (v, value)) {
781+ m_cfg->newValue = v ? " 1" : " 0" ;
782+ } else {
783+ badUsage (opt, value);
784+ }
785+ }
786+ }
787+
766788// ===========================================================================
767789void Cli::OptBase::setNameIfEmpty (const string & name) {
768790 if (m_fromName.empty ())
@@ -1401,6 +1423,12 @@ Cli::OptBase * Cli::findOpt(const void * value) {
14011423 return nullptr ;
14021424}
14031425
1426+ // ===========================================================================
1427+ // private
1428+ const string & Cli::newValue () const {
1429+ return m_cfg->newValue ;
1430+ }
1431+
14041432// ===========================================================================
14051433Cli::Opt<bool > & Cli::confirmOpt (const string & prompt) {
14061434 auto & ask = opt<bool >(" y yes." )
@@ -1677,7 +1705,7 @@ static void doBefore(
16771705) {
16781706 vector<string> sargs;
16791707 for (auto && arg : args)
1680- sargs.push_back (arg.value );
1708+ sargs.push_back (arg.text );
16811709 fn (cli, sargs);
16821710 if (!equal (args, sargs)) {
16831711 // String vector was changed, create new vector of args and completely
@@ -1951,7 +1979,7 @@ static bool expandResponseFile(
19511979) {
19521980 string content;
19531981 error_code ec;
1954- auto fn = args[pos].value .substr (1 );
1982+ auto fn = args[pos].text .substr (1 );
19551983 auto cfn = ancestors.empty ()
19561984 ? (fs::path) fn
19571985 : fs::path (ancestors.back ()).parent_path () / fn;
@@ -1992,7 +2020,7 @@ static bool expandResponseFiles(
19922020 vector<string> & ancestors
19932021) {
19942022 for (size_t pos = 0 ; pos < args.size (); ++pos) {
1995- if (!args[pos].value .empty () && args[pos].value .front () == ' @' ) {
2023+ if (!args[pos].text .empty () && args[pos].text .front () == ' @' ) {
19962024 if (!expandResponseFile (cli, args, pos, ancestors))
19972025 return false ;
19982026 }
@@ -2234,14 +2262,14 @@ bool Cli::OptIndex::parseOptionValue(
22342262 cli.badUsage (" No value given for " + st.name );
22352263 return false ;
22362264 }
2237- auto ptr = args[st.argPos ].value .c_str ();
2265+ auto ptr = args[st.argPos ].text .c_str ();
22382266 addOptionMatch (out, st, ptr, args);
22392267
22402268 // Option has value list, use following arguments up to the next option as
22412269 // values.
22422270 if (st.optName .flags & fNameList ) {
22432271 while (st.argPos + 1 < args.size ()) {
2244- ptr = args[st.argPos + 1 ].value .c_str ();
2272+ ptr = args[st.argPos + 1 ].text .c_str ();
22452273 if (*ptr == ' -' ) {
22462274 // The next argument looks like an option, so stop taking
22472275 // arguments.
@@ -2273,7 +2301,7 @@ bool Cli::OptIndex::parseToRawValues(
22732301 const vector<Cli::Arg> & args,
22742302 Cli & cli
22752303) {
2276- cli.m_cfg ->progName = args[0 ].value ;
2304+ cli.m_cfg ->progName = args[0 ].text ;
22772305 ParseState st;
22782306 if (cli.m_cfg ->cmds [" " ].unknownArgs ) {
22792307 st.cmdMode = ParseState::kUnknown ;
@@ -2283,7 +2311,7 @@ bool Cli::OptIndex::parseToRawValues(
22832311 }
22842312
22852313 for (; st.argPos < args.size (); ++st.argPos ) {
2286- st.ptr = args[st.argPos ].value .c_str ();
2314+ st.ptr = args[st.argPos ].text .c_str ();
22872315 if (*st.ptr == ' -' && st.ptr [1 ] && st.moreOpts ) {
22882316 // Argument contains one or more options.
22892317 st.ptr += 1 ;
@@ -2442,7 +2470,7 @@ static bool badMinMatched(
24422470// ===========================================================================
24432471// static
24442472void Cli::OptIndex::doAfters (OptBase & opt, Cli & cli) {
2445- opt.doAfterActions (cli);
2473+ opt.doAfters (cli);
24462474}
24472475
24482476// ===========================================================================
@@ -2595,6 +2623,8 @@ bool Cli::parse(const vector<string> & args) {
25952623Cli & Cli::resetValues () & {
25962624 for (auto && opt : m_cfg->opts )
25972625 opt->reset ();
2626+ m_cfg->curOpt = {};
2627+ m_cfg->newValue .clear ();
25982628 m_cfg->parseExit = false ;
25992629 m_cfg->exitCode = kExitOk ;
26002630 m_cfg->errMsg .clear ();
@@ -2716,16 +2746,21 @@ bool Cli::parseValue(
27162746 badUsage (prefix, ptr, detail);
27172747 return false ;
27182748 }
2719- string val;
27202749 if (ptr) {
2721- val = ptr;
2722- opt.doParseAction (*this , val);
2723- if (parseAborted ())
2724- return false ;
2750+ m_cfg->newValue = ptr;
2751+ m_cfg->curOpt = &opt;
2752+ opt.doTransforms (*this );
2753+ m_cfg->curOpt = {};
2754+ if (!parseAborted ())
2755+ opt.doParse (*this );
2756+ if (!parseAborted ())
2757+ opt.doChecks (*this );
27252758 } else {
2759+ m_cfg->newValue .clear ();
27262760 opt.assignImplicit ();
2761+ opt.doChecks (*this );
27272762 }
2728- opt. doCheckActions (* this , val );
2763+ m_cfg-> newValue . clear ( );
27292764 return !parseAborted ();
27302765}
27312766
@@ -3735,7 +3770,8 @@ static void calcColumns(
37353770 auto & col = cols[icol];
37363771 if (raw.newTable && col.minPct != -1 ) {
37373772 // Use min/max widths from preamble of this table cell.
3738- assert (col.maxPct != -1 );
3773+ assert (col.maxPct != -1 // LCOV_EXCL_LINE
3774+ && " Internal dimcli error: column min width w/o max" );
37393775 tcol.minWidth =
37403776 (int ) round (col.minPct * cfg.maxLineWidth / 100 );
37413777 tcol.maxWidth =
0 commit comments