Argument parsing in c++

Is getopt really the only argument parsing utility available in c++ without using third party libraries? Does anyone have any good tutorials on parsing positional and optional arguments in c++?

A Conspiracy Theorist Is Talking Shirt $21.68

POSIWID: The Purpose Of A System Is What It Does Shirt $21.68

A Conspiracy Theorist Is Talking Shirt $21.68

  1. 2 years ago
    Anonymous

    Literally just do it manually.
    int main(int argc, char** argv) {
    std::vector<std::string> args(argv, argv+argc);
    for(auto it = args.begin(); it<args.end();++it){
    if(*it[0] == '-') {
    if(*it == "--help") {
    printHelp();
    std::exit(1);
    } else if (*it == "--file") {
    std::string filepath = *(it++);
    // check if given filepath is valid
    }
    } else /* positional arg */{

    }
    }//end arg parse loop
    return 0;
    } // end main

    • 2 years ago
      Anonymous

      I made a mistake there, should be (++it) instead of (it++).
      But also, To be safe you should check if the iterator is valid before dereferenccing it
      So like...

      if (*it == "--file") {
      if (++it == args.end()) {
      std::cerr << "--file is missing a valuen" ;
      std::exit(1);
      }
      std::string filepath = *it;
      // validate that value is ok
      }

      • 2 years ago
        Anonymous

        And people laugh when I say that pre/postfix increment/decrement operators should be banned.

    • 2 years ago
      Anonymous

      I made a mistake there, should be (++it) instead of (it++).
      But also, To be safe you should check if the iterator is valid before dereferenccing it
      So like...

      if (*it == "--file") {
      if (++it == args.end()) {
      std::cerr << "--file is missing a valuen" ;
      std::exit(1);
      }
      std::string filepath = *it;
      // validate that value is ok
      }

      lmao seplets can't even manage basic things right.
      Meanwhile in real world:
      use clap::{Arg, App};

      fn main() {
      let matches = App::new("My Test Program")
      .version("0.1.0")
      .author("Hackerman Jones <[email protected]>")
      .about("Teaches argument parsing")
      .arg(Arg::with_name("file")
      .short("f")
      .long("file")
      .takes_value(true)
      .help("A cool file"))
      .arg(Arg::with_name("num")
      .short("n")
      .long("number")
      .takes_value(true)
      .help("Five less than your favorite number"))
      .get_matches();

      let myfile = matches.value_of("file").unwrap_or("input.txt");
      println!("The file passed is: {}", myfile);

      let num_str = matches.value_of("num");
      match num_str {
      None => println!("No idea what your favorite number is."),
      Some(s) => {
      match s.parse::<i32>() {
      Ok(n) => println!("Your favorite number must be {}.", n + 5),
      Err(_) => println!("That's not a number! {}", s),
      }
      }
      }
      }

    • 2 years ago
      Anonymous

      A good argument parser handles these cases:
      --file=filename
      -f filename
      -ffilename
      --file filename -- --file # "--file" is interpreted as a positional arg
      --bad # gives an error message
      - # interpreted not as an option but as a positional argument
      >*it[0]
      What happens if someone passes an empty string? Do you get UB?

      • 2 years ago
        Anonymous

        >Do you get UB?
        Oh, defined as of C++11 I guess

      • 2 years ago
        Anonymous

        Agreed. Every parser should support the -- syntax for passing positional args which start with a dash.

  2. 2 years ago
    Anonymous

    use ProgramOptions.hxx

  3. 2 years ago
    Anonymous

    Meanwhile in the REAL world

    use Getopt::Long qw/:config no_auto_abbrev no_ignore_case/;
    ...
    GetOptions (
    'h|help=s' => pod2usage (...),
    'v|verbose' => $verbose,
    'whatever=i' => sub { my $val = $_[1]; } # do something
    } or pod2usage;

    • 2 years ago
      Anonymous
      • 2 years ago
        Anonymous

        Enjoy your unreadable boilerplate code I guess

    • 2 years ago
      Anonymous

      Grim

  4. 2 years ago
    Anonymous

    argp is way better than getopt in my experience. It's available by default in GNU libc.

    • 2 years ago
      Anonymous

      I agree, but people who use meme libcs are going to be offended.

      If only competitors actually implemented these useful extensions instead of b***hing and crying about following a useless barebones "standard", we'd all be much better off and with more actual competition.

      • 2 years ago
        Anonymous

        >If only competitors actually implemented these useful extensions instead of b***hing and crying about following a useless barebones "standard", we'd all be much better off and with more actual competition.
        It wouldn't be competition anymore. It'd be GNU and imitation GNU, with everyone else playing catchup to become the least-bad imitation.
        Over 90% of GNU extensions are braindamaged, so it's better to just select and take the few that aren't, rather than taking them all.

        • 2 years ago
          Anonymous

          >It'd be GNU and imitation GNU, with everyone else playing catchup to become the least-bad imitation.
          That's how it is already, since nobody else is trying to innovate for shit. If you're not going to come up with improvements yourself, you're doomed to always play catch-up.

          • 2 years ago
            Anonymous

            >The info page handles it better: https://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html
            You're right.
            >The -a option lists two short options it's equivalent to (plus a long option, but I think I've seen short short option descriptions that only listed other short options).
            True! You're right that this is just a GNU documentation issue rather than a GNU-style option issue.

            I'd like to thank you for this discussion.

          • 2 years ago
            Anonymous

            >nobody else is trying to innovate
            Wrong. The BSDs regularly end up with new features, new short options, and new commands. Often such a feature originates on one BSD, then spreads to the other three.

    • 2 years ago
      Anonymous

      whoa wtf i didnt know about this thank you

  5. 2 years ago
    Anonymous

    getopt is C though, C++ doesn't have anything like that. Anon, it took the C++ committee 20+ years to add a contains() method to std::map, you think they are going to add some specific feature like an argument parser?

    • 2 years ago
      Anonymous

      >Anon, it took the C++ committee 20+ years to add a contains() method to std::map
      >https://stackoverflow.com/q/3886593
      Jesus, why? Why does it take them so long?
      Same thing with splitting strings, which I guess was blocked on string_view but then I don't understand why it took so long to add string_view

      • 2 years ago
        Anonymous

        C++ is an abomination. A million features, yet none of them useful.

      • 2 years ago
        Anonymous

        >Jesus, why? Why does it take them so long?
        They see C++ more as a core language to be extended by libraries (even though there is no good package manage lmao.) Some languages are "batteries included" (Go, Python) and that's great, some are not (C++, Rust).

        For what it's worth, splitting out these extra features makes sense because it makes the language more flexible. The STL is not really part of C++ rather it is its own thing. You don't have to use it, you can roll your own containers and stuff if you want to, e.g. in a kernel.

        • 2 years ago
          Anonymous

          >They see C++ more as a core language to be extended by libraries
          For this design choice to work, the language must provide powerful enough primitives to implement said funcitonality. C++ doesn't, it just bolted the keyword "class" on top of C and called it a day.

        • 2 years ago
          Anonymous

          I get that for argument parsing, but contains() and string_view have no business being third-party. Rust's HashMap::contains_key() predates 1.0 and its string_view equivalent is so important that they made it a builtin type (so they can use it for string literals).
          contains() is just a harmless convenience method, so it's bad that they didn't have it but not very interesting. Not having string views on the other hand makes the language less flexible, not more. If you have a lowest common denominator view type that everyone uses then libraries can interoperate smoothly.

          • 2 years ago
            Anonymous

            You are right of course, contains() has zero overhead, it just need to return find(x) !+ end.

            The C++ people just have no taste. They will take forever to add basic features yet at the same time create totally unusable clusterfricks such as the random or chrono api.

  6. 2 years ago
    Anonymous

    There is nothing wrong with getopt().
    https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
    If you prefer, you may want to look for an implementation of getflags()
    http://man.cat-v.org/unix_10th/3/getflags

    • 2 years ago
      Anonymous

      getopt works, but it doesn't "just work". It's very verbose and arguably error prone.

      • 2 years ago
        Anonymous

        >arguably error prone.
        How so?

  7. 2 years ago
    Anonymous

    use the plan9port flag parsing header

    • 2 years ago
      Anonymous

      I like long options.

      • 2 years ago
        Anonymous

        Why? They're legitimately dangerous and force users to be extremely defensive when scripting.
        GNU's option parsing rules are awful.
        Assuming -a and -b are regular flags that don't take options:
        # -b is seen as a regular argument here because it is after a regular argument. Regular arguments have the same effect as --.
        unixprog -a foo -b
        # --bopt is seen as an actual flag here, because in GNU option parsing, regular arguments do not have the -- effect
        gnuprog --aopt foo --bopt
        This means in shell scripts where any GNU option parsing is involved, the scripter has to be hyper-defensive and manually use -- all the time.

        Perhaps long options and GNU option parsing can be decoupled: even in that case, long options are unergonomic by requiring you to type more, for no benefit.
        gnuprog --longoption=very,long,yes

        • 2 years ago
          Anonymous

          You need to be nearly as defensive even with the traditional rules. -a -b -c "$foo" is going to give problems either way.
          The rule of early termination has nothing to do with robustness. I'm not sure that was even on their minds. The only reason it exists is that it makes the implementation simpler. (Most of Unix is like this.) You don't have to reshuffle argv or make the programmer interleave option handling and positional argument handling.
          >Perhaps long options and GNU option parsing can be decoupled
          They're easy to decouple, the issues are basically unrelated.
          >for no benefit
          There are many benefits.
          You can tell what they mean just by looking at them. That's wonderful when reading commands rather than writing them.
          There's a lower risk of conflicting options. If you extend the standard POSIX "pu" command with a --frobnicate flag while I add a --fuzz flag then there's minimal confusion. If we both add a -f flag but they do completely different things that's an issue.
          It's easier to maintain consistency. You can add a --verbose option to any command you want, but sometimes -v already has a meaning.
          They're arguably easier to memorize, or to guess.
          If you get them wrong you're more likely to get an error message instead of invoking the wrong option.
          And it's common practice to have short options that alias long options, so you're not locked out of your low-keystroke preference.

          • 2 years ago
            Anonymous

            >You need to be nearly as defensive even with the traditional rules.
            I disagree. You always need to be somewhat defensive when scripting, but Unix tools are much more sane than GNU tools in this regard.
            >The only reason it exists is that it makes the implementation simpler.
            Simpler implementations are often simpler for users to understand, too.
            >You can tell what they mean just by looking at them
            Wrong. Sure, you may have one word instead of one letter, but that is not enough to tell you what an option really does. If you do not entirely know what an option does, you're looking at the man page either way.
            >If we both add a -f flag but they do completely different things that's an issue.
            Why would this be an issue?
            If you extend with --fuzz on one implementation and --fuzz on another implementation it'd be the same thing.
            >It's easier to maintain consistency. You can add a --verbose option to any command you want, but sometimes -v already has a meaning.
            I agree with you here.

            (continued)

          • 2 years ago
            Anonymous

            >They're arguably easier to memorize
            Perhaps. I can't particularly agree or disagree here. Since everyone is different, I would 100% believe someone who said this was true.
            >or to guess.
            You should never be guessing. Always use the man page.
            I'm reminded of how so many GNU users will go mindlessly guess "prog -h" will give them help when -h already has a meaning for that command. Sure, in this case, they could use --help, but there may be other single-English-word long options where an English word could be interpreted in two or three ways.
            The man page should always be used, so the verbosity of long options cannot be seen as a benefit.
            >If you get them wrong you're more likely to get an error message instead of invoking the wrong option.
            True.
            >And it's common practice to have short options that alias long options, so you're not locked out of your low-keystroke preference.
            I wish this were true, but it unfortunately isn't.
            My most commonly-used mpv option is --no-audio-display, which has no Unix option equivalent and is very painful to write out, so I have to use an alias instead.
            Even where short options are available, some projects (like GNU) get inferior documentation because of how they handle documenting short and long options.
            For example, cp -p:
            https://man7.org/linux/man-pages/man1/cp.1.html
            See how -p is documented. It doesn't give you any of the meaning of -p, which could easily be summarised in a single sentence. ("Preserve attributes.") Then check out --preserve and notice how nothing there is documented either. I see this all the time with long options in man pages.

            >Unix tools are much more sane than GNU tools in this regard.
            What about my example? Isn't that the common failure case, and isn't it identical between conventions?
            >Simpler implementations are often simpler for users to understand, too.
            True, but you need to find a balance. And I don't think the balance they picked half a century ago is the right balance today.
            >that is not enough to tell you what an option really does.
            Yeah, okay, the knowledge isn't instantly beamed into your head, but it's way easier to make an educated guess. If I'm skimming a shell script and I see "rsync --recursive" then I don't need to reach for a man page, but "-r" might make me nervous.
            >Why would this be an issue?
            I'm used to "pu -f" from Foonix, and then I run "pu -f" on BarOS, and it frobnicates my files instead of fuzzing them and I lose data.
            I'm used to "pu --fuzz" from Foonix, and then I run "pu --fuzz" on BarOS, and it tells me "unrecognized option --fuzz".
            It's not airtight, but can you see how it's an improvement?
            >You should never be guessing.
            Your -h/--help is a perfect example.
            If an English word is ambiguous then maybe be careful with guessing. But how much can go wrong with --color=always, or --verbose, or --case-sensitive?
            You don't need to be as absolutist about this if the options are more scrutable.
            >--no-audio-display
            I agree this is a counterexample, but this brings up another point: mpv has over 800 options. They're not going to fit that into the short option syntax without dipping into unicode. Should they try?
            (Unrelated, isn't this better in mpv.conf instead of an alias?)
            >cp -p
            Yeah, that sucks. The info page handles it better: https://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html
            But I don't feel this is related to long options. The -a option lists two short options it's equivalent to (plus a long option, but I think I've seen short short option descriptions that only listed other short options).

          • 2 years ago
            Anonymous

            >What about my example? Isn't that the common failure case, and isn't it identical between conventions?
            Yes, in that case you would be using -- both on Unix and GNU.
            >If I'm skimming a shell script and I see "rsync --recursive" then I don't need to reach for a man page, but "-r" might make me nervous.
            I see. I get nervous either way. As you can already tell, I'm really guessing-averse.
            >I'm used to "pu -f" from Foonix, and then I run "pu -f" on BarOS, and it frobnicates my files instead of fuzzing them and I lose data.
            It's up to you to be aware of -f's portability status. That's kinda how command line interfaces are: they're not GUIs and they don't have help text when you hover over different options. Perhaps that's a bad thing. But it's how it is.
            >I'm used to "pu --fuzz" from Foonix, and then I run "pu --fuzz" on BarOS, and it tells me "unrecognized option --fuzz".
            Correct, that may happen, or you may lose data.
            >It's not airtight, but can you see how it's an improvement?
            Only when people are hitting enter for commands they don't understand. Sure.
            >But how much can go wrong with --color=always, or --verbose, or --case-sensitive?
            Agreed, those are good points you have.
            >mpv has over 800 options. They're not going to fit that into the short option syntax without dipping into unicode.
            Ah, I didn't know there were so many options to mpv. You are correct that it wouldn't fit into short options. I wonder what the real answer to this is. Perhaps that is a case for GNU-style options.
            >(Unrelated, isn't this better in mpv.conf instead of an alias?)
            I don't know how to use mpv.conf. .w.
            (continued)

          • 2 years ago
            Anonymous

            >It's up to you to be aware of -f's portability status
            >Only when people are hitting enter for commands they don't understand
            Realistically I won't always understand all the details, even when I think I do. People make mistakes and it's nice to anticipate that.
            That's a pretty general philosophical argument of course. If you take it far enough you get something like Rust, very good at catching mistakes but oh-so-complicated.
            >I don't know how to use mpv.conf. .w.
            Putting audio-display=no in ~/.config/mpv/mpv.conf should do it. It basically mirrors the command line options.
            The man page also says something about profiles, which I've never used but look straightforward.

            >The info page handles it better: https://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html
            You're right.
            >The -a option lists two short options it's equivalent to (plus a long option, but I think I've seen short short option descriptions that only listed other short options).
            True! You're right that this is just a GNU documentation issue rather than a GNU-style option issue.

            I'd like to thank you for this discussion.

            Thank you too! It's nice to talk to someone else who cares about this topic. You also made some good points.

          • 2 years ago
            Anonymous

            >They're arguably easier to memorize
            Perhaps. I can't particularly agree or disagree here. Since everyone is different, I would 100% believe someone who said this was true.
            >or to guess.
            You should never be guessing. Always use the man page.
            I'm reminded of how so many GNU users will go mindlessly guess "prog -h" will give them help when -h already has a meaning for that command. Sure, in this case, they could use --help, but there may be other single-English-word long options where an English word could be interpreted in two or three ways.
            The man page should always be used, so the verbosity of long options cannot be seen as a benefit.
            >If you get them wrong you're more likely to get an error message instead of invoking the wrong option.
            True.
            >And it's common practice to have short options that alias long options, so you're not locked out of your low-keystroke preference.
            I wish this were true, but it unfortunately isn't.
            My most commonly-used mpv option is --no-audio-display, which has no Unix option equivalent and is very painful to write out, so I have to use an alias instead.
            Even where short options are available, some projects (like GNU) get inferior documentation because of how they handle documenting short and long options.
            For example, cp -p:
            https://man7.org/linux/man-pages/man1/cp.1.html
            See how -p is documented. It doesn't give you any of the meaning of -p, which could easily be summarised in a single sentence. ("Preserve attributes.") Then check out --preserve and notice how nothing there is documented either. I see this all the time with long options in man pages.

  8. 2 years ago
    Anonymous

    Just use something like Argh! for basic stuff lel

Your email address will not be published. Required fields are marked *