getopt does not parse optional arguments to parameters

32,508

I recently came across this issue myself. I arrived at a similar solution to the one Brian Vandenberg and Haystack suggested. But to improve readability and avoid code duplication, you can wrap it all up in a macro like below:

#define OPTIONAL_ARGUMENT_IS_PRESENT \
    ((optarg == NULL && optind < argc && argv[optind][0] != '-') \
     ? (bool) (optarg = argv[optind++]) \
     : (optarg != NULL))

The macro can be used like this:

case 'o': // option with optional argument
    if (OPTIONAL_ARGUMENT_IS_PRESENT)
    {
        // Handle is present
    }
    else
    {
        // Handle is not present
    }
    break;

If you are interested, you can read more about how this solution works in a blog post I wrote: https://cfengine.com/blog/2021/optional-arguments-with-getopt-long/

This solution is tested and is – at the time of this writing – currently used in CFEngine.

Share:
32,508
hayalci
Author by

hayalci

hayalci loves GNU, Linux, Python and KDE.

Updated on July 09, 2022

Comments

  • hayalci
    hayalci almost 2 years

    In C, getopt_long does not parse the optional arguments to command line parameters parameters.

    When I run the program, the optional argument is not recognized like the example run below.

    $ ./respond --praise John
    Kudos to John
    $ ./respond --blame John
    You suck !
    $ ./respond --blame
    You suck !
    

    Here is the test code.

    #include <stdio.h>
    #include <getopt.h>
    
    int main(int argc, char ** argv )
    {
        int getopt_ret, option_index;
        static struct option long_options[] = {
                   {"praise",  required_argument, 0, 'p'},
                   {"blame",  optional_argument, 0, 'b'},
                   {0, 0, 0, 0}       };
        while (1) {
            getopt_ret = getopt_long( argc, argv, "p:b::",
                                      long_options,  &option_index);
            if (getopt_ret == -1) break;
    
            switch(getopt_ret)
            {
                case 0: break;
                case 'p':
                    printf("Kudos to %s\n", optarg); break;
                case 'b':
                    printf("You suck ");
                    if (optarg)
                        printf (", %s!\n", optarg);
                    else
                        printf ("!\n", optarg);
                    break;
                case '?':
                    printf("Unknown option\n"); break;
            }
        } 
        return 0;
    }