0

Hey I have a function to check the given arguments for my program.

I want to get the long-name of the given users argument. Problem is currently he gives me weird high numbers example 32758 while my struct has only 9 elements...

I have to use it for university otherwise I would use the boost library....

#include <iostream>
#include <getopt.h>

int main(int argc, char *argv[])
{
    // Standard directories
    std::string outputDir = "PROJECT_PATH\\output\\"; /**< Output directory */

    // Options
    const struct option longOptions[3] = {
        {"output-dir", required_argument, nullptr, 'O'},
        {"help", no_argument, nullptr, 'h'},
        {nullptr, 0, nullptr, 0}};

    int opt;
    int option_index;
    while ((opt = getopt_long(argc, argv, "O:h", longOptions, &option_index)) != -1)
    {
        std::cout << "Long option index: " << option_index << std::endl;
        std::cout << "Option name: " << longOptions[option_index].name << std::endl;
        switch (opt)
        {
        case 'O':
            outputDir = optarg;
            break;
        case 'h':
            // printHelpText();
            exit(0);
        case '?':
            if ((optopt == 'O' || optopt == 'h'))
            {
                std::cout << "OK ... option '-" << static_cast<char>(optopt) << "' without argument"
                          << std::endl;
                exit(1);
            }
            else if (isprint(optopt))
            {
                std::cerr << "ERR ... Unknown option -" << static_cast<char>(optopt) << std::endl;
                exit(-1);
            }
            else
            {
                std::cerr << "ERR ... Unknown option character \\x" << static_cast<char>(optopt) << std::endl;
                exit(-1);
            }
        }
    }
    return 0;
}
Muddyblack k
  • 314
  • 3
  • 16
  • You didn't initialize most of the `longOptions` array at all, causing undefined behavior when the uninitialized array elements are accessed by `getopt_long`. – user17732522 Jun 04 '23 at 12:23
  • 2
    Now the array is too small and your constructor writes out-of-bounds to it, again causing undefined behavior. Please show only code that you actually tested _exactly_ as is. – user17732522 Jun 04 '23 at 12:25
  • Sorry yeah must be of length 3. Man I should take more time for checking the created minimalist code. I am sorry for that. Should be it now – Muddyblack k Jun 04 '23 at 12:26
  • So, did you actually test that the unexpected behavior still occurs exactly in the same way with the modified code? The number `32758` is actually one that is produced in your new test? What was the command line you test with? – user17732522 Jun 04 '23 at 12:27
  • You can initialize the array and its members inline directly. Or in the constructor initializer list like you do with `argc` and `argv`. – Some programmer dude Jun 04 '23 at 12:27
  • 1
    OT: Please take some time to think about the condition `(optopt == 'O' || optopt == 'h') && isprint(optopt)`. If `optopt` is equal to `'O'` or `'h'` then it's by definition printable as well. – Some programmer dude Jun 04 '23 at 12:30
  • Thank you for your tips. But after correction I still wont get the correct index of the arguments. – Muddyblack k Jun 04 '23 at 12:36
  • 1
    Is that really the _smallest_ code that shows the problem? You shouldn't need a `class` to demonstrate this - a simple function call should be sufficient. – Toby Speight Jun 04 '23 at 12:37
  • 1
    Your `"Long option index"` output, what does it show? What did you expect? And where do you want to get the long option? Please try to create a [mre] that demonstrates what you're really trying to do. – Some programmer dude Jun 04 '23 at 12:41
  • @TobySpeight Yes you are right I correct it – Muddyblack k Jun 04 '23 at 12:41

2 Answers2

4

Looking at the documentation and source code for getopt_long() it does not seem to calculate the index of the long option if it parses a short option so you are seeing uninitialized data in option_index.

It will only be filled with data if a long option is actually present.

If you need this value, write your own loop through the array looking for the returned short option.

Here is a link to getopt_long() in android copied from BSD. I would assume this is the same on all other platforms.

https://android.googlesource.com/platform/bionic/+/a27d2baa/libc/unistd/getopt_long.c

Erik Elmgren
  • 760
  • 1
  • 4
  • 21
0

Okay well you have to differ between the short and long options. And if using an option that requires an argument you have to add one to get a result.

std::cout << "Long option index: " << option_index << std::endl;
if (option_index > options_amount - 1)
{
    std::cout << static_cast<char>(optopt) << std::endl;
}
else
{
    std::cout << "Option name: " << longOptions[option_index].name << std::endl;
}

Here if you forget to add the path for --output-dir

mini.exe --output-dir
option requires an argument -- output-dir
Long option index: 32758
O
OK ... option '-O' without argument

With argument if works fine:

mini.exe --output-dir ./hello
Long option index: 0   
Option name: output-dir
Muddyblack k
  • 314
  • 3
  • 16