Search code examples
cgetopt

getopt immediately exiting loop


I am trying to get getopt to work with my C program, but I have found that it is not working. Here is the function that doesn't work

char* getFlagArg(int argc, char **argv, char flag) {
 extern char *optarg;
 extern int optind, optopt, opterr;
 char opt;
 char options[3] = {flag,':',0};
 while((opt = getopt(argc, argv, options)) != -1) {
     if(opt == flag)
         return optarg;
 }
 return "";
}

When I run this code, it immediately exits the loop (the loop does not run even once). I can't figure out why this is happening. I have verified that argc, argv, and options are all what I expect them to be. Thoughts? Please and thank you!


Solution

  • The point I was trying to get at in the question's comments was this:

    char *arg;
    
    arg = getFlagArg (argc, argv, 'b');
    printf ("-b arg = %s\n", arg);
    arg = getFlagArg (argc, argv, 'u');
    printf ("-u arg = %s\n", arg);
    

    If you have called getFlagArg or getopt already, the second call will possibly fail. Imagine you had an option -b that accepted an argument, and the command line was ./a.out -u foo -b quux filename. Because you searched for -b first, optind will be 5, and searching for -u will fail because optind is greater than 1, which is the value optind must be to find the -u option in the example command line I provided.

    You will need to "reset" getopt by setting optind to 1. Of course, we would need to see the code calling getFlagArg if this isn't the problem.

    Edit

    Options without arguments are allowed to be in the same argv element. getopt can handle this, but if you have two options -a and -c, ./a.out -cau foo will work with getopt, but you cannot necessarily find -c after finding -a even by setting optind to 1 again. Only after you go through -u foo (or any other option requiring an argument) will you be able to reset optind and restart parsing.

    FreeBSD and likely some other BSD clones provide a nonstandard optreset variable to handle this sort of case. Glibc on Linux, however, does not, so beware of this strange "quirk" of getopt.