1

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?

afenster
  • 3,468
  • 19
  • 26
ratzip
  • 1,571
  • 7
  • 28
  • 53

1 Answers1

0

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();
}
afenster
  • 3,468
  • 19
  • 26
  • yes, but some command may have non-option arguments, for example, it is valid to call the command list "base -show 1 1", but if I add this if (optind < argc) { /* at least one non-option argument exists */ printHelp(); }, it will print the help info for all the vaild input – ratzip Oct 15 '14 at 13:48
  • The point is that `getopt` just cannot validate non-option arguments so if it sees something that does not look like an option, e.g. `fsfs`, it skips this parameter. You should validate non-option arguments manually. – afenster Oct 15 '14 at 13:50
  • in linux, looks like the optind is not increased, if the input is base -show 1 1, the optind is 2 after the while, and base -- the optind is also 2, how to slove it – ratzip Oct 15 '14 at 14:54
  • It is always equal to the position of the first non-option argument. In `-show 1 1` it points to the first 1, in `--` it points to the NULL value as there are no non-option arguments. – afenster Oct 15 '14 at 15:37