tags:

views:

691

answers:

3

Hi All,

Can someone help me with the getopt fuction?

When i do the following in main:

char *argv1[] = {"testexec","-?"};
char *argv2[] = {"testexec","-m","arg1"};
int  cOption;
/* test for -? */

setvbuf(stdout,(char*)NULL,_IONBF,0);
printf("\n argv1 ");
while (( cOption = getopt (2, argv1, "m:t:n:fs?")) != -1) {
    switch(cOption){
        case 'm':
            printf("\n -m Arg : %s \n",optarg);
            break;
        case '?':
            printf("\n -? Arg ");
            break;
        case 'n':
            printf("\n -n Arg : %s \n",optarg);
            break;
    }
}

printf("\n argv2 ");

while (( cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) {
    switch(cOption){
        case 'm':
            printf("\n -m Arg : %s \n",optarg);
            break;
        case '?':
            printf("\n -? Arg : %s \n",optarg);
            break;
        case 'n':
            printf("\n -n Arg : %s \n",optarg);
            break;
    }
}

I'm running this code on rhel3 which uses old libc version. I dont know which one to be exact.

Now the problem is getopt doesn't work the second time with argv2. But if i comment out the first getopt call with argv1 , it works.

Can someone tell me what am i doing wrong here?

Thanks.

+5  A: 

argv1 and 2 must end in 0:

char* argv1[] = {"par1", "par2", 0};

Edit: OK, I read the getopt man page and I found this:

The variable optind is the index of the next element to be processed in argv. The system initializes this value to 1. The caller can reset it to 1 to restart scanning of the same argv, or when scanning a new argument vector.

So, making optind=1 between the two calls at getopt makes it work as expected.

Diego Sevilla
Good answer, but while that's certainly true, I tried changing it in the example code and it didn't fix the particular problem being asked about.
David Zaslavsky
David, you're right. I just spotted that error and forgot the rest :) I edited the answer, as I noticed that if you update the optind value to 1, the code works as expected. Regards
Diego Sevilla
Beware: the POSIX standard does not state that resetting optind to 1 will reset getopt() to the initial state, especially if you did not completely parse the first arguments. For example, if the first argument is -xy and you stop after processing x, there's no guarantee that a reset of optind works.
Jonathan Leffler
+3  A: 

The getopt() function uses some global variables, like optind and optarg, to store state information between calls. After you finish processing one set of options, there is data left in those variables that is causing problems with the next set of options. You could potentially try to reset getopt's state between calls by clearing the variables, but I'm not sure that would work since the function might use other variables which aren't documented and you'd never know if you'd gotten them all; besides, it would be absolutely nonportable (i.e. if the implementation of getopt() changes, your code breaks). See the man page for details. Best not to use getopt() for more than one set of arguments in a given program if you can help it.

I'm not sure if there is an actual function to reset getopt's state (or perhaps a reentrant version of the function, which lets you store the state in your own variables)... I seem to remember seeing something like that once, but I can't find it now that I look :-/

David Zaslavsky
A: 

Is there any reason why you are not using getopt_long() instead? On most platforms, getopt() just calls _getopt_long() with a switch to disable long arguments. That's the case with almost every platform that I know of (still in use), including Linux, BSD and even emerging OS's like HelenOS -, I know, I was the one who ported getopt to its libc :)

It is much easier on ANYONE using your program to have long options at least until they get used to using it.

getopt_long() will allow you to use two (or more) option indexes that can stay 'live' after they are done processing arguments, only the internal (global, non-reentrant) one would have to be re-set which is no big deal.

This lets you easily compare the argument count to the number of options actually passed in both invocations with many other benefits .. please consider not using the antiquated interface.

Look at getopt.h, you'll see what I mean.

Tim Post
Define most platforms? HP-UX, Solaris, AIX - getopt() does not call getopt_long(). That's 3 of 6 Unix variants (BSD, Linux, MacOS X being the others that matter).
Jonathan Leffler