Search code examples
cargumentscommand-line-argumentsargp

GNU argp: How to parse option with only long name?


I want to use argp in my C program to parse command line options.

One requirement is that an option does not have a short name (like -f bar) but only a long name (like --foo=bar).

My approach so far is to set the key field of the argp_option struct to 0 to make it not show a short name.

I have looked at the provided examples and argp.h in detail but I can't find a means to parse an option that only has a long name in the parser function that is given to argp.

What I did find out is that, theoretically, in the parser I could use

case ARGP_KEY_ARG:
  printf("%s\n", arg);

to find the value of long options (e.g. when called with --foo=bar, bar would be printed here). However, this doesn't seem like the right approach since I don't see a simple way to actually tell which option the value belongs to. and this also shows actual command line arguments (not option values).

I'd be thankful for any tips about where I need to look. Cheers.


Solution

  • From "The GNU C Library: Argp Option Vectors — Specifying Options in an Argp Parser":

    int key

    The integer key provided by the current option to the option parser. If key has a value that is a printable ASCII character (i.e., isascii (key) is true), it also specifies a short option -char, where char is the ASCII character with the code key.

    In other words, the key field of an option can be any int value, and if isascii(key) is nonzero, then it also specifies a short option—meaning you can use non-ASCII values (values outside the range 0x00..0x7F) to avoid the short option. Despite not being a short option, the value of key is still used as the value of the associated long option (e.g. --foo), so you'd handle it the same as any key/short option.

    O/T: I collect all of my option keys in an enum as constants, so I'm not wondering what option 0x100 represents in a switch, e.g. for GNU tar, it might be something like this for its compression options:

    enum compress_options {
        // Archive file extension determines compression program
        COMP_FILTER_AUTO = 'a',
        // Option arg is program used to deal with compression
        COMP_FILTER_ARG = 'I',
    
        COMP_FILTER_BZIP2 = 'j',
        COMP_FILTER_XZ = 'J',
        COMP_FILTER_GZIP = 'z',
        COMP_FILTER_COMPRESS = 'Z',
    
        COMP_FILTER_LZIP = 0x100,
        COMP_FILTER_LZMA,
        COMP_FILTER_LZOP,
    
        // Do not use archive suffix to determine compression program.
        COMP_FILTER_NOAUTO,
    };
    

    Then you'd just need to ensure that the next set of options uses 0x200, then 0x300, etc. to avoid issues with options having the same value. If you needed, you could also use 0x100, 0x180, 0x200, 0x280, etc. (e.g. 0x100 might represent a subcommand and 0x180 might be the first option for that subcommand).

    It's important to group the short options and non-short options separately. The implicitly assigned values in an enum depend upon the value of the last explicitly assigned value. Had I placed COMP_FILTER_NOAUTO immediately after COMP_FILTER_AUTO, the --no-auto-compress long option would have an associated short option -b, which it does not in reality.