Question

I have the following code:

void parse(char *commandLine) {
    int rc = 0;
    int argc = 0;
    char *cmdLine;
    char *argv[MAX_ARGS];
    filename = NULL;
    stdoutFilename = NULL;
    stderrFilename = NULL;
    cmdLine = strdup(commandLine);
    char *param = strtok(cmdLine, " ");
    while (param && argc < MAX_ARGS) {
        argv[argc++] = param;
        param = strtok(NULL, " ");
        printf("%s\n", argv[argc-1]);
    }
    free(cmdLine);
    scanOptions(argc, argv);
    printf("Filename %s\n", filename);

...

and

void scanOptions(int argc, char *argv[]) {
    int c ;
    while ((c = getopt (argc, argv, "Df:e:o:")) != -1) {
        switch (c) {
            case 'D': __debug = 1; break;
            case 'f': filename = strdup(optarg); break;
            case 'o': stdoutFilename = strdup(optarg); break;
            case 'e': stderrFilename = strdup(optarg); break;
            default: fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
        }
    }
}

filename, stdoutFilename and stderrFilename are global variables. If I call the parse method as:

parse("-ftest/testfile.txt") the variable filename is not set and the call to 
printf("Filename %s\n", filename); prints "Filename (null)".

What's wrong with that?

Was it helpful?

Solution

There's a few things wrong, that may or may not be the cause of your problem:

Use of freed memory

free(cmdLine);
scanOptions(argc, argv);

You can't free the cmdLine here, since your strtok() calls will assign pointers inside cmdLine to your argv. free() it after scanOptions() , though if you save any optarg pointers directly, they will point into space that you have free()'d - you use strdup() so youre safe in your case.

Resetting getopt()

If you have called getopt previously, you need to reset some of its variables so it can scan again, (see the getopt manpage for an explanation). You need to do:

optind = 0;

Wrong index in argv The first index in argv is by convention the program name, not any program arguments. So make sure your argv[0] isn't any of your arguments. But it needs to be a valid string and not e.g. a NULL pointer.

argv[1] should be the first argument.

Add a sentiel to argv

The traditional argv of main() ends with a NULL pointer, your emulated argv should too. After the while loop, do

argv[argc] = NULL;

OTHER TIPS

getopt(3) considers argv[0] to be the program name and so will only parse arguments for argv[1], argv[2], etc...

To make it work, init argc to 1 in parse() while you build your temporary array:

int argc = 1;

getopt expects the parameters to be stored in argv from index 1 on.

argv[0] by conventions is used by the program's name.

So you might like to change your code from:

int argc = 0;

to be:

int argc = 1;

I add the correct piece of code for reference:

    char *param = strtok(cmdLine, " ");
    argv[argc++] = "dummy";
    while (param && argc < MAX_ARGS) {
        argv[argc++] = param;
        param = strtok(NULL, " ");
    }
    scanOptions(argc, argv);
    free(cmdLine);

The solution is to add argv[argc++] = "dummy"; to fill argv[0] and to call free(cmdLine) after scanOptions.

I cannot add comments to your post. But i would like to know the following:-

why cant you call scanOptions() directly from Main.

scanOptions(argc, argv);

This is far to complicated and error phrone. You cannot maintain this. Use boost::program_options instead.

It will look like:

namespace po = boost::program_options;

boost::program_options::variables_map vars;

po::options_description options("Command line options");

options.add_options()
    ("help", "display this help message and exit")
    ("in", po::value<std::string>()->default_value("file1.txt"), "input file")
    ("out", "output file");

po::store(po::parse_command_line(argc, argv, options), vars);
po::notify(vars);

std::string infile = vars["in"].as<std::string>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top