Чтение онлайн

ЖАНРЫ

Linux программирование в примерах
Шрифт:

91 #define PROGRAM_NAME "env"

92

93 #define AUTHORS N_ ("Richard Mlynarik and David MacKenzie")

94

95 int putenv;

96

97 extern char **environ;

98

99 /* Имя, посредством которого эта программа была запущена. */

100 char *program_name;

101

102 static struct option const longopts[] =

103 {

104 {"ignore-environment", no_argument, NULL, 'i'},

105 {"unset", required_argument, NULL, 'u'},

106 {GETOPT_HELP_OPTION_DECL},

107 {GETOPT_VERSION_OPTION_DECL},

108 {NULL, 0, NULL, 0}

109 };

GNU Coreutils

содержит большое число программ, многие из которых выполняют одни и те же общие задачи (например, анализ аргументов). Для облегчения сопровождения многие типичные идиомы были определены в виде макросов. Двумя таким макросами являются
GETOPT_HELP_OPTION_DECL
и
GETOPT_VERSION_OPTION
(строки 106 и 107). Вскоре мы рассмотрим их определения. Первая функция,
usage
, выводит информацию об использовании и завершает программу. Макрос
_("string")
(строка 115, используется также по всей программе) также предназначен для локализации, пока также считайте его содержащим строковую константу.

111 void

112 usage(int status)

113 {

114 if (status '= 0)

115 fprintf(stderr, _("Try '%s --help' for more information.\n"),

116 program_name);

117 else

118 {

119 printf (_("\

120 Usage: %s [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]\n"),

121 program_name);

122 fputs (_("\

123 Set each NAME to VALUE in the environment and run COMMAND. \n\

124 \n\

125 -i, --ignore-environment start with an empty environment\n\

126 -u, --unset=NAME remove variable from the environment\n\

127 "), stdout);

128 fputs(HELP_OPTION_DESCRIPTION, stdout);

129 fputs(VERSION_OPTION_DESCRIPTION, stdout);

130 fputs(_("\

131 \n\

132 A mere - implies -i. If no COMMAND, print the resulting\

133 environment.\n"), stdout);

134 printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);

135 }

136 exit(status);

137 }

Первая часть

main
объявляет переменные и настраивает локализацию. Функции
setlocale
,
bindtextdomain
и
textdomain
(строки 147–149) обсуждаются в главе 13 «Интернационализация и локализация». Отметим, что эта программа использует аргумент
main envp
(строка 140). Это единственная программа Coreutils, которая так делает. Наконец, вызов
atexit
в строке 151 (см. раздел 9.1.5.3. «Функции завершения») регистрирует библиотечную функцию Coreutils, которая очищает все выходные буферы и закрывает
stdout
, выдавая сообщение при ошибке. Следующая часть программы обрабатывает аргументы командной строки, используя
getopt_long
.

139 int

140 main(register int argc, register char **argv, char **envp)

141 {

142 char *dummy_environ[1];

143 int optc;

144 int ignore_environment = 0;

145

146 program_name = argv[0];

147 setlocale(LC_ALL, "");

148 bindtextdomain(PACKAGE, LOCALEDIR);

149 textdomain(PACKAGE);

150

151 atexit(close_stdout);

152

153 while ((optc = getopt_long(argc, argv, "+iu:", longopts, NULL)) != -1)

154 {

155 switch (optc)

156 {

157 case 0:

158 break;

159 case 'i':

160 ignore_environment = 1;

161 break;

162 case 'u':

163 break;

164 case_GETOPT_HELP_CHAR;

165 case_GETOPT_VERSION_CHAR(PROGRAM_NAME, AUTHORS);

166 default:

167 usage(2);

168 }

169 }

170

171 if (optind != argc && !strcmp(argv[optind], "-"))

172 ignore_environment = 1;

Вот

отрывок из файла
src/sys2.h
в дистрибутиве Coreutils с упомянутыми ранее определениями и макросом '
case_GETOPT_xxx
', использованным выше (строки 164–165):

/* Вынесение за скобки общей части кода, обрабатывающего --help и

– -version. */

/* Эти значения перечисления никак не могут конфликтовать со значениями опций,

обычно используемыми командами, включая CHAR_MAX + 1 и т.д. Избегайте

CHAR_MIN - 1, т.к. оно может равняться -1, значение завершения опций getopt.

*/

enum {

 GETOPT_HELP_CHAR = (CHAR_MIN — 2),

 GETOPT_VERSION_CHAR = (CHAR_MIN - 3)

};

#define GETOPT_HELP_OPTION_DECL \

 "help", no_argument, 0, GETOPT_HELP_CHAR

#define GETOPT_VERSION_OPTION_DECL \

 "version", no_argument, 0, GETOPT_VERSION_CHAR

#define case_GETOPT_HELP_CHAR \

 case GETOPT_HELP_CHAR: \

usage(EXIT_SUCCESS); \

break;

#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \

 case GETOPT_VERSION_CHAR: \

version_etc(stdout, Program_name, PACKAGE, VERSION, Authors); \

exit(EXIT_SUCCESS); \

break;

Результатом этого кода является печать сообщения об использовании утилиты для

– -help
и печать информации о версии для
– -version
. Обе опции завершаются успешно («Успешный» и «неудачный» статусы завершения описаны в разделе 9.1.5.1 «Определение статуса завершения процесса».) Поскольку в Coreutils входят десятки утилит, имеет смысл вынести за скобки и стандартизовать как можно больше повторяющегося кода.

Поделиться с друзьями: