@@ -428,124 +428,125 @@ public:
428428 if (!isFlag) {
429429 // positional argument
430430 fArgs .push_back (arg);
431- } else {
431+ continue ;
432+ }
433+
434+ ++arg;
435+ // Parse long or short flag and its argument into `argStr` / `nxtArgStr`.
436+ // Note that `argStr` may contain multiple flags in case of grouped short flags (in which case nxtArgStr
437+ // refers only to the last one).
438+ argStr.clear ();
439+ std::string_view nxtArgStr;
440+ // If this is false `nxtArgStr` *must* refer to the next arg, otherwise it might or might not be.
441+ bool nxtArgIsTentative = true ;
442+ if (arg[0 ] == ' -' ) {
443+ // long flag
432444 ++arg;
433- // Parse long or short flag and its argument into `argStr` / `nxtArgStr`.
434- // Note that `argStr` may contain multiple flags in case of grouped short flags (in which case nxtArgStr
435- // refers only to the last one).
436- argStr.clear ();
437- std::string_view nxtArgStr;
438- // If this is false `nxtArgStr` *must* refer to the next arg, otherwise it might or might not be.
439- bool nxtArgIsTentative = true ;
440- if (arg[0 ] == ' -' ) {
441- // long flag
442- ++arg;
443- const char *eq = strchr (arg, ' =' );
444- if (eq) {
445- argStr.push_back (std::string_view (arg, eq - arg));
446- nxtArgStr = std::string_view (eq + 1 );
447- nxtArgIsTentative = false ;
448- } else {
449- argStr.push_back (std::string_view (arg));
450- if (i < nArgs - 1 && args[i + 1 ][0 ] != ' -' ) {
451- nxtArgStr = args[i + 1 ];
452- ++i;
453- }
454- }
445+ const char *eq = strchr (arg, ' =' );
446+ if (eq) {
447+ argStr.push_back (std::string_view (arg, eq - arg));
448+ nxtArgStr = std::string_view (eq + 1 );
449+ nxtArgIsTentative = false ;
455450 } else {
456- // short flag.
457- // If flag grouping is active, all flags except the last one will have an implicitly empty argument.
458- auto argLen = strlen (arg);
459- while (fSettings .fFlagTreatment == EFlagTreatment::kGrouped && argLen > 1 ) {
460- argStr.push_back (std::string_view{arg, 1 });
461- ++arg, --argLen;
462- }
463-
464451 argStr.push_back (std::string_view (arg));
465452 if (i < nArgs - 1 && args[i + 1 ][0 ] != ' -' ) {
466453 nxtArgStr = args[i + 1 ];
467454 ++i;
468455 }
469456 }
457+ } else {
458+ // short flag.
459+ // If flag grouping is active, all flags except the last one will have an implicitly empty argument.
460+ auto argLen = strlen (arg);
461+ while (fSettings .fFlagTreatment == EFlagTreatment::kGrouped && argLen > 1 ) {
462+ argStr.push_back (std::string_view{arg, 1 });
463+ ++arg, --argLen;
464+ }
465+
466+ argStr.push_back (std::string_view (arg));
467+ if (i < nArgs - 1 && args[i + 1 ][0 ] != ' -' ) {
468+ nxtArgStr = args[i + 1 ];
469+ ++i;
470+ }
471+ }
472+
473+ for (auto j = 0u ; j < argStr.size (); ++j) {
474+ std::string_view argS = argStr[j];
470475
471- for (auto j = 0u ; j < argStr.size (); ++j) {
472- std::string_view argS = argStr[j];
476+ const auto *exp = GetExpectedFlag (argS);
477+ if (!exp) {
478+ fErrors .push_back (std::string (" Unknown flag: " ) + argOrig);
479+ break ;
480+ }
473481
474- const auto *exp = GetExpectedFlag (argS);
475- if (!exp) {
482+ // In Prefix mode, check if the returned expected flag is shorter than `argS`. This can mean two things:
483+ // - if `nxtArgIsTentative == false` then this flag was followed by an equal sign, and in that case
484+ // the intention is interpreted as "I want this flag's argument to be whatever follows the equal sign",
485+ // which means we treat this as an unknown flag;
486+ // - otherwise, we use the rest of `argS` as the argument to the flag.
487+ // More concretely: if the user added flag "-D" and argS is "-Dfoo=bar", we parse it as
488+ // {flag: "-Dfoo", arg: "bar"}, rather than {flag: "-D", arg: "foo=bar"}.
489+ if ((exp->fOpts & kFlagPrefixArg ) && argS.size () > exp->fName .size ()) {
490+ if (nxtArgIsTentative) {
491+ i -= !nxtArgStr.empty (); // if we had already picked a candidate next arg, undo that.
492+ nxtArgStr = argS.substr (exp->fName .size ());
493+ nxtArgIsTentative = false ;
494+ } else {
476495 fErrors .push_back (std::string (" Unknown flag: " ) + argOrig);
477496 break ;
478497 }
498+ } else {
499+ assert (exp->fName .size () == argS.size ());
500+ }
479501
480- // In Prefix mode, check if the returned expected flag is shorter than `argS`. This can mean two things:
481- // - if `nxtArgIsTentative == false` then this flag was followed by an equal sign, and in that case
482- // the intention is interpreted as "I want this flag's argument to be whatever follows the equal sign",
483- // which means we treat this as an unknown flag;
484- // - otherwise, we use the rest of `argS` as the argument to the flag.
485- // More concretely: if the user added flag "-D" and argS is "-Dfoo=bar", we parse it as
486- // {flag: "-Dfoo", arg: "bar"}, rather than {flag: "-D", arg: "foo=bar"}.
487- if ((exp->fOpts & kFlagPrefixArg ) && argS.size () > exp->fName .size ()) {
488- if (nxtArgIsTentative) {
489- i -= !nxtArgStr.empty (); // if we had already picked a candidate next arg, undo that.
490- nxtArgStr = argS.substr (exp->fName .size ());
491- nxtArgIsTentative = false ;
492- } else {
493- fErrors .push_back (std::string (" Unknown flag: " ) + argOrig);
494- break ;
495- }
496- } else {
497- assert (exp->fName .size () == argS.size ());
498- }
502+ std::string_view nxtArg = (j == argStr.size () - 1 ) ? nxtArgStr : " " ;
499503
500- std::string_view nxtArg = (j == argStr.size () - 1 ) ? nxtArgStr : " " ;
501-
502- RCmdLineOpts::RFlag flag;
503- flag.fHelp = exp->fHelp ;
504- // If the flag is an alias (e.g. long version of a short one), save its name as the aliased one, so we
505- // can fetch the value later by using any of the aliases.
506- if (exp->fAlias < 0 )
507- flag.fName = exp->fName ;
508- else
509- flag.fName = fExpectedFlags [exp->fAlias ].fName ;
510-
511- // Check for duplicate flags
512- if (!(exp->fOpts & kFlagAllowMultiple )) {
513- auto existingIt = std::find_if (fFlags .begin (), fFlags .end (),
514- [&flag](const auto &f) { return f.fName == flag.fName ; });
515- if (existingIt != fFlags .end ()) {
516- std::string err = std::string (" Flag " ) + exp->AsStr () + " appeared more than once" ;
517- if (exp->fFlagType == RCmdLineOpts::EFlagType::kWithArg )
518- err += " with the value: " + existingIt->fValue ;
519- fErrors .push_back (err);
520- break ;
521- }
504+ RCmdLineOpts::RFlag flag;
505+ flag.fHelp = exp->fHelp ;
506+ // If the flag is an alias (e.g. long version of a short one), save its name as the aliased one, so we
507+ // can fetch the value later by using any of the aliases.
508+ if (exp->fAlias < 0 )
509+ flag.fName = exp->fName ;
510+ else
511+ flag.fName = fExpectedFlags [exp->fAlias ].fName ;
512+
513+ // Check for duplicate flags
514+ if (!(exp->fOpts & kFlagAllowMultiple )) {
515+ auto existingIt =
516+ std::find_if (fFlags .begin (), fFlags .end (), [&flag](const auto &f) { return f.fName == flag.fName ; });
517+ if (existingIt != fFlags .end ()) {
518+ std::string err = std::string (" Flag " ) + exp->AsStr () + " appeared more than once" ;
519+ if (exp->fFlagType == RCmdLineOpts::EFlagType::kWithArg )
520+ err += " with the value: " + existingIt->fValue ;
521+ fErrors .push_back (err);
522+ break ;
522523 }
524+ }
523525
524- // Check that arguments are what we expect.
525- if (exp->fFlagType == RCmdLineOpts::EFlagType::kWithArg ) {
526- if (!nxtArg.empty ()) {
527- flag.fValue = nxtArg;
528- } else {
529- fErrors .push_back (" Missing argument for flag " + exp->AsStr ());
530- }
526+ // Check that arguments are what we expect.
527+ if (exp->fFlagType == RCmdLineOpts::EFlagType::kWithArg ) {
528+ if (!nxtArg.empty ()) {
529+ flag.fValue = nxtArg;
531530 } else {
532- if (!nxtArg.empty ()) {
533- if (nxtArgIsTentative)
534- --i;
535- else
536- fErrors .push_back (" Flag " + exp->AsStr () + " does not expect an argument" );
537- }
531+ fErrors .push_back (" Missing argument for flag " + exp->AsStr ());
532+ }
533+ } else {
534+ if (!nxtArg.empty ()) {
535+ if (nxtArgIsTentative)
536+ --i;
537+ else
538+ fErrors .push_back (" Flag " + exp->AsStr () + " does not expect an argument" );
538539 }
539-
540- if (!fErrors .empty ())
541- break ;
542-
543- fFlags .push_back (flag);
544540 }
545541
546542 if (!fErrors .empty ())
547543 break ;
544+
545+ fFlags .push_back (flag);
548546 }
547+
548+ if (!fErrors .empty ())
549+ break ;
549550 }
550551 }
551552};
0 commit comments