Using getopt for required arguments

WToa picture WToa · Oct 20, 2012 · Viewed 7.8k times · Source

I currently have code that looks like this:

while (( flags = getopt(argc, argv, "abc")) != -1){
    switch(flags){
    case 'a':
        dflag = 1;
        break;
    case 'b':
        rflag = 1;
        break;
    case 'c':
        cflag = 1;
        break;
    }
}

The problem is I wanted to include something like testprogram -c -d 1

Where c is required to handle the -d, without -c, testprogram -d 1 will just run without arguments.

I tried a large variety of things and I just can't seem to get this to work.

Any help would be appreciated.

Answer

Jonathan Leffler picture Jonathan Leffler · Oct 20, 2012

I think there are two options available to you, one of which will work and one of which may or may not work.

The 'may or may not work' option would be exemplified by:

char *opts = "abc";
char *opts_d = "abcd:";

while ((opt = getopt(argc, argv, opts)) != -1)
{
    switch (opt)
    {
    case 'a':
        aflag = 1;
        break;
    case 'b':
        bflag = 1;
        break;
    case 'c':
        cflag = 1;
        opts = opts_d;
        break;
    case 'd':
        dflag = 1;
        dvalue = optarg;
        break;
    default:
        ...error handling...
        break;
    }
}

I'm not sure whether there's anything that prohibits you from changing the list of valid options on successive calls to [getopt()][1], but I do know it is not normally done to change the options as you go. So, treat with caution. Note that if the -c option is never found, the opt value of d will never be returned by getopt(), so that code will not be executed otherwise. Note that if the user enters a -d option before the -c, getopt() will report an invalid option when it processes the -d. You can control the error reporting; you would probably have to. (The optopt variable contains the actual option letter that was encountered as invalid.)

The 'will work' option is:

while ((opt = getopt(argc, argv, "abcd:")) != -1)
{
    switch (opt)
    {
    case 'a':
        aflag = 1;
        break;
    case 'b':
        bflag = 1;
        break;
    case 'c':
        cflag = 1;
        break;
    case 'd':
        if (cflag == 0)
            ...report error about must use -c option before -d option...
        dflag = 1;
        dvalue = optarg;
        break;
    default:
        ...error handling...
        break;
    }
}