Разработка приложений в среде Linux. Второе издание - Майкл Джонсон
Шрифт:
Интервал:
Закладка:
38: filename = alloca(strlen(getenv("HOME")) + 20);
39: strcpy(filename, getenv("HOME"));
40: strcat(filename, "/.phonedb");
41:
42: dp = dpopen(filename, flags, 0);
43: if (!dp) {
44: fprintf(stderr, "сбой при открытии %s: %sn", filename,
45: dperrmsg(dpecode));
46: return NULL;
47: }
48:
49: return dp;
50: }
51:
52: /* добавить новую запись в базу данных; произвести
53: прямой разбор аргументов командной строки */
54: int addRecord(int argc, char ** argv) {
55: DEPOT * dp;
56: char * name, * phone;
57: int rc = 0;
58: int overwrite = 0;
59: int flag;
60:
61: /* проверить параметры; -f означает перезапись
62: существующего элемента, а имя и номер телефона
63: должны оставаться неизмененными */
64: if (!argc) usage();
65: if (!strcmp(argv[0], " -f")) {
66: overwrite = 1;
67: argc--, argv++;
68: }
69:
70: if (argc! = 2) usage();
71:
72: name = argv[0];
73: phone = argv[1];
74:
75: /* открыть базу данных для записи */
76: if (!(dp = openDatabase(1))) return 1;
77:
78: /* если не перезаписывается существующий элемент,
79: проверить, не используется ли уже это имя */
80: if (!overwrite) {
81: flag = DP_DKEEP;
82: } else {
83: flag = DP_DOVER;
84: }
85:
86: if (!dpput(dp, name, -1, phone, -1, flag)) {
87: if (dpecode == DP_EKEEP) {
88: fprintf(stderr, "%s уже существуетn", name);
89: } else {
90: fprintf(stderr, "сбой записи: %sn", dperrmsg(dpecode));
91: }
92:
93: rc = 1;
94: }
95:
96: dpclose(dp);
97:
98: return rc;
99: }
100:
101: /* найти имя и вывести номер телефона, с которым оно связано;
102: напрямую разобрать командную строку */
103: int queryRecord(int argc, char ** argv) {
104: DEPOT * dp;
105: int rc;
106: char * phone;
107:
108: /* ожидается только один аргумент, имя для поиска */
109: if (argc != 1) usage();
110:
111: /* открыть базу данных для чтения */
112: if (!(dp = openDatabase(0))) return 1;
113:
114: phone = dpget(dp, argv[0], -1, 0, -1, NULL);
115: if (!phone) {
116: if (dpecode == DP_ENOITEM)
117: fprintf(stderr, "%s не существуетn", argv[0]);
118: else
119: fprintf(stderr, "ошибка чтения базы данных: %sn"
120: dperrmsg(dpecode));
121:
122: rc = 1;
123: } else {
124: printf("%s %sn", argv[0], (char *) phone);
125: rc = 0;
126: }
127:
128: dpclose(dp);
129:
130: return rc;
131: }
132:
133: /* удалить определенную запись; имя передается в качестве
134: аргумента командной строки */
135: int delRecord(int argc, char ** argv) {
136: DEPOT * dp;
137: int rc;
138:
139: /* ожидается только один аргумент */
140: if (argc != 1) usage();
141:
142: /* открыть базу данных для обновления */
143: if (!(dp = openDatabase(1))) return 1;
144:
145: if (!(rc = dpout(dp, argv[0], -1))) {
146: if (dpecode == DP_ENOITEM)
147: fprintf(stderr, "%s не существуетn", argv[0]);
148: else
149: fprintf(stderr, "ошибка удаления элемента: %sn",
150: dperrmsg(dpecode));
151:
152: rc = 1;
153: }
154:
155: dpclose(dp);
156:
157: return rc;
158: }
159:
160: /* вывести список всех записей, имеющихся в базе данных */
161: int listRecords(void) {
162: DEPOT * dp;
163: char * key, * value;
164:
165: /* открыть базу данных только для чтения */
166: if (!(dp = openDatabase(0))) return 1;
167:
168: dpiterinit(dp);
169:
170: /* итерация по всем записям */
171: while ((key = dpiternext(dp, NULL))) {
172: value = dpget(dp, key, -1, 0, -1, NULL);
173: printf("%s %sn", key, value);
174: }
175:
176: dpclose(dp);
177:
178: return 0;
179: }
180:
181: int main(int argc, char ** argv) {
182: if (argc == 1) usage();
183:
184: /* найти флаг режима и вызвать соответствующую функцию
185: с остальными аргументами */
186: if (!strcmp(argv[1], "-а"))
187: return addRecord(argc - 2, argv + 2);
188: else if (!strcmp(argv[1], "-q"))
189: return queryRecord(argc - 2, argv + 2);
190: else if (!strcmp(argv[1], "-d"))
191: return delRecord(argc - 2, argv + 2);
192: else if (!strcmp(argv[1], "-l")) {
193: if (argc != 2) usage();
194: return listRecords();
195: }
196:
197: usage(); /* не обнаружено никаких параметров */
198: return 0; /* возврат */
199: }
Глава 26
Синтаксический анализ параметров командной строки
Многие Linux-программы позволяют задавать параметры командной строки. Эти параметры выполняют самые разнообразные функции, однако имеют практически одинаковую синтаксическую структуру. Короткие параметры состоят из символа -, за которым следует один алфавитно-цифровой символ. Длинные параметры, обычные для утилит GNU, состоят из пары символов --, за которыми следует строка, состоящая из букв, цифр и дефисов. После любого из этих параметров может стоять аргумент. Пробел отделяет короткий параметр от его аргументов, а пробел или знак равенства отделяют длинный параметр от аргумента.
Проверить синтаксис параметров командной строки можно многими способами. Наиболее популярным методом является проверка синтаксиса массива argv, выполняемая вручную. Помочь в проверке синтаксиса параметров могут библиотечные функции getopt() и getoptlong(). Функция getopt() присутствует во многих реализациях Unix, однако она поддерживает только короткие параметры. Функция getoptlong() доступна в Linux и позволяет автоматически анализировать синтаксис коротких и длинных параметров[181].
Библиотека popt предназначена специально для синтаксического анализа параметров. По сравнению с функциями getopt() она обладает некоторыми преимуществами.
• В ней не используются глобальные переменные, что позволяет применять ее при многократных проходах, необходимых для синтаксического анализа argv.
• Она может анализировать синтаксис произвольного массива, состоящего из элементов в стиле argv. Поэтому библиотеку popt можно применять для синтаксического анализа текстовых строк, представленных в стиле командной строки, из любого источника.
• Библиотека может анализировать синтаксис аргументов многих типов, не требуя для этого дополнительного кода в приложении.
• Она предлагает стандартный метод использования псевдонимов параметров. Программы, использующие библиотеку popt, могут позволить пользователям добавлять новые параметры командной строки, которые будут определяться как комбинации уже существующих параметров. Благодаря этому пользователь может определять новое сложное поведение или изменять поведение существующих параметров, принятое по умолчанию.
• Благодаря особому механизму библиотеки могут анализировать синтаксис одних параметров в тот момент, когда главное приложение анализирует синтаксис других параметров.
• Она может автоматически генерировать сообщение об использовании, в котором будут перечислены параметры, воспринимаемые программой, а также более подробное справочное сообщение.
• Библиотека может генерировать обычные сообщения об ошибках.
Подобно функции getoptlong(), библиотека popt поддерживает короткие и длинные параметры.
Библиотека popt является в высшей степени доступной и может работать на любой POSIX-платформе. Самую последнюю версию библиотеки можно найти по адресу ftp://ftp.rpm.org/pub/rpm. Библиотека popt обладает целым рядом функциональных возможностей, не упоминаемых в этой главе; их описание можно найти на man-странице для popt.
Библиотека popt может распространяться либо под лицензией General Public License GNU, либо под лицензией Library General Public License GNU.
26.1. Таблица параметров
26.1.1. Определение параметров
Приложения передают библиотеке popt информацию о своих параметрах командной строки через массив структур struct poptOption.