Выбрать главу

$ ./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, " -l\n");

 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\n", 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, "сбой записи: %s\n", 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, "ошибка чтения базы данных: %s\n"

120:     dperrmsg(dpecode));

121:

122:   rc = 1;

123:  } else {

124:   printf("%s %s\n", 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:  /* открыть базу данных для обновления */