docopt / docopt.cpp

C++11 port of docopt
Boost Software License 1.0
1.03k stars 146 forks source link

Cannot distinguish default value from value given by a user #72

Open lmoellendorf opened 7 years ago

lmoellendorf commented 7 years ago
Given this usage text

Usage:
mycli [options]
mycli ADDRESS VALUE

Options:
-h, --help                   Show this screen.
-v, --version                Show version.
--always_set=[<n>]       This set to its default [default: 10].

arg.first.compare ( "--always_set" ) will always be true and arg.second.asLong() will be 10, even if the option --always_set has not been passed.

What I would like to achieve instead is:

mycli -> arg.first.compare ( "--always_set" ) is false mycli --always_set=2 -> arg.first.compare ( "--always_set" ) is true and arg.second.asLong() is 2 mycli --always_set -> arg.first.compare ( "--always_set" ) is true and arg.second.asLong() is 10. Actually this gives an error, although I (tried to) set the value of --always_set optional using the angular brackets.

Is there a way to achieve what I want?

isometriq commented 6 years ago

@lmoellendorf How did you get the long value? I can't except by converting from string (std::stoi), even when using your syntax. See here #62

lmoellendorf commented 6 years ago

@isometriq This is a shortened snippet from my code:

int main ( int argc, char *argv[] )
{

  std::map<std::string, docopt::value> args
  = docopt::docopt ( USAGE,
  { argv + 1, argv + argc },
  true,               // show help if requested
  VERSION_STRING );

  struct ctx *ctx;

  long option_value = 0;

  for ( auto const &arg : args ) {

    if ( 0 == arg.first.compare ( "--address" )
              && arg.second
              /**
               * "isLong() does not work as it is expected"
               * https://github.com/docopt/docopt.cpp/issues/62
               */
              && arg.second.isString() ) {
      try {

        option_value = arg.second.asLong();

        if ( ( ret = set_address ( ctx, option_value ) ) ) {

          std::cerr << "Error: Setting address failed!" << std::endl;

        } else {

          std::cout << "Address set to: " << option_value << std::endl;

        }

      } catch ( std::exception &e ) {
        std::cerr <<
                  "An exception occurred while parsing --address parameter. "
                  //<< e.what()
                  << std::endl;
        ret = -1;
      }
    }
  }
}
jaredgrubb commented 4 years ago

It sounds like you want three states: { not included, included with no param (use default), included with param } .. which isn't something that is standard POSIX syntax as far as I know.

I think you would be better off saying what the default would be in text but not having it specified.