Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
Теперь должно быть ясно, что getopt_long() предоставляет гибкий механизм для разбора опций. В табл. 2.2 приведена сводка всех возможных возвращаемых значений функции и их значение.
Таблица 2.2. Возвращаемые значения getopt_long()
Возвращаемый код Значение 0 getopt_long() установила флаг, как указано в таблице длинных опций 1 optarg указывает на простой аргумент командной строки '?' Недействительная опция ' ' Отсутствующий аргумент опции 'x' Символ опции 'x' -1 Конец опцийНаконец, мы улучшим предыдущий пример кода, показав оператор switch полностью:
int do_all, do_help, do_verbose; /* флаговые переменные */
char *myfile, *user; /* файл ввода, имя пользователя */
struct option longopts[] = {
{ "all", no_argument, &do_all, 1 },
{ "file", required_argument, NULL, 'f'},
{ "help", no_argument, &do_help, 1 },
{ "verbose", no_argument, &do_verbose, 1 },
{ "user" , optional_argument, NULL, 'u'},
{ 0, 0, 0, 0 }
};
...
while((c=getopt_long(argc, argv, ":ahvf:u::W;", longopts, NULL)) != -1) {
switch (c) {
case 'a':
do_all = 1;
break;
case 'f':
myfile = optarg;
break;
case 'h':
do_help = 1;
break;
case 'u':
if (optarg != NULL)
user = optarg;
else
user = "root";
break;
case 'v':
do_verbose = 1;
break;
case 0:
/* getopt_long() установил переменную, просто продолжить */
break;
#if 0
case 1:
/*
* Используйте этот case, если getopt_long() должна
* просмотреть все аргументы. В этом случае добавьте к
* optstring ведущий * символ '-'. Действительный код,
* если он есть, работает здесь.
*/
break;
#endif
case ':': /* отсутствует аргумент опции */
fprintf(stderr, "%s: option '-%c' requires an argumentn",
argv[0], optopt);
break;
case '?':
default: /* недействительная опция */
fprintf(stderr, "%s: option '-%c' is invalid: ignoredn",
argv[0], optopt);
break;
}
}
В своих программах вы можете захотеть сделать для каждого символа опции комментарии, объясняющие их значение. Однако, если вы использовали описательные имена переменных для каждого символа опции, комментарии уже не так нужны. (Сравните do_verbose и vflag.)
2.3.3.4. GNU getopt() или getopt_long() в программах пользователей
Вы можете захотеть использовать в своих программах GNU getopt() или getopt_long() и заставить их работать на не-Linux системах/ Это нормально; просто скопируйте исходные файлы из программы GNU или из CVS архива библиотеки С GNU (GLIBC)[30]. Исходные файлы getopt.h, getopt.с и getopt1.c. Они лицензированы на условиях меньшей общедоступной лицензии (Lesser General Public License) GNU, которая позволяет включать библиотечные функции даже в патентованные программы. Вы должны включить в свою программу копию файла COPYING.LIB наряду с файлами getopt.h, getopt.с и getopt1.с.
Включите исходные файлы в свой дистрибутив и откомпилируйте их с другими исходными файлами. В исходном коде, вызывающем getopt_long(), используйте '#include <getopt.h>', а не '#include "getopt.h"'. Затем, при компилировании, добавьте к командной строке компилятора С -I. Таким способом сначала будет найдена локальная копия заголовочного файла.
Вы можете поинтересоваться: «Вот так, я уже использую GNU/Linux. Почему я должен включать getopt_long() в свой исполняемый модуль, увеличивая его размер, если процедура уже находится в библиотеке С?» Это хороший вопрос. Однако, здесь не о чем беспокоиться. Исходный код построен так, что если он компилируется на системе, которая использует GLIBC, откомпилированные файлы не будут содержать никакого кода! Вот подтверждение на нашей системе:
$ uname -а /* Показать имя и тип системы */
Linux example 2.4.18-14 #1 Wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
$ ls -l getopt.о getopt1.о /* Показать размеры файлов */
-rw-r--r-- 1 arnold devel 9836 Mar 24 13:55 getopt.о
-rw-r--r-- 1 arnold devel 10324 Mar 24 13:55 getopt1.о
$ size getopt.о getopt1.о /* Показать включенные в исполняемый
модуль размеры */
text data bss dec hex filename
0 0 0 0 0 getopt.о
0 0 0 0 0 getopt1.о
Команда size печатает размеры различных составных частей двоичного объекта или исполняемого файла. Мы объясним вывод в разделе 3.1 «Адресное пространство Linux/Unix». Что важно понять прямо сейчас, это то, что несмотря на ненулевой размер самих файлов, они не вносят никакого вклада в конечный исполняемый модуль. (Думаем, это достаточно ясно.)
2.4. Переменные окружения
Окружение представляет собой набор пар вида 'имя=значение' для каждой программы. Эти пары называются переменными окружения. Каждое имя состоит от одной до любого числа буквенно-цифровых символов или символов подчеркивания ('_'), но имя не может начинаться с цифры. (Это правило контролируется оболочкой; С API может помешать в окружение все, что захочет, за счет возможного запутывания последующих программ.)
Переменные окружения часто используются для управления поведением программ. Например, если в окружении существует POSIXLY_CORRECT, многие программы запрещают расширения или историческое поведение, которые несовместимы со стандартом POSIX.
Вы можете решить использовать (и должны задокументировать) переменные окружения для управления поведением вашей программы. Например, вы можете вместо аргумента командной строки использовать для опций отладки переменную окружения. Преимуществом использования переменных окружения является то, что пользователи могут установить их в своем загрузочном файле и не беспокоиться больше постоянным набором определенных опций в командной строке.
Конечно, недостатком использования переменных окружения является то, что они могут молча изменять поведение программы. Джим Мейеринг (Jim Meyering), сопроводитель Coreutils, выразил это таким образом:
Они упрощают пользователю настройку программы без изменения способа ее вызова. Это может быть как благословением, так и проклятием. Если вы пишете сценарий, который зависит от значения определенной переменной окружения, а затем этот сценарий использует еще кто-то, у кого нет таких же установок окружения, он легко может потерпеть неудачу (или, что еще хуже, молча выдать неверные результаты).
2.4.1. Функции управления окружением
Несколько функций позволяют получать значения переменных окружения, изменять эти значения или удалять их. Вот соответствующие объявления:
#include <stdlib.h>
char *getenv(const char *name);
/* ISO С: Получить переменную
окружения */
int setenv(const char *name, /* POSIX: Установить переменную */
const char *value, /* окружения */
int overwrite);
int putenv(char *string); /* XSI: Установить переменную
окружения, использует строку */
void unsetenv(const char *name); /* POSIX: Удалить переменную
окружения */
int clearenv(void); /* Общее: очистить все окружение */
Функция getenv() — та, которую вы будете использовать в 99% случаев. Ее аргументом является имя переменной окружения, которую нужно искать, такое, как «НОМЕ» или «PATH». Если переменная существует, getenv() возвращает указатель на строковое значение. Если нет, возвращается NULL. Например:
char *pathval;
/* Поиск PATH; если нет, использовать значение
по умолчанию */
if ((pathval = getenv("PATH")) == NULL)
pathval = "/bin:/usr/bin:/usr/ucb";
Иногда переменная окружения существует, но с пустым значением. В этом случае возвращаемое значение не равно NULL, но первый символ, на которую оно указывает, будет нулевым байтом, который в С является символом конца строки, ' '. Ваш код должен позаботиться проверить, что возвращаемое значение не равно NULL. Если оно не NULL, необходимо также проверить, что строка не пустая, если вы хотите для чего-то использовать значение переменной. В любом случае, не используйте возвращенное значение слепо.