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

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

Каждая таблица может определять свою собственную функцию обратного вызова, которая подменяет обычную обработку параметров, определенных в этой таблице. Вместо нее функция обратного вызова вызывается для каждого обнаруживаемого параметра. Параметры, определяемые в других таблицах параметров (включая таблицы, вложенные в таблицу, определяющую обратный вызов), обрабатываются с использованием обычных правил, если только в других таблицах не будут определены свои собственные обратные вызовы.

Обратные вызовы можно определять только в первом элементе таблицы параметров. Если этот элемент определяет обратный вызов, член

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 {

 7: int height, width;

 8: char*fg,*bg;

 9: };

10:

11: static void callback(poptContext con,

12: enum poptCallbackReason reason,

13: const struct poptOption * opt,

14: const char * arg,

15: const void * data);

16:

17: /* Здесь сохраняются
переменные, которые прошли синтаксический анализ. Обычно

18: глобальные переменные использовать не рекомендуется, зато работать с ними проще.*/

19: struct params ourParam;

20:

21: struct poptOption libTable[] = {

22: { NULL, '\0',

23: POPT_ARG_CALLBACK | POPT_CBFLAG_PRE | POPT_CBFLAG_POST,

24: callback, '\0', (void *) &ourParam, NULL },

25: { "height", 'h', POPT_ARG_STRING, NULL, '\0', NULL, NULL },

26: { "width", 'w', POPT_ARG_STRING, NULL, '\0', NULL, NULL },

27: { "fg", 'f', POPT_ARG_STRING, NULL, '\0', NULL, NULL },

28: { "bg", 'b', POPT_ARG_STRING, NULL, '\0', NULL, NULL },

29: { NULL, '\0', POPT_ARG_NONE, NULL, '\0', NULL, NULL }

30: };

31:

32: static void callback(poptContext con,

33: enum poptCallbackReason reason,

34: const struct poptOption * opt,

35: const char * arg,

36: const void * data) {

37: struct params * p = (void *) data;

38: char * chptr = NULL;

39:

40: if (reason == POPT_CALLBACK_REASON_PRE) {

41: p->height = 640;

42: p->width = 480;

43: p->fg = "white";

44: p->bg = "black";

45: } else if (reason == POPT_CALLBACK_REASON_POST) {

46: printf("используется высота %d ширина %d передний план %s фон %s\n",

47: p->height, p->width, p->fg, p->bg);

48:

49: } else {

50: switch (opt->shortName) {

51: case 'h': p->height = strtol(arg, &chptr, 10); break;

52: case 'w': p->width = strtol(arg, &chptr, 10); break;

53: case 'f' : p->fg = (char *) arg; break;

54: case 'b': p->bg = (char *) arg; break;

55: }

56:

57: if (chptr && *chptr) {

58: fprintf(stderr, "для %s ожидался числовой аргумент\n",

59: opt->longName);

60: exit(1);

61: }

62: }

63: }

64:

Программа, для которой необходимо обеспечить эти аргументы командной строки, должна включать одну дополнительную строку в своей таблице

popt
. Обычно этой строкой является макрос, задаваемый в заголовочном файле (подобно тому, как реализуется
POPT_AUTOHELP
), но в целях упрощения в данном примере мы просто явным образом покажем эту строку.

 1: /* popt-nest.c */

 2:

 3: #include <popt.h>

 4:

 5: /* Обычно это объявление осуществляется в заголовочном файле */

 6: extern struct poptOption libTable[];

 7:

 8: int main(int argc, const char * argv[]) {

 9: poptContext optCon;

10: int rc;

11: struct poptOption options[] = {

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