Опция getopt_long() с необязательным аргументом

Я пытаюсь создать опцию с необязательным аргументом, используя getopt_long().

Вот мой код:

static struct option long_options[] = {
   {"help",   no_argument,      NULL, 'h'},
   {"debug",  no_argument,      NULL, 'd'},
   {"config", optional_argument, NULL, 'c'},
   {NULL, 0, NULL, 0}
};

while ((ch = getopt_long(argc, argv, "hdc::", long_options, NULL)) != -1) {
        // check to see if a single character or long option came through
        switch (ch) {
            case 'h':
                opt.help = true;
                break;
            case 'd':
                opt.debug = true;
                break;
            case 'c':
                printf("C-Option: %s\n", optarg);
                if (optarg != NULL) {
                    opt.configFile = optarg;
                }
                break;
        }
    }

Я пытаюсь аргументировать -c необязательно, поэтому вы можете запустить программу с этими параметрами:

-c test.cfg -> optarg = "test.cfg"

-c -> optarg = null

Если я установлю c:: чем optarg всегда null,

Если я установлю c: чем я получаю ошибку: option requires an argument -- 'c'

Что я не прав? Есть ли другие варианты, которые я могу установить?

1 ответ

Решение

Из справочных страниц:

Если опция имеет необязательный аргумент, он должен быть записан непосредственно после символа опции, если он присутствует.

Ваш код работает как положено:

./a.out -c some_argument --> "C-Option: (null)"
./a.out -csome_argument  --> "C-Option: some_argument"
./a.out -c=some_argument --> "C-Option: =some_argument"

Вы можете рассмотреть добавление необязательных имен аргументов с помощью '=', как в приведенном выше примере. Вот еще один вопрос, который обсуждает проблему.

ОБНОВИТЬ

Я видел хорошее решение этой проблемы в ссылке на другой вопрос, упомянутый выше. Идея состоит в том, чтобы проверить, следуя опции, которая принимает аргумент, чтобы увидеть, если следующая строка в argv[] это вариант. Если нет, то предполагается, что это аргумент. Затем аргумент обрабатывается, и optind продвигается соответственно. Вот как эта идея может быть применена к вашей проблеме:

case 'c':
            if (optarg == NULL && argv[optind] != NULL
                && argv[optind][0] != '-') {            // not an option
                printf("C-Option: %s\n", argv[optind]);
                opt.configFile = argv[optind];
                ++optind;
            } else {  // handle case of argument immediately after option
                printf("C-Option: %s\n", optarg);
                if (optarg != NULL) {
                    opt.configFile = optind;
            }
            break;

Этот код приведет к следующему выводу:

./a.out -csome_argument  --> "C-Option: some_argument"
./a.out -c some_argument --> "C-Option: some_argument"
Другие вопросы по тегам