Где getopt_long хранит нераспознанную опцию? - PullRequest
13 голосов
/ 27 апреля 2010

Когда getopt или getopt_long встречает нелегальный вариант, она сохраняет символ опции обижая в optopt. Когда недопустимым вариантом является параметр long , где я могу узнать, что это был за параметр? И что-нибудь значимое хранится в optopt тогда?

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

Ответы [ 2 ]

7 голосов
/ 28 апреля 2010

Вы совершенно правы, что справочная страница скрывает эти подробности, но из исходного кода можно почерпнуть достаточно подсказок, например, реализацию glibc в glibc-xyz / posix / getopt.c _getopt_internal_r.(Возможно, это единственная интересная реализация этой функции расширения GNU?)

Этот код устанавливает optopt в 0, когда встречается с ошибочной длинной опцией, которая, я думаю, полезна, чтобы отличать этот случай от ошибочной короткой опции, когда optopt, безусловно, будет не NUL.

Сообщения об ошибках, генерируемые, когда opterr != 0 в основном выводят ошибочную длинную опцию как argv[optind], и более поздний код (всегда или - консервативно - впо меньшей мере, в основном) позже optind перед возвратом.

Поэтому рассмотрим эту программу:

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

int main(int argc, char **argv) {
  struct option longopts[] = {
    { "foo", no_argument, NULL, 'F' },
    { NULL, 0, NULL, 0 }
  };
  int c;

  do {
    int curind = optind;
    c = getopt_long(argc, argv, "f", longopts, NULL);
    switch (c) {
    case 'f':  printf("-f\n");  break;
    case 'F':  printf("--foo\n");  break;
    case '?':
      if (optopt)  printf("bad short opt '%c'\n", optopt);
      else  printf("bad long opt \"%s\"\n", argv[curind]);
      break;
    case -1:
      break;
    default:
      printf("returned %d\n", c);
      break;
    }
  } while (c != -1);

  return 0;
}

$ ./longopt -f -x --bar --foo
-f
./longopt: недопустимый параметр - 'x'
плохая короткая опция 'x'
./longopt: нераспознанная опция '--bar'
плохая длинная опция "--bar"
--foo

Таким образом, в этих случаях, кэшируя значение до getopt_long optind, мы легко можем распечатать те же плохие опции, что и opterr messages.

Это может быть не совсем правильно во всех случаях, так как реализация glibc используетего собственная __nextchar, а не argv[optind] (в случае «нераспознанного варианта») заслуживает изучения, но этого должно быть достаточно, чтобы начать работу.

Если вы тщательно обдумаете связь между optind иповторные вызовы getopt_long, я думаю, распечатка argv[cached_optind] будет довольно безопасной.optopt существует, потому что для коротких опций вам нужно знать, какой именно символ в слове является проблемой, но для длинных опций проблема заключается в целом текущем слове (по модулю отбрасывая аргументы опций вида =param).И текущее слово - это то, на которое getopt_long смотрит с (входящим) значением optind.

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

4 голосов
/ 28 апреля 2010

Самое близкое, что я могу найти, это то, что если вы получите BADCH, верните элемент argv, который вызвал его, в argv[optind-1]. Похоже, должен быть лучший способ найти аргумент проблемы.

...