Search code examples
cgetoptgetopt-long

error handling of getopt in C


I have a question about the error handling of getopt in C:

#include <unistd.h>
#include <getopt.h>

void showFunction()
{
   printf("show function\n");
}

void printHelp()
{
   printf("print help info\n");
}

#define HELP 1
#define SHOW_OPTION 2

int main(int argc, char *argv[])
{    
    const struct option long_opts[] = {{"help",      no_argument, NULL, HELP},
                                       {"show",      no_argument ,NULL, SHOW_OPTION},
                                       {NULL,   0,           NULL, 0}};
    int opt;

    while((opt = getopt_long_only(argc, argv, "", long_opts, NULL)) != -1)
    {
        switch(opt) {
            case HELP:
                printHelp();
                break;
            case SHOW_OPTION:
                showFunction();
                break;
            case '?':
                printHelp();
                break;
            default:
                printf("type base --help for details\n");
        }
    }
    return 0;
}

this part will handle some error:

case '?':
                printHelp();
                break;

but if I type ./base -- or ./base - or ./base sdfs or ./base -- fsfs, it can not handle all those invalid input, so how to handle the input above? Can anyone help?


Solution

  • getopt functions support not only options (e.g. -h or --help) but also so-called non-option arguments. E.g. if you write ./base --show arg1 arg2, then --show is an option, but arg1 and arg2 are non-option arguments. Also, you can explicitly put -- in your options to show that all argument after these dashes is a non-option argument.

    In your examples, options like -, sdfs, fsfs are non-option arguments. getopt_longonly (as well as other getopt functions) sets the optind extern variable to point to the first non-option element in the argv array.

    Let's go through your examples:

    ./base --: as -- is the special option that shows that everything after it is not an option, this command line is perfectly valid and is equal to calling ./base without any options.

    ./base -: the variable optind will have the value 1, and argv[1] is "-". It treats single dash - as a non-option argument.

    ./base -- fsfs: here the -- is ignored as it shows that after that there are only non-option arguments, and fsfs is the first non-option argument so optind will be equal to 2 and argv[2] is "fsfs".

    If you don't expect any non-option arguments, just check that the value of optind is equal to argc. If it is less then argc it means that you have some non-option argument:

    if (optind < argc) {
        /* at least one non-option argument exists */
        printHelp();
    }