Основы программирования в Linux
case '?':default:fprintf(stderr, "Usage: %s [-i]\n", prog_name);result = EXIT_FAILURE;break;} /* switch */} /* while */return(result);}Упражнение 7.16. Файл cd_access.cТеперь переходите к функциям доступа к базе данных dbm.
1. Как обычно, начните с нескольких файлов
. Далее примените директивы#includeдля задания файлов, которые будут использоваться для хранения данных:#define#define _XOPEN_SOURCE#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <string.h>#include <ndbm.h>/* В некоторых дистрибутивах файл в предыдущей строке может быть придется заменить на gdbm-ndbm.h */#include "cd_data.h"#define CDC_FILE_BASE "cdc_data"#define CDT_FILE_BASE "cdt_data"#define CDC_FILE_DIR "cdc_data.dir"#define CDC_FILE_PAG "cdc_data.pag"#define CDT_FILE_DIR "cdt_data.dir"#define CDT_FILE_PAG "cdt_data.pag"2. Используйте эти две переменные области действия файла для отслеживания текущей базы данных:
static DBM *cdc_dbm_ptr = NULL;static DBM *cdt_dbm_ptr = NULL;3. По умолчанию функция
открывает существующую базу данных, но передав ненулевой (т.е. true) параметрdatabase_initialize, вы можете заставить ее создать новую (пустую) базу данных, при этом существующая база данных удаляется. Если база данных успешно инициализирована, также инициализированы и два ее указателя, указывающие на то, что база данных открыта.new_databaseint database_initialize(const int new_database) {int open_mode = O_CREAT | O_RDWR;/* Если открыта какая-либо имеющаяся база данных, закрывает ее */if (cdc_dbm_ptr) dbm_close(cdc_dbm_ptr);if (cdt_dbm_ptr) dbm_close(cdt_dbm_ptr);if (new_database) {/* Удаляет старые файлы */(void)unlink(CDC_FILE_PAG);(void)unlink(CDC_FILE_DIR);(void)unlink(CDT_FILE_PAG);(void)unlink(CDT_FILE_DIR);}/* Открывает несколько новых файлов, создавая их при необходимости */cdc_dbm_ptr = dbm_open(CDC_FILE_BASE, open_mode, 0644);cdt_dbm_ptr = dbm_open(CDT_FILE_BASE, open_mode, 0644);if (!cdc_dbm_ptr || !cdt_dbm_ptr) {fprintf(stderr, "Unable to create database\n");cdc_dbm_ptr = cdt_dbm_ptr = NULL;return (0);}return (1);}4. Функция
просто закрывает базу данных, если она была открыта и устанавливает указатели базы данных вdatabase_close, чтобы показать, что нет открытой базы данных:nullvoid database_close(void) {if (cdc_dbm_ptr) dbm_close(cdc_dbm_ptr);if (cdt_dbm_ptr) dbm_close(cdt_dbm_ptr);cdc_dbm_ptr = cdt_dbm_ptr = NULL;}5. Далее у вас появляется функция, извлекающая единственный элемент каталога, когда передан указатель на строку текста из каталога. Если элемент не найден, у возвращенных данных пустое поле каталога:
cdc_entry get_cdc_entry(const char *cd_catalog_ptr) {cdc_entry entry_to_return;char entry_to_find[CAT_CAT_LEN + 1];datum local data datum;datum local_key_datum;memset(&entry_to_return, '\0', sizeof(entry_to_return));6. Начните с некоторых имеющих смысл проверок, чтобы убедиться в том, что база данных открыта, и вы передали приемлемые параметры, т.е. ключ поиска содержит только допустимую строку и значения
:nullif (!cdc_dbm_ptr || !cdt_dbm_ptr) return (entry_to_return);if (!cd_catalog_ptr) return (entry_to_return);if (strlen(cd_catalog_ptr) >= CAT_CAT_LEN) return (entry_to_return);memset(&entry_to_find, '\0', sizeof(entry_to_find));strcpy(entry_to_find, cd_catalog_ptr);7. Задайте структуру
, нужную функциям базы данных dbm, и используйте функциюdatumдля извлечения данных. Если не извлечены никакие данные, вы возвращаете пустую структуруdbm_fetch, которая была инициализирована ранее:entry_to_returnlocal_key_datum.dptr = (void *) entry_to_find;local_key_datum.dsize = sizeof(entry_to_find);memset(&local_data_datum, '\0', sizeof(local_data_datum));local_data_datum = dbm_fetch(cdc_dbm_ptr, local_key_datum);if (local_data_datum.dptr) {memcpy(&entry_to_return, (char*)local_data_datum.dptr, local_data_datum.dsize);