25.5. Пример

We use cookies. Read the Privacy and Cookie Policy

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] <имя> <телефон> ");

 17:  fprintf(stderr, " -d <имя> ");

 18:  fprintf(stderr, " -q <имя> ");

 19:  fprintf(stderr, " -l ");

 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: %s ", 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 уже существует ", name);

 89:   } else {

 90:    fprintf(stderr, "сбой записи: %s ", 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 не существует ", argv[0]);

118:   else

119:    fprintf(stderr, "ошибка чтения базы данных: %s "

120:     dperrmsg(dpecode));

121:

122:   rc = 1;

123:  } else {

124:   printf("%s %s ", 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 не существует ", argv[0]);

148:   else

149:    fprintf(stderr, "ошибка удаления элемента: %s ",

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 %s ", 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: }