Разработка приложений в среде Linux. Второе издание - Майкл Джонсон
Шрифт:
Интервал:
Закладка:
95: struct poptOption optionsTable[] = {
96: { "extended-regexp", 'E', POPT_ARG_VAL,
97: &mode, MODE_EXTENDED,
98: "шаблоном для соответствия является расширенное регулярное "
99: "выражение" },
100: { "fixed-strings", 'F', POPT_ARG_VAL,
101: &mode, MODE_FIXED,
102: "шаблоном для соответствия является базовая строка, (не "
103: "регулярное выражение)", NULL },
104: { "basic-regexp", 'G', POPT_ARG_VAL,
105: &mode, MODE_REGEXP,
106: "шаблоном для соответствия является базовое регулярное выражение" },
107: { "ignore-case", 'i', POPT_ARG_NONE, &ignoreCase, 0,
108: "выполнять поиск, чувствительный к регистру", NULL },
109: { "max-count", 'm', POPT_ARG_INT, &maxCount, 0,
110: "завершить после получения N совпадений", "N" },
111: { "regexp", 'е', POPT_ARG_STRING, &pattern, 0,
112: "регулярное выражение для поиска", "pattern" },
113: POPT_AUTOHELP
114: { NULL, ' ', POPT_ARG_NONE, NULL, 0, NULL, NULL }
115: };
Ниже показан пример того, как выглядит справочное сообщение, сгенерированное данной таблицей параметров.
Usage: grep [OPTION...]
Использование: grep [ПАРАМЕТРЫ...]
-Е, --extended-regexp шаблоном для соответствия является
расширенное регулярное выражение
-F, --fixed-strings шаблоном для соответствия является
базовая строка (не регулярное выражение)
-G, --basic-regexp шаблоном для соответствия является базовое
регулярное выражение
-i, --ignore-case выполнять поиск, чувствительный к регистру
-m, --max-count=N завершить после получения N совпадений
-е, --regexp=pattern регулярное выражение для поиска
Help options:
-?, --help Show this help message
--usage Display brief usage message
Параметры справки:
-?, --help Показать это сообщение
--usage Отобразить краткое сообщение об использовании
Хотя эта информация и имеет привлекательный вид, она требует некоторых уточнений. В первой строке не сказано, что команда ожидает имена файлов в командной строке. Показанный здесь текст [OPTION...] принят в popt по умолчанию, и с помощью функции poptSetOtherOptionHelp() может быть изменен для получения более детального описания.
#include <popt.h>
poptSetOtherOptionHelp(poptContext con, const char * text);
Первым параметром является содержимое, а второй параметр определяет текст, который должен появиться после имени программы. Если добавить следующий вызов
poptSetOtherOptionHelp(optCon, "<шаблон> <список файлов>");
то первая строка в справочном сообщении будет изменена на
Usage: grep <шаблон> <список файлов>
Использование: grep <шаблон> <список файлов>
что является более точным.
Последнее, что требуется уточнить в отношении справочных сообщений, это способ обработки вложенных таблиц. Давайте снова обратимся к справочному сообщению для нашей программы grep; для параметров справки выделяется отдельный раздел справочного сообщения. Если элемент POPT_ARG_INCLUDE_TABLE таблицы параметров содержит член descrip, то строка будет использоваться в качестве описания для всех параметров во вложенной таблице, и эти параметры будут отображаться в своем собственном разделе справочного сообщения (подобно параметрам справки для tail). Если descrip будет иметь значение NULL, то параметры для вложенной таблицы будут отображаться вместе с параметрами из главной таблицы, а не в своем собственном разделе.
Иногда программы предлагают параметры, которые, возможно, не должны использоваться; они могут быть включены для поддержки унаследованных приложений или приложений, разработанных только для тестирования. Автоматическая генерация справочных сообщений для такого параметра можно подавить с помощью битового "ИЛИ" POPT_ARGFLAG_DOC_HIDDEN и члена arg структуры struct poptOption, описывающей данный параметр.
26.3. Использование обратных вызовов
Мы показали два способа обработки параметров с помощью библиотеки popt: с помощью возврата параметра функцией poptGetNextOpt() и путем автоматического изменения переменных во время представления параметров. К сожалению, ни один из этих способов не подходит для вложенных таблиц. Очевидно, что возвращение параметров, определяемых во вложенной таблице для обработки в приложении, не будет работать, поскольку вложенные таблицы предназначены для того, чтобы приложению не нужно было знать, какие параметры предлагает библиотека. Присвоение переменным значений тоже не подходит, поскольку в этом случае не ясно, каким переменным нужно присваивать значения. Использование глобальных переменных часто тоже является неподходящим, а библиотека не имеет доступных для использования локальных переменных, поскольку синтаксический анализ выполняется из главного приложения, а не из библиотеки. Чтобы обеспечить гибкую обработку параметров во вложенных таблицах, библиотека popt предлагает использовать обратные вызовы (callback).
Каждая таблица может определять свою собственную функцию обратного вызова, которая подменяет обычную обработку параметров, определенных в этой таблице. Вместо нее функция обратного вызова вызывается для каждого обнаруживаемого параметра. Параметры, определяемые в других таблицах параметров (включая таблицы, вложенные в таблицу, определяющую обратный вызов), обрабатываются с использованием обычных правил, если только в других таблицах не будут определены свои собственные обратные вызовы.
Обратные вызовы можно определять только в первом элементе таблицы параметров. Если этот элемент определяет обратный вызов, член argInfo будет иметь значение POPT_ARG_CALLBACK, a arg будет указывать на функцию обратного вызова. Член descrip может представлять любое значение указателя, и передается в обратный вызов каждый раз во время его инициирования, открывая доступ к любым произвольным данным. Все остальные члены структуры struct poptOption должны иметь нулевое значение или NULL.
Во время обработки параметров обратный вызов можно инициировать в трех точках: до начала обработки, при нахождении параметра в таблице для данного обратного вызова и после завершения обработки. Это дает библиотекам возможность инициализировать любые необходимые им структуры (включая данные, определяемые членом descrip), и выполнять любые служебные действия, которые могут понадобиться после завершения обработки (например, очищать динамическую память, выделенную для члена descrip). Они всегда вызываются при нахождении параметра, однако в таблице параметров необходимо указать, что их нужно вызывать в двух других местах. Чтобы сделать это, значения POPT_CBFLAG_PRE или POPT_CBFLAG_POST (или оба) должны объединяться битовым "ИЛИ" со значением POPT_ARG_CALLBACK, присвоенным члену arg структуры, которая определяет обратный вызов.
Далее показан прототип, который следует использовать для определения функции обратного вызова:
void callback(poptContext con, enum poptCallbackReason reason,
const struct poptOption * opt, const char * arg,
const void * data);
Первый параметр представляет содержимое, синтаксический анализ которого будет выполнен во время инициирования обратного вызова. Следующим параметров является POPT_CALLBACK_REASON_PRE, если обработка параметра еще не началась, POPT_CALLBACK_REASON_POST, если обработка параметров завершена, или POPT_CALLBACK_REASON_OPTION, если в таблице для данного обратного вызова был обнаружен параметр. Если этот параметр является последним, то аргумент opt будет указывать на элемент таблицы параметров для обнаруженного параметра, а аргумент arg будет указывать на строку, определяющую аргумент для данного параметра. Если ожидается аргумент, не представленный в виде строки, обратный вызов будет отвечать за проверку типа и преобразование аргумента. Последний параметр для обратного вызова, data, представляет собой значение поля descrip в элементе таблицы параметров, который задает обратный вызов.
Ниже показан пример библиотеки, которая использует вложенную таблицу popt и обратные вызовы для синтаксического анализа некоторых параметров командной строки. Структура данных инициализируется до начала синтаксического анализа командной строки, а затем отображаются последние значения.
1: /* popt-lib.с */
2:
3: #include <popt.h>
4: #include <stdlib.h>
5:
6: struct params {