'Passing Negative Numbers into Getopt

I need to pass negative numbers into getopt and I was wondering if there is a simple way to change the prefix used by getopt (i.e. '-' character to flag in the case statement) into a different character like '--' or '+'.

Do I need to use Getopt::Long to change the prefix?



Solution 1:[1]

Using -- (e.g. yourcommand <actual options> -- -5) will allow you to pass negative arguments in cases where you don't have control of the code. The man page for getopt states

The special argument "--" forces an end of option-scanning regardless of the scanning mode.

Solution 2:[2]

I dont believe there is a way to change the command line argument prefix to be anything other than - (or -- when using getopt_long()). However, if you need to pass a negative number, you should define the argument as 'required_argument'. For example, here's a short GetOpt method that uses the getopt_long_only method to get the command line arguments:

// personaldetails.cpp

// compile with:
// g++ -std=c++11 personaldetails.cpp -o personaldetails
#include <iostream>
#include <string>
#include <vector>
#include <getopt.h>

int main (int argc, char** argv)
{
    // Define some variables
    std::string name = "" ;
    int age = 0 ;
    double weight = 0.0 ;

    // Setup the GetOpt long options.
    std::vector<struct option> longopts ;
    longopts.push_back({"Name",  required_argument, 0, 'N'}) ; 
    longopts.push_back({"Age",   required_argument, 0, 'A'}) ; // <- IMPORTANT
    longopts.push_back({"Weight",required_argument, 0, 'W'}) ; // <- IMPORTANT
    longopts.push_back({0,0,0,0}) ;

    // Now parse the options
    while (1)
    {
        int c(0) ;
        int option_index = -1;

        c = getopt_long_only (argc, argv, "A:N:W:",
                              &longopts[0], &option_index);

        /* Detect the end of the options. */
        if (c == -1) break;

        // Now loop through all of the options to fill them based on their values
        switch (c)
        {
            case 0:
                /* If this option set a flag, do nothing else now. */
                break ;
            case '?':
                // getopt_long_omly already printed an error message.
                // This will most typically happen when then an unrecognized
                // option has been passed.
                return 0 ;
            case 'N':
                name = std::string(optarg) ;
                break ;
            case 'A':
                age = std::stoi(optarg) ;
                break ;
            case 'W':
                weight = std::stod(optarg) ;
                break ;
            default:
                // Here's where we handle the long form arguments
                std::string opt_name( longopts[option_index].name ) ;
                if (opt_name.compare("Name")==0) {
                    name = std::string(optarg) ;
                } else if (opt_name.compare("Age")==0) {
                    age = std::stoi(optarg) ;
                } else if (opt_name.compare("Weight")==0) {
                    weight = std::stod(optarg) ;
                }
                break ;
        }
    }

    // Print the persons details
    std::cout << "Name  : " << name << std::endl;
    std::cout << "Age   : " << age << std::endl;
    std::cout << "Weight: " << weight << std::endl;

    return 0 ;
}

The key part here is that in longopts I've set the parameters I'm going to convert to integer and double to have required_argument. This tells GetOpt to expect another parameter after you've declared it on the command line. This means that GetOpt will read in the argument after your command line parameter as the argument to that command line parameter. For the case where we want to pass the single char argument (i.e. -N, -A, or -W), this is where passing "N:A:W:" to getopt is important. The : basically does the same thing for the single char parameter as required_argument does for the long form.

Running the script I can do:

$ ./personaldetails -Name Sally -Age -45 -Weight 34.5
Name  : Sally
Age   : -45
Weight: 34.5

$./personaldetails -N Sally -A -45 -W -34.5
Name  : Sally
Age   : -45
Weight: -34.5

Note that because the script uses getopt_long_only() I can pass the long form of the argument parameters with a single -.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Thav
Solution 2 Jvinniec