Книга: Программирование для Linux. Профессиональный подход
Листинг 11.5. (main.c) Главная серверная функция, выполняющая анализ аргументов командной строки
Листинг 11.5. (main.c) Главная серверная функция, выполняющая анализ аргументов командной строки
#include <assert.h>
#include <getopt.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "server.h"
/* Описание длинных опций для функции getopt_long(). */
static const struct option long_options[] = {
{ "address", 1, NULL, 'a' },
{ "help", 0, NULL, 'h' },
{ "module-dir", 1, NULL, 'm' },
{ "port", 1, NULL, 'p' },
{ "verbose", 0, NULL, 'v' },
};
/* Описание коротких опций для функции getopt_long(). */
static const char* const short_options = "a:hm:p:v";
/* Сообщение о том, как правильно использовать программу. */
static const char* const usage_template =
"Usage: %s { options }n"
" -a, --address ADDR Bind to local address (by default, bindn"
" to all local addresses).n"
" -h, --help Print this information.n"
" -m, --module-dir DIR Load modules from specified directoryn"
" (by default, use executable directory).n"
" -p, --port PORT Bind to specified port.n"
" -v, --verbose Print verbose messages.n";
/* Вывод сообщения о правильном использовании программы
и завершение работы. Если аргумент IS_ERROR не равен нулю,
сообщение записывается в поток stderr и возвращается
признак ошибки, в противном случае сообщение выводится в
поток stdout и возвращается обычный нулевой код. */
static void print_usage(int is_error) {
fprintf(is_error ? stderr : stdout, usage_template,
program_name);
exit(is_error ? 1 : 0);
}
int main(int argc, char* const argv[]) {
struct in_addr local_address;
uint16_t port;
int next_option;
/* Сохранение имени программы для отображения в сообщениях
об ошибке. */
program_name = argv[0];
/* Назначение стандартных установок. По умолчанию сервер
связан со всеми локальными адресами, и ему автоматически
назначается неиспользуемый порт. */
local_address.s_addr = INADDR_ANY;
port = 0;
/* He отображать развернутые сообщения. */
verbose = 0;
/* Загружать модули из каталога, в котором содержится
исполняемый файл. */
module_dir = get_self_executable_directory();
assert(module_dir != NULL);
/* Анализ опций. */
do {
next_option =
getopt_long(argc, argv, short_options,
long_options, NULL);
switch (next_option) {
case 'a':
/* Пользователь ввел -a или --address. */
{
struct hostent* local_host_name;
/* Поиск заданного адреса. */
local_host_name = gethostbyname(optarg);
if (local_host_name == NULL ||
local_host_name->h_length == 0)
/* He удалось распознать имя. */
error(optarg, "invalid host name");
else
/* Введено правильное имя */
local_address.s_addr =
*((int*)(local_host_name->h_addr_list[0]));
}
break;
case 'h':
/* Пользователь ввёл -h или --help. */
print_usage(0);
case 'm':
/* Пользователь ввел -m или --module-dir. */
{
struct stat dir_info;
/* Проверка существования каталога */
if (access(optarg, F_OK) != 0)
error(optarg, "module directory does not exist");
/* Проверка доступности каталога. */
if (access(optarg, R_OK | X_OK) != 0)
error(optarg, "module directory is not accessible");
/* Проверка того, что это каталог. */
if (stat(optarg, &dir_info) != 0 || !S_ISDIR(dir_info.st_mode))
error(optarg, "not a directory");
/* Все правильно. */
module_dir = strdup(optarg);
}
break;
case 'p':
/* Пользователь ввел -p или --port. */
{
long value;
char* end;
value = strtol(optarg, &end, 10);
if (*end != '')
/* В номере порта указаны не только цифры. */
print_usage(1);
/* Преобразуем номер порта в число с сетевым (обратным)
порядком следования байтов. */
port = (uint16_t)htons(value);
}
break;
case 'v':
/* Пользователь ввел -v или --verbose. */
verbose = 1;
break;
case '?':
/* Пользователь ввел непонятную опцию. */
print_usage(1);
case -1:
/* Обработка опций завершена. */
break;
default:
abort();
}
} while (next_option != -1);
/* Программа не принимает никаких дополнительных аргументов.
Если они есть, выдается сообщение об ошибке. */
if (optind != argc)
print_usage(1);
/* Отображение имени каталога, если программа работает в режиме
развернутых сообщений. */
if (verbose)
printf("modules will be loaded from %sn", module_dir);
/* Запуск сервера. */
server_run(local_address, port);
return 0;
}
Файл main.c
содержит следующие функции.
? Функция getopt_long()
(см. раздел 21.3, "Функция getopt_long()") вызывается для анализа опций командной строки. Опции могут задаваться в двух форматах: длинном и коротком. Описание длинных опций приведено в массиве long_options
, а коротких — в массиве short_options
.
По умолчанию серверный порт имеет номер 0, а локальный адрес задан в виде константы INADDR_ANY
. Эти установки можно переопределить с помощью опций --port(-p
) и --address(-a
) соответственно. Если пользователь ввел адрес, вызывается библиотечная функция gethostbyname()
, преобразующая его в числовой Internet-адрес.[38]
По умолчанию серверные модули загружаются из каталога, где находится исполняемый файл. Этот каталог определяется с помощью функции get_self_executable_directory()
. Данную установку можно переопределить с помощью опции --module(-m
). В таком случае проверяется, является ли указанный каталог доступным.
По умолчанию развернутые сообщения не отображаются, если не указать опцию --verbose(-v
).
? Если пользователь ввел опцию --help(-h
) или указал неправильную опцию, вызывается функция print_usage()
, которая отображает сообщение о правильном использовании программы и завершает работу.
- Инструмент командной строки gbak
- Листинг 10.1. (simpleid.c) Отображение идентификаторов пользователя и группы
- Инструмент командной строки gfix
- 2.1.3. Функция getopt_long()
- Группировка по встроенным функциям и UDF
- 2.5. Разработка технического задания на проведение детального анализа рынка при работе над инновационным проектом. Основ...
- 9.1. Проблема синтаксического анализа
- 2.12.2. Анализ усилительных каскадов в области малых времен
- Преобразование строки в целое: stoi( )
- 19.1.1. Функция jQuery()
- Функция strcmp( )
- Глава 5. Разработка и анализ бизнес-планов в системе Project Expert