3

I'm writing a simple code making use of *argv[] parameter. I'd like to know whether I can use getopt() function for the following intent.

./myprogram -a PATH
./myprogram PATH

The program can either take merely PATH (e.g. /usr/tmp) or take -a option in addition to PATH. Can getopt() be used for this state? If can, how?

2 Answers2

4

The program can either take merely PATH (e.g. /usr/tmp) or take option in addition to PATH. Can getopt() be used for this state? If can, how?

Certainly. I'm not sure where you even see a potential issue, unless its that you don't appreciate POSIX's and getopt()'s distinction between options and arguments. They are related, but not at all the same thing.

getopt() is fine with the case that no options are in fact specified, and it gives you access to the non-option arguments, such as PATH appears to be for you, regardless of how many options are specified. The usual usage model is to call getopt() in a loop until it returns -1 to indicate that no more options are available from the command line. At each step, the global variable optind variable provides the index of the next argv element to process, and after getopt() (first) returns -1, optind provides the index of the first non-option argument. In your case, that would be where you expect to find PATH.

int main(int argc, char *argv[]) {
    const char options[] = "a";
    _Bool have_a = 0;
    char *the_path;
    int opt;

    do {
        switch(opt = getopt(argc, argv, options)) {
            case -1:
                the_path = argv[optind];
                // NOTE: the_path will now be null if no path was specified,
                //       and you can recognize the presence of additional,
                //       unexpected arguments by comparing optind to argc
                break;
            case 'a':
                have_a = 1;
                break;
            case '?':
                // handle invalid option ...
                break;
            default:
                // should not happen ...
                assert(0);
                break;
        }
    } while (opt >= 0);
}
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Sir what do you mean by saying `Certainly. I'm not sure where you even see a potential issue, unless its that you don't appreciate POSIX's and getopt()'s distinction between options and arguments. They are related, but not at all the same thing.` ? I don't know whether there is/are difference(s) between POSIX's and getopt()'s options and args. Shouldn't I use getopt() for such a case? – Soner from The Ottoman Empire Mar 07 '19 at 14:19
  • @snr, you can totally use `getopt()` for your case, as indeed my example code demonstrates. I was simply venturing a wild guess about why you're uncertain about that being so, and it sounds like I may have been right. Options, arguments to options, and non-option arguments are all conveyed to your program *via* its arguments, but options are not themselves arguments, nor do they necessarily map to arguments in 1:1 fashion. Options correspond to and are represented by individual option letters, not whole arguments, and `getopt()` can distinguish these from non-option arguments. – John Bollinger Mar 07 '19 at 14:28
3

Using an optstring of "a" allows an argument of -a to act as a flag.
optind helps detect that only one additional argument is present.
The program can be executed as ./program -a path or ./program path

#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    char op = ' ';//default value
    int opt;

    while ((opt = getopt(argc, argv, "a")) != -1)//optstring allows for -a argument
    {
        switch (opt)
        {
        case 'a':
            op = 'a';//found option, set op
            break;
        default:
            fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
            return 1;
        }
    }
    if ( optind + 1 != argc)//one argument allowed besides optstring values
    {
        fprintf(stderr, "Usage: %s [-a] PATH\n", argv[0]);
        return 1;
    }

    printf("%s %c\n", argv[optind], op);
    return 0;
}
xing
  • 2,125
  • 2
  • 14
  • 10
  • Note that recognizing options that are presented after a non-option argument is an extension. POSIX-conforming `getopt()` does not do that. GNU `getopt()`, which behaves as you describe by default, might *also* not do that, depending on the option string and on the process's environment. – John Bollinger Mar 07 '19 at 14:09