Search code examples
c++getopt

Using getopt when options have options C++


I am using getopt to parse command line arguments and my issue is that some of my options have options. My project is to test different backend implementations of maps and the -b flag specifies which implementation to use. Most of the options are straight forward but for the backends that use hash tables (chained and open) there is an additional -number that can be added to the end to specify the load factor. So it would be -b chained-0.75.

My idea is that I would take the substring from 8 to the end (or 5 for the "open" option) because that would ignore the "chained-" part of the string and then use atof() to convert it to a double and then declare my map. I believe optarg is a char array (?) and I keep running into type mismatch errors even though I have tried std::string str(optarg); I also don't know what to write in place of else if (strcasecmp(optarg, "chained") == 0) because there could be any number at the end of it. So right now when I do -b chained-0.75 it calls the usage function.

Here is what I have so far:

while ((c = getopt(argc, argv, "hb:n:p:")) != -1) {
    switch (c) {
        case 'b':
            if (strcasecmp(optarg, "unsorted") == 0) {
                map = new UnsortedMap();
            } else if (strcasecmp(optarg, "sorted") == 0) {
                map = new SortedMap();
            } else if (strcasecmp(optarg, "bst") == 0) {
                map = new BSTMap();
            } else if (strcasecmp(optarg, "unordered") == 0) {
                map = new UnorderedMap();
            } else if (strcasecmp(optarg, "chained") == 0) {
                double load_factor;
                std::string str(optarg);
                std::string ld_str = str.substr(8, str.length()-1);
                load_factor = atof(ld_str);
                map = new ChainedMap(load_factor);
            } else if (strcasecmp(optarg, "open") == 0) {
                map = new OpenMap();
            } else {
                usage(1);
            }
            break;

Any hints or ideas would be appreciated!


Solution

  • strcasecmp() is an exact match comparison function, this strcasecmp() will obviously not match "chained-0.75". The only thing that strcasecmp() will match against the string "chained" is "chained", not "chained-0.75", not "changed-foobar", not "chained-anything".

    The right function is strncasecmp:

    } else if (strncasecmp(optarg, "chained-", 8) == 0) {
    

    Note that you're comparing against "chained-", and not just "chained". A few moments' of thinking should make it clear why.

    The existing code also fails to take into account the possibility that the string after "chained-" is not a number, since atof() does not handle parsing errors. If you need to be able to detect and handle an error here, use strtod() instead of atof().