82
extern int optind, opterr, optopt;
Листинг 2.34. Описание функции getopt() и ассоциированных с
ней внешних переменных.
В общем и целом логика ее работа та же, что и у служебной
программы getopts (с соответствующим переименованием используемых
переменных). Аргументы argc и argv задают командную строку в том
виде, как она передается функции main(), optstring представляет собой
цепочку имен опций. Переменная optind (с начальным значением 1)
служит индексом в массиве argv []. Стандарт POSIX-2001 не
специфицирует, как именно getopt() разбирает несколько
расположенных поочередно (после одного знака минус) имен опций и
определяет, какие опции уже обработаны.
В итоге функция getopt() возвращает имя очередной опции из
числа перечисленных в цепочке optstring (если таковое удалось
выделить). При наличии у опции аргумента указатель на него
помещается в переменную optarg с соответствующим увеличением
значения optind.
Если у опции аргумент отсутствует, а на первом месте в optstring
задано двоеточие, оно и служит результатом.
Если встретилось имя опции, не перечисленное в optstring, или у
опции нет аргумента, а на первом месте в optstring задано не двоеточие,
то результатом станет знак вопроса.
В любой из перечисленных выше ошибочных ситуаций в
переменную optopt помещается имя "проблемной" опции. Кроме того, в
стандартный протокол выдается диагностическое сообщение по образу и
подобию утилиты getopts. Для подавления выдачи следует присвоить
переменной opterr нулевое значение.
Наконец, если при вызове getopt() указатель argv [optind] не
отмечает начало опции (например, он пуст или первый символ
указуемой цепочки отличен от знака минус), результат равен -1 как
признак того, что разбор опций закончен.
Следующий пример программы (см. листинг 2.35) возвращает нас
к рассмотренной выше shell-процедуре cmd. Он показывает, как можно
обработать командную строку вызова утилиты, допускающей
взаимоисключающие опции a и b, а также опцию o, которая должна
иметь аргумент.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Программа разбирает опции вызвавшей ее командной строки */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h>
#include <stdio.h>
int main (int argc, char *argv []) {
int c; /* Имя анализируемой опции */
int aflg = 0; /* Признак того, что задана опция a */
int bflg = 0; /* Признак того, что задана опция b */