Как можно определить, что требуемый аргумент опции отсутствует?

Я использую getopt_long на машине GNU/Linux. Инициализируйте список опций как:

static struct option long_options[] = {
     {"mode", required_argument, 0, 9},
     {0, 0, 0, 0}
};

Иметь следующую строку кода

c = getopt_long(argc, argv, "", long_options, index_ptr);

Когда я запускаю свою программу с командой:

prog --mode

Приведенная выше строка кода возвращает '?' в с, но не ':', как ожидается, в соответствии с getopt(3) Страница man: "Ошибка и возврат -1 такие же, как для getopt()"

Да, при использовании / разборе коротких опций можно написать в списке опций что-то вроде ":m:", чтобы переменная c в отсутствующем аргументе содержала ":", а не "?", Но что нужно сделать, чтобы различать два случая (отсутствует аргумент, недопустимая опция) при разборе только длинных опций?

Как можно отличить неверную опцию от опции с пропущенным обязательным аргументом?

2 ответа

Решение

Единственный способ, с помощью которого я могу достичь вашей цели - провести различие между недопустимым параметром и допустимым параметром с отсутствующим аргументом, - это установить has_arg поле структуры параметров для optional_argument, а затем проверить вручную на аргумент. затем getopt_long() вернет только значение '?' когда есть недопустимая опция, и вы можете проверить, есть ли у указанной опции аргумент, посмотрев в optarg, Вот пример:

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

int main(int argc, char *argv[])
{
    int i, opt;
    int index = -1;

    static struct option long_options[] = {
        {"mode", optional_argument, NULL, 'm'},
        {0, 0, 0, 0}
    };

    /* suppress error messages */
    //opterr = 0;

    while ((opt = getopt_long(argc, argv, "", long_options, &index)) != -1) {
        if (opt == '?') {
            /* do something, perhaps: */
            //printf("Invalid option \n");
            //      exit(EXIT_FAILURE);
        }
        if (opt == 'm' && optarg == NULL) {
            printf("Missing argument in '--mode' option\n");
            exit(EXIT_FAILURE);
        }        
    }

    return 0;
}

Это действительно досадно, что GNU getopt в этом случае не просто возвращает :( Он был так близок к правильному результату, но явно проверяет, существует ли :в короткой строке аргументов .

В моем альтернативном решении я использую этоoptoptустанавливается на соответствующийval. Это решает проблему с печатью обобщенного сообщения об отсутствующих аргументах опции, но почему-то кажется грязным. Я не проверял это слишком много, будьте осторожны. Он неправильно обрабатывает входные данные с одним-.

      #define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

int main(int argc, char *argv[])
{
    static int req, opt;
    static struct option long_options[] = {
        {"req_flag", required_argument, &req, 1},
        {"opt_flag", optional_argument, &opt, 1},
        {"req", required_argument, NULL, 'r'},
        {"opt", optional_argument, NULL, 'o'},
        {"none", no_argument, NULL, 'n'},
        {0, 0, 0, 0}
    };

    /* suppress getopt's own error messages */
    opterr = 0;

    int c, option_index;
    while ((c = getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
        printf("c=%c (%x), option_index=%d, optind=%d, optopt=%c (%x), optarg='%s'\n",
            c, c, option_index, optind, optopt, optopt, optarg);
        switch (c) {
            case 0:
                if (optarg != NULL) {
                    printf("flag for %s was set to %d (optarg=%s)\n",
                        long_options[option_index].name, *long_options[option_index].flag, optarg);
                    // the flag's value is probably useless in the case of req_flag because
                    // if it is required you probably want to change behavior depending
                    // on the value of optarg and not just its presence :)
                    // That (and also handling of optarg of optional flags) would need to
                    // be done here depending on option_index. I wouldn't recommend using this.
                } else {
                    printf("flag for %s was set to %d\n",
                        long_options[option_index].name, *long_options[option_index].flag);
                }
                break;
            case 'r':
                printf("%s=%s\n", long_options[option_index].name, optarg);
                break;
            case 'o':
                if (optarg == NULL) {
                    printf("%s given w/o argument\n", long_options[option_index].name);
                } else {
                    printf("%s=%s\n", long_options[option_index].name, optarg);
                }
                break;
            case '?':
                if (optopt == 0) {
                    printf("Invalid option: %s\n", argv[optind-1]);
                } else {
                    printf("Missing argument for long option %s\n", argv[optind-1]);
                }
                exit(EXIT_FAILURE);
        }
    }

    return 0;
}
Другие вопросы по тегам