Linux программирование в примерах - страница 23

стр.

', a >optarg указывает на «>YANKEES», тогда как для >-b или '>-b YANKEES' возвращаемое значение будет все то же '>b', но в >optarg будет помещен NULL. В последнем случае «>YANKEES» представляет отдельный аргумент командной строки.

2.3.3. Длинные опции

Функция >getopt_long() осуществляет разбор длинных опций в описанном ранее виде. Дополнительная процедура >getopt_long_only() работает идентичным образом, но она используется для программ, в которых все опции являются длинными и начинаются с единичного символа '>-'. В остальных случаях обе функции работают точно так же, как более простая функция GNU >getopt(). (Для краткости, везде, где мы говорим «>getopt_long()», можно было бы сказать «>getopt_long() и >getopt_long_only()».) Вот объявления функций из справки getopt(3) GNU/Linux:

>#include /* GLIBC */


>int getopt_long(int argc, char *const argv[],

> const char *optstring,

> const struct option *longopts, int *longindex);

>int getopt_long_only(int argc, char *const argv[],

> const char *optstring,

> const struct option *longopts, int *longindex);

Первые три аргумента те же, что и в >getopt(). Следующая опция является указателем на массив >struct option, который мы назовем таблицей длинных опций и который вскоре опишем. Параметр >longindex, если он не установлен в NULL, указывает на переменную, в которую помешается индекс обнаруженной длинной опции в >longopts. Это полезно, например, при диагностике ошибок.

2.3.3.1. Таблица длинных опций

Длинные опции описываются с помощью массива структур >struct option. Структура >struct option определена в >; она выглядит следующим образом:

>struct option {

> const char *name;

> int has_arg;

> int *flag;

> int val;

>};

Элементы структуры следующие:

>const char *name

Это имя опции без предшествующих черточек, например, «>help» или «>verbose».

>int has_arg

Переменная описывает, имеет ли длинная опция аргумент, и если да, какого вида этот аргумент. Значение должно быть одно из представленных в табл. 2.1. Макроподстановки являются некоторыми символическими именами для числовых значений, приведенных в таблице. Хотя числовые значения тоже работают, макроподстановки гораздо легче читать, и вы должны их использовать вместо соответствующих чисел в любом коде, который пишете.

>int *flag

Если этот указатель равен NULL, >getopt_long() возвращает значение поля >val структуры. Если он не равен NULL, переменная, на которую он указывает, заполняется значением >val, a >getopt_long() возвращает 0. Если >flag не равен NULL, но длинная опция отсутствует, указанная переменная не изменяется.

>int val

Если длинная опция обнаружена, это возвращаемое значение или значение для загрузки в >*flag, если >flag не равен NULL. Обычно, если >flag не равен NULL, >val является значением true/false, вроде 1 или 0. С другой стороны, если >flag равен NULL, >val обычно содержит некоторую символьную константу. Если длинная опция соответствует короткой, эта символьная константа должна быть той же самой, которая появляется в аргументе >optstring для этой опции. (Все это станет вскоре ясно, когда мы рассмотрим несколько примеров.)


Таблица 2.1. Значения для >has_arg

МакроподстановкаЧисловое значениеСмысл
>no_argument0Опция не принимает аргумент
>required_argument1Опции требуется аргумент
>optional_argument2Аргумент опции является необязательным

У каждой длинной опции есть один такой элемент с соответствующими заполненными значениями. В последнем элементе массива все значения должны быть равны нулю. Нет необходимости сортировать массив: >getopt_long() осуществляет линейный поиск. Однако, сортировка его по длинным именам может упростить его чтение для программиста.

При первой встрече использование >flag и >val кажется сбивающим с толку. Давайте сделаем на время шаг назад и рассмотрим, почему это работает именно таким способом В большинстве случаев, обработка опций заключается в установке значений различных флаговых переменных при обнаружении различных символов опций, наподобие этого:

>while ((с = getopt(argc, argv, ":af:hv")) != -1) {

> switch (с) {

> case 'a':

>  do_all = 1;

>  break;

> case 'f':

>  myfile = optarg;

>  break;