cgcccommand-lineposixgetopt

Parsing a list of parameters built programmatically does not work with getopt


I am running a C program like this:

int main(int argc, char **argv)
{
    int opt;

    // Normal command line parsing
    while ((opt = getopt(argc, argv, "s")) != -1)
        printf("app opt %c\n", opt);

    // "Simulate" the command line compiling the argument list manually
    char optarr0[100];
    char optarr1[100];
    strcpy(optarr0, "./myapp");
    strcpy(optarr1, "-s");
    char *man_argv[2];
    int man_argc = 2;
    man_argv[0] = optarr0;
    man_argv[1] = optarr1;  
    while ((opt = getopt(man_argc, man_argv, "s")) != -1)
        printf("man opt %c\n", opt);

    printf("done\n");

    return 0;
}

Where I am trying to supply arguments to POSIX getopt manually instead of getting them from the main parameters argc and argv, from the actual command line.

The runtime system is uCLinux for Blackfin ADSP-BF518 processor. Linux version is:

Linux blackfin 2.6.35.13 #204 Tue Oct 31 13:34:19 CET 2017 blackfin GNU/Linux

and I am cross-compiling the application in a Lubuntu 12.04 system with gcc 4.6.3.

The problem is that the output of the program is:

root:/home> ./myapp -s
app opt s
done

instead of the expected one:

root:/home> ./myapp -s
app opt s
man opt s
done

The application even crashes when called with an additional invalid parameter:

root:/home> ./myapp -s -c

What could be the problem?


Solution

  • The getopt function uses a global variable called optind, initialized to 1, to keep track of the current option it is processing on successive calls. When you call getopt again on your rebuilt list of arguments, the value of optind is 3 so that's where it starts in your set of arguments.

    You need to reset this to 1 before calling getopt on your argument list. Also, the argument list needs to be NULL terminated:

    char *man_argv[3] = { optarr0, optarr1, NULL };
    int man_argc = 2;
    optind = 1;
    while ((opt = getopt(man_argc, man_argv, "s")) != -1)
        printf("man opt %c\n", opt);