MrWolvwxyz
MrWolvwxyz

Reputation: 93

optarg set to null

I am attempting to use atoi on optarg but it might as well be anything. I have been trying to figure out why my getopt_long is not working. When I enter my switch statement optarg is set to null and it stays that way. I have checked my colons and they are correct. This is my code.

static struct option long_options[] = 
    {
        {"algorithm", required_argument, 0, 'a'},
        {"reverse", no_argument, 0, 'r'},
        {"key", required_argument, 0, 'k'},
        {"output", required_argument, 0, 'o'},
        {"help", no_argument, 0, 'h'},
        {"version", no_argument, 0, 'V'},
        {0, 0, 0, 0}
    };

int option_index = 0;
int c;
//Getopt to get the correct options from the command line.
while ((c = getopt_long(argc, argv, "a:rk:o:hV", long_options, 
        &option_index)) != -1)
{
    bool endOption = false;

    if (endOption) break;

    switch (c) 
    {
        case 0:
        {
            endOption = true;
            break;
        }
        case 'a':
        {
            if (optarg == "insertion") algorithm = 0;
            break;
        }

        case 'r':
        {
            reverseFlag = true;
            break;
        }
        case 'k':
        {
            while (optarg != " ")
            {
                if (optarg == ",")
                {
                    optarg++;
                }
                else 
                {
                    sortOrder.push_back(atoi(optarg)); //error here
                    optarg++;
                }
            }
        }
        case 'o':
        {
            fileFlag = true;
            break;
        }
        case 'h':
        case 'V':
        default:
        {
            cerr<<"You have entered an incorrect flag, do it better"<<endl;
            break;
        }
    }
}

//more stuff//

I have tried using double colons and just about everything else.

Upvotes: 1

Views: 3376

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754190

You can't compare strings like this:

 if (optarg == "insertion") algorithm = 0;

You need to use strcmp() or equivalent, like this:

if (strcmp(optarg, "insertion") == 0) algorithm = 0;

There may be other problems, but that springs to mind immediately.


Tinkering with optarg doing optarg++ is probably not a good idea. That is information from the function to you; it is dodgy changing it. You could take a copy of the pointer and then increment that, stepping through the string it points at. There is certainly no guarantee that there will be a space in the argument for -k, and that is likely the source of your trouble, along with the misuse of character pointer comparisons instead of using strcmp() or equivalent.

You seem to be missing a break after case 'k':.

The bool endOption inside the body of the loop is odd: it get set to false on each iteration; it is tested while it is still false, so the break is not executed; it is set to true when getopt_long() returns 0; but the value is reset before the next iteration. You should probably declare this variable outside the main while ((c = getopt_long(...)) != -1) loop. Then it will behave sensibly (though you should probably terminate the loop if it is set before calling getopt_long() again - so maybe the condition on it should be at the bottom of the main while loop.


Changing the loop test in -k handling to while (strcmp(optarg, "") != 0) (the key difference is a missing space between the two double quotes), and then I get sane behaviour out of it. Notice how I've instrumented the options so that I can see what is being executed. When I ran with the comparison to a string containing a space, I got a fancy dump of my environment before the loop terminated. That's the sort of thing that leads to core dumps.

#include <getopt.h>
#include <vector>
#include <iostream>
#include <cstdlib>
using namespace std;

static struct option long_options[] = 
{
    {"algorithm", required_argument, 0, 'a'},
    {"reverse", no_argument, 0, 'r'},
    {"key", required_argument, 0, 'k'},
    {"output", required_argument, 0, 'o'},
    {"help", no_argument, 0, 'h'},
    {"version", no_argument, 0, 'V'},
    {0, 0, 0, 0}
};

int main(int argc, char **argv)
{
    vector<int> sortOrder;
    int option_index = 0;
    int c;
    bool reverseFlag = false;
    int algorithm = 1;
    bool fileFlag = false;

    //Getopt to get the correct options from the command line.
    while ((c = getopt_long(argc, argv, "a:rk:o:hV", long_options, &option_index)) != -1)
    {
        bool endOption = false;

        if (endOption) break;

        switch (c) 
        {
            case 0:
                    cerr << "Found 0 value\n";
                    endOption = true;
                    break;
            case 'a':
                    cerr << "Found -a option: " << optarg << endl;
                    if (strcmp(optarg, "insertion") == 0)
                        algorithm = 0;
                    break;
            case 'r':
                    cerr << "Found -r option\n";
                    reverseFlag = true;
                    break;
            case 'k':
                    cerr << "Found -k option: " << optarg << endl;
                    while (strcmp(optarg, "") != 0)
                    {
                        if (strcmp(optarg, ",") == 0)
                            optarg++;
                        else 
                        {
                            cerr << "pushback <<" << optarg << ">>\n";
                            sortOrder.push_back(atoi(optarg)); //error here
                            optarg++;
                        }
                    }
                    break;
            case 'o':
                    cerr << "Found -o option: " << optarg << endl;
                    fileFlag = true;
                    break;
            case 'h':
            case 'V':
            default:
                    cerr << "You have entered an incorrect flag, do it better" << endl;
                    break;
        }
    }
}

When that's run as:

./getopt -k 2,1

I got the output:

Found -k option: 2,1
pushback <<2,1>>
pushback <<,1>>
pushback <<1>>

It might be that you want to change the comparison from:

if (strcmp(optarg, ",") == 0)

to:

if (*optarg == ',')

You might even reasonably change the loop condition to:

while (*optarg != '\0')

thus avoid strcmp() altogether. Incidentally, I'm not sure which header pulled in <cstring>, but one of them did.


For the record, I'm testing on a Mac Mini running MacOS X 10.7.2 (Lion) and using the provide G++ compiler, i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00).

Upvotes: 2

Related Questions