что такое переносимый способ сброса getopt ()? - PullRequest
1 голос
/ 02 марта 2020

Я нацеливаю механизм getopt() на свой собственный массив, похожий на argv, после того, как использую его на реальном argv. интерфейс не реентерабелен (состояние удержания), и различные реализации сбрасываются по-разному.

  • в XPG3 / SVID это optreset = 1; (freebsd, macosx)
  • в XPG4 / POSIX / SUS это optind = 1; (suse tumbleweed)
  • в Linux / GLIB C это также optind = 0; (debian)

я не хочу, чтобы autoconf просто для этого.

что такое надежный набор #ifdef?

1 Ответ

0 голосов
/ 02 марта 2020

Единственным стандартным параметром является настройка optind = 1.

Стандарт SUSv4 не упоминает optreset и объявляет optind = 0 "не указано":

Если приложение устанавливает optind в ноль перед вызовом getopt(), поведение не определено.

В противном случае стандарт неясен и вообще ничего не говорит о вызове getopt() несколько раз, ни разрешая, ни объявляя его неопределенным.

Кроме того, нет определений, которые говорят, что поддерживаются optind = 0 или optreset (хотя первый поддерживается в OpenBSD, но не во FreeBSD, и последний в Linux / musl, но не в Linux / glib c), поэтому не может быть надежного способа обнаружить его с помощью #ifdef s.

Не для ошибок в причудливых getopt/_long реализациях (см. Ниже), просто установка optind = 1 для перезапуска getopt() должна работать нормально до тех пор, пока

a) вы не используете никаких расширений GNU :

Программа, которая сканирует несколько векторов аргументов или повторно сканирует их vector более одного раза, и хочет использовать расширения GNU, такие как + и - в начале строки optstring, или изменяет значение POSIXLY_CORRECT между сканированиями , должен повторно инициализировать getopt() Сброс optind на 0,

b) вы не перезапустите getopt() в середине, пока он не вернул -1. Например. от FreeBSD getopt:

#define BADCH   (int)'?'
#define BADARG  (int)':'
#define EMSG    ""
...
int
getopt(int nargc, char * const nargv[], const char *ostr)
{
        static char *place = EMSG;              /* option letter processing */
        ...
        if (optreset || *place == 0) {          /* update scanning pointer */
                optreset = 0;
                ...
                        place = EMSG;
                        return (-1);
                ...
                        place = EMSG;
                        return (-1);
                ...
                        place = EMSG;
                        if (strchr(ostr, '-') == NULL)
                                return (-1);
        ...
                return (BADCH);
        ...
                                return (BADARG);
        ...
                        return (BADCH);
        ...
        return (optopt);                        /* return option letter */
}

Ошибки

Реализация glib c getopt будет цепляться за устаревшее состояние даже после возвращения -1. Это может привести к глупым ошибкам и сбоям, если старые строки будут освобождены.

Реализация OpenBSD будет делать аналогично , но только при фиктивной опции - используется, как в getopt("q", ["prog", "-q-", NULL]). Обратите внимание, что реализация OpenBSD getopt_long, как по умолчанию getopt(), могла использоваться в других системах, таких как Solaris и Android.

.
...