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

25.5. Пример

25.5. Пример

Для закрепления материала этой главы ниже приводится пример приложения, в котором задействовано большинство функциональных возможностей qdbm. Подразумевается, что в результате выполнения этого приложения будет создана простая база данных телефонных номеров, хотя ее можно использовать и для хранения любых простых пар "имя-значение". Приложение хранит базу данных в домашнем каталоге пользователя как .phonedb.

Флаг добавляет запись в базу данных. Если будет указан флаг -f, то любой существующий элемент будет заменен новыми данными. Следующий параметр представляет собой значение ключа, которое необходимо использовать, а последний параметр — собственно данные (номер телефона).

Флаг -q запрашивает в базе данных определенный ключ, который должен быть представлен другим указанным параметром. Записи удаляются из базы данных с помощью флага -d, который принимает значение ключа для удаления в другом параметре.

Если задать флаг -l, то будут перечислены все пары "ключ-значение", имеющиеся в базе данных.

Вот как выглядят пример использования phones.

$ ./phones -a Erik 374-5876
$ ./phones -a Michael 642-4235
$ ./phones -a Larry 527-7976
$ ./phones -a Barbara 227-2272
$ ./phones -q Larry
Larry 527-7976
$ ./phones -l
Larry 527-7976
Erik 374-5876
Michael 642-4235
Barbara 227-2272
$ ./phones -d Michael
$ ./phones -l
Larry 527-7976
Erik 374-5876
Barbara 227-2272

Эта программа выполняет определенные полезные действия, состоит менее чем из 200 строк исходного кода, и с успехом может применяться для работы с большим количеством пар "ключ-значение", четко раскрывая назначение библиотеки qdbm.

  1: /* phones.с */
  2:
  3: /* Программа реализует очень простую базу данных телефонных номеров.
  4: Всю необходимую информацию по ее использованию можно найти в тексте. */
  5:
  6: #include <alloca.h>
  7: #include <depot.h>
  8: #include <errno.h>
  9: #include <fcntl.h>
 10: #include <stdio.h>
 11: #include <stdlib.h>
 12: #include <string.h>
 13: #include <unistd.h>
 14:
 15: void usage(void) {
 16:  fprintf(stderr, "использование: phones -a [-f] <имя> <телефон>n");
 17:  fprintf(stderr, " -d <имя>n");
 18:  fprintf(stderr, " -q <имя>n");
 19:  fprintf(stderr, " -ln");
 20:  exit(1);
 21: }
 22:
 23: /* Открыть базу данных $НОМЕ/.phonedb. Если writeable имеет ненулевое
 24:    значение, база данных открывается для обновления. Если writeable
 25:    равен 0, база данных открывается только для чтения. */
 26: DEPOT * openDatabase(int writeable) {
 27:  DEPOT * dp;
 28:  char * filename;
 29:  int flags;
 30:
 31:  /* Установить режим открытия */
 32:  if (writeable) {
 33:   flags = DP_OWRITER | DP_OCREAT;
 34:  } else {
 35:   flags = DP_OREADER;
 36:  }
 37:
 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: }

Оглавление книги


Генерация: 0.104. Запросов К БД/Cache: 2 / 0
поделиться
Вверх Вниз