0

So, I have next code:

#include<unistd.h>
#include<getopt.h>
#include<getopt.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

// #include"main.hpp"
// #include"functions.cpp"

int main(int argc, char** argv) {
    
    opterr = 0;

    int f_verbose = false;

    int option_index = 0;
    
    static struct option long_options[] = 
        {
            {"file", required_argument, NULL, 'f'},
            {"verbose", no_argument, NULL, 'v'},
            {"help", no_argument, NULL, 'h'},
            {"version", no_argument, NULL, 1},
            {NULL, 0, NULL, 0},
        };

    int arg;
    char* file_path = NULL;

    while( -1 != (arg = getopt_long(argc, argv, ":f:hv", long_options, &option_index)) ) {
        switch(arg) {
//          case 0: // long options
//              if (long_options[option_index].flag != 0)
//                  break;

            case ':':
                fprintf(stderr, "No argument(s) provided for '%s' option.\n", argv[optopt]);
//              read_help(*argv);
                exit(EXIT_FAILURE);

            case '?':
                fprintf(stderr, "Unknown option: '%s'.\n", argv[optopt]);
//              read_help(*argv);
                exit(EXIT_FAILURE);

            case 'f':
                errno = 0;
                file_path = (char*)malloc(sizeof(*optarg)*(strlen(optarg) + 1));
                if (file_path == NULL) {
                    fprintf(stderr, "Could not allocate memory: %s\n", strerror(errno));
                    exit(EXIT_FAILURE);
                }
                break;

            case 'v': 
                f_verbose = true;
                break;

            case 'h':
                printf("Usage: %s -f filename [-v | --verbose] [-h | --help]\n"
                       "\n"
                       "Avaliable options:\n"
                       "  -f, --file <filename>\n"
                       "      Get lines coordinates from <filename>.\n"
                       "  -v, --verbose\n"
                       "      Print execution time\n"
                       "  -h, --help\n"
                       "      Print help message\n"
                       "  --version\n"
                       "      Print version.\n"
                       "\n"
                       "Program purpose:\n" 
                       "You should pass filename of file, first\n"
                       "two strings containing two numbers of 2D\n"
                       "plane coordinates of lines ends in each.\n"
                       "Program have to calculate and print lines\n" 
                       "interception coordinates, if there is some.\n",
                       *argv);
                exit(EXIT_SUCCESS);

            case 1: // --version
                printf("v1.0, mod 3, NAU, Vladyslav Rehan, 2023.\n");
                exit(EXIT_SUCCESS);

            default:
                printf("ENTERED DEfAULT\n");
                abort();
        }
    }
    printf("END\n");
}

When I compile it and pass bad option, I get segmentation fault or Unknown option error provided by getup_long I guess:

➜  Mod_1 g++ main.cpp
➜  Mod_1 ./a.out --unknown
Unknown option: './a.out'.
➜  Mod_1 ./a.out -a
[1]    18507 segmentation fault  ./a.out -a
➜  Mod_1 ./a.out -c
[1]    18517 segmentation fault  ./a.out -c
➜  Mod_1 ./a.out --what
Unknown option: './a.out'.
➜  Mod_1 ./a.out -v
END
➜  Mod_1 ./a.out --version
v1.0, mod 3, NAU, Vladyslav Rehan, 2023.
➜  Mod_1 ./a.out --v
Unknown option: './a.out'.
➜  Mod_1 what is happening

Same, but as a photo

Why I get Unknown option: './a.out'. if I have set opterr = 0;? Why there is segmentation fault?

And, I do now about optind-1 trick, but it wont work properly with ./a.out -ac for example:

➜  Mod_1 ./a.out -ac
Unknown option: './a.out'.

Again some mysterious error message appears.

I have already reviewed GNU Clib doc ten times, it says that getopt_long works the same as getopt so opterr = 0; and int optopt should make sense. Or I am misunderstanding something? How to detect type (long option or short option) of bad option?

  • `optopt` stores the character of the bad option (like `'a'` if you pass `-a`), not the index. You should not be using it as an array index like `argv[optopt]` – xnsc Apr 01 '23 at 23:00

2 Answers2

0

First, f_verbose should be a bool not an int. So, to do that you should just add the library stdbool, by doing #include <stdbool.h>. Also, you can't pass : and the ? as arguments. Normally, after that it should be working.

user16217248
  • 3,119
  • 19
  • 19
  • 37
  • I can include `:` to `optstring. Short cutout of GNU Clib reference manual: "If the first character of options is a colon (‘:’), then getopt returns ‘:’ instead of ‘?’ to indicate a missing option argument." – Vladyslav Rehan Apr 02 '23 at 08:21
  • Also, from the same manual about option struct `int *flag`, `int val` are ints so `f_verbose` should be int. otherwise I couldn't distinguish more than two long options that dont have short option equivalent, because bool is only 0 and 1. – Vladyslav Rehan Apr 02 '23 at 08:26
0

This was solved as:

#include<unistd.h>
#include<getopt.h>
#include<getopt.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

// #include"main.hpp"
// #include"functions.cpp"

int main(int argc, char** argv) {
    
    opterr = 0;

    int f_verbose = false;

    int option_index = 0;
    
    static struct option long_options[] = 
        {
            {"file", required_argument, NULL, 'f'},
            {"verbose", no_argument, NULL, 'v'},
            {"help", no_argument, NULL, 'h'},
            {"version", no_argument, NULL, 1},
            {NULL, 0, NULL, 0},
        };

    int arg;
    char* file_path = NULL;

    while( -1 != (arg = getopt_long(argc, argv, ":f:hv", long_options, &option_index)) ) {
        switch(arg) {
//          case 0: // long options
//              if (long_options[option_index].flag != 0)
//                  break;

            case ':':
                if (long_options[option_index].has_arg == required_argument)
                    fprintf(stderr, "No argument(s) provided for '--%s' long option.\n",  long_options[option_index].name);
                else
                    fprintf(stderr, "No argument(s) provided for '-%c' option.\n", optopt);
        //      read_help(*argv);
                exit(EXIT_FAILURE);

            case '?':
                if (optopt == 0)
                    fprintf(stderr, "Unknown long option: '%s'.\n", argv[optind-1]);
                else
                    fprintf(stderr, "Unknown option: '-%c'.\n", optopt);
            //  read_help(*argv);
                exit(EXIT_FAILURE);

            case 'f':
                errno = 0;
                file_path = (char*)malloc(sizeof(*optarg)*(strlen(optarg) + 1));
                if (file_path == NULL) {
                    fprintf(stderr, "Could not allocate memory: %s\n", strerror(errno));
                    exit(EXIT_FAILURE);
                }
                break;

            case 'v': 
                f_verbose = true;
                break;

            case 'h':
                printf("Usage: %s -f filename [-v | --verbose] [-h | --help] [--version]\n"
                       "\n"
                       "Avaliable options:\n"
                       "  -f, --file <filename>\n"
                       "      Get lines coordinates from <filename>.\n"
                       "  -v, --verbose\n"
                       "      Print execution time\n"
                       "  -h, --help\n"
                       "      Print help message\n"
                       "  --version\n"
                       "      Print version.\n"
                       "\n"
                       "Program purpose:\n" 
                       "You should pass filename of file, first\n"
                       "two strings containing two numbers of 2D\n"
                       "plane coordinates of lines ends in each.\n"
                       "Program have to calculate and print lines\n" 
                       "interception coordinates, if there is some.\n",
                       *argv);
                exit(EXIT_SUCCESS);

            case 1: // --version
                printf("v1.0, mod 3, NAU, Vladyslav Rehan, 2023.\n");
                exit(EXIT_SUCCESS);

            default:
                printf("ENCOUNTERED deFAULT\n");
                abort();
        }
    }
    printf("END\n");
}