Skip to content

Instantly share code, notes, and snippets.

@brendonhc
Last active June 3, 2018 03:06
Show Gist options
  • Save brendonhc/605f59d814cd1a7952a86b91ddac84d5 to your computer and use it in GitHub Desktop.
Save brendonhc/605f59d814cd1a7952a86b91ddac84d5 to your computer and use it in GitHub Desktop.
Trabalho 2 da disciplina Algoritmos e estrutura de dados 2 - ICMC - USP - 2018
/**
* Implementação de um modelo simples de banco de dados com leitura e escrita
* de arquivos em disco para um trabalho da disciplina Algoritmos e Estrutura
* De dados 2.
* ICMC - USP - 2018
* Professor: João Batista
*
* Autor: Brendon Hudson
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TAMREG 84
#define NDX_LINE_SIZE 10 // XYZ|NNNNN'\n'
#define PKEY 0 // Indice da chave primária na tabela da estrutura indextable_t
#define RRN 1 // Indice do RRN na tabela da estrutura indextable_t
#define NAME_SIZE 40
#define CAR_NAME_SIZE 20
#define LINE_MAX_SIZE 100
typedef unsigned bool_t;
#define TRUE 1
#define FALSE 0
#define SUCCESS_OP 1
#define FAILED_OP -1
#define OUT_OF_DATE_STR "-OutOfDate\0"
/* Enumeração das opções utilizadas no menu "database_driver" */
enum OPERATION {
INSERT = 1, REMOVE, CHANGE, SEARCH, COMPACT, EXIT
};
/**
* Estrutura para subir o arquivo de indices primários para serem manipulados
* na memória principal.
*/
struct indextable_s {
char *path;
char *_flag;
int **index;
size_t size;
};
typedef struct indextable_s * indextable_t;
struct database_s {
char *path;
char *_flag; // indica se seu respectivo arquivo em disco está compactado
int next_offset;
size_t size;
indextable_t ndx;
};
typedef struct database_s * database_t;
/** cmp
* Função auxiliar para ordenar uma tabela int[][] (int **) em ordem crescente
* de sua primeira posição int[0][x] usando a função 'qsort' da stdlib.h.
* Parâmetros:
* const void *a: endereço do primeiro número
* const void *b: endereço do segundo número
* Retorno: 1 se a > b; -1 se a < b; 0 se a == b
*/
int cmp(const void *a, const void *b)
{
int m = *(*((int**)a));
int n = *(*((int**)b));
if (m > n) return 1;
else if (n > m) return -1;
return 0;
}
/** trim **
* Funcao auxiliar que percorre uma dada string de trás para frente eliminando
* os espacos em branco.
* Parâmetros:
* char *str - String que será manipulada
*
* Retorno:
* char * - String dada sem espaços em branco
*/
char *trim(char *str)
{
int i;
for (i = strlen(str)-1; str[i] == ' '; i--);
str[i+1] = '\0';
return str;
}
/** flelinha **
* Função implementada pelo professor "João Batista" da disciplina SCC 0503
* para ler as linhas da tabela de informações inicial no formato que foi
* definido por ele mesmo e passando as informações pertinentes em cada uma
* devolta pelos ponteiros.
* Parêmetros:
* FILE *fp -
* char *number -
* char *name -
* char *car -
*/
void flelinha(FILE *fp, char *number, char *name, char *car)
{
char c;
int i;
// pula "|" inicial
c = fgetc(fp);
// enquanto houver digitos vai lendo e armazena no number
i = 0;
while ((c = fgetc(fp)) != ' ')
number[i++] = c;
number[i] = '\0';
// vai pulando até chegar no name...
while ((c = fgetc(fp)) != '|');
// agora le o name
for (i=0; i<NAME_SIZE;i++)
name[i] = fgetc(fp);
name[i] = '\0';
// elimina os brancos do lado direito...
name = trim(name);
// pula "|"
c = fgetc(fp);
// agora le o car
for (i=0; i<CAR_NAME_SIZE;i++)
car[i] = fgetc(fp);
car[i] = '\0';
// elimina os brancos do lado direito...
car = trim(car);
// pula "|"
c = fgetc(fp);
// pula "\n"
c = fgetc(fp);
}
/** exception
* Função que simula uma exceção genérica imprimindo na saída de erro padrão
* a mensagem passada por parâmetro na tela e encerrando o programa.
* Parâmetros:
* char *msg: String com mensagem a ser escrita na saída de erro padrão
*/
void exception(char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
/** fduplicate
* Função auxiliar que copia exatamente o conteudo de um arquivo em disco
*para outro.
*/
void fduplicate(const char *src_path, const char *dest_path)
{
FILE *src_fp, *dest_fp;
src_fp = fopen(src_path, "r");
dest_fp = fopen(dest_path, "w");
while (!feof(src_fp)) {
fputc(fgetc(src_fp), dest_fp);
}
fclose(src_fp);
fclose(dest_fp);
}
/** indexes_out_of_date
* Função que cria arquivo indicando que a tabela de indices em disco difere
* dos dados contidos na base de dados em disco, e, dentro do arquivo, um
* inteiro correspondente ao número de registros válidos na base de dados, caso
* seja necessário para uma posterior recuperação. */
void indexes_out_of_date(database_t db)
{
FILE *fp = fopen(db->ndx->_flag, "w");
fprintf(fp, "%lu", db->size);
fclose(fp);
}
/** database_not_compacted
* Função que cria um arquivo indicando que o arquivo em disco da base de dados
* não está compactado, ou seja, possui espaços vazios em seu corpo não
* utilizados.
*/
void database_not_compacted(database_t db)
{
fclose(fopen(db->_flag, "w"));
}
/** create_database_with_file_table **
* Função que cria um arquivo de banco de dados formatado no padrão do tipo
* "database_t" e sua respectiva tabela de indices primários a partir de uma
* tabela de informações com um formato pré-definido.
* Parâmetros:
* char *table_name - caminho para a tabela de informações com formato
* pré-definido.
*/
void create_database_with_file_table(char *table_path, char *database_path,
char *index_path)
{
FILE *input_fp, *database_fp, *indexes_fp;
char str[LINE_MAX_SIZE], number[4], name[NAME_SIZE+1], car[CAR_NAME_SIZE+1];
int i, n_registers, offset = 0; // numero de registros....
int **sort_ndx;
// PRIMEIRO
// Abertura e criação dos arquivos no disco
input_fp = fopen(table_path, "r");
if (!input_fp) {
exception("Falha ao abrir tabela inicial");
}
database_fp = fopen(database_path, "w");
if (!database_fp) {
exception("Falha ao criar arquivo da base de dados");
}
indexes_fp = fopen(index_path, "w");
if (!indexes_fp) {
exception("Falha ao criar arquivo de indices primarios");
}
// SEGUNDO
// Leitura da tabela inicial e escrita nos arquivos de dados
// Lê o número de registros
fscanf(input_fp, "nro de registros = %d\n", &n_registers);
// Pula as outras duas linhas iniciais que sao comentarios...
fgets(str,LINE_MAX_SIZE,input_fp);
fgets(str,LINE_MAX_SIZE,input_fp);
// Cria base de dados com as linhas no seguinte formato:
// indice|name|car'\n'
//sort_ndx == tabela de registros em ram para ordena-la
sort_ndx = (int **) malloc(n_registers*sizeof(int *));
for (i = 0; i < n_registers; i++) {
flelinha(input_fp, number, name, car);
sort_ndx[i] = (int *) malloc(2*sizeof(int));
// offset recebe a quandidade de caracteres escritos pelo fprintf
// para guardar a posição do próximo registro livre para os índices
sort_ndx[i][PKEY] = atoi(number);
sort_ndx[i][RRN] = offset;
offset += fprintf(database_fp, "%s|%s|%s\n", number, name, car);
}
// Ordena a tabela de indices primária antes de escreve-la no disco
qsort(sort_ndx, (size_t) n_registers, sizeof(int *), cmp);
for (int i = 0; i < n_registers; i++) {
fprintf(indexes_fp,"%03d|%05d\n", sort_ndx[i][PKEY], sort_ndx[i][RRN]);
}
// push_indexes(tmp_ndx);
fclose(input_fp);
fclose(database_fp);
fclose(indexes_fp);
}
/** exists_file **
* Função que retorna TRUE se existir o arquivo procurado ou retorna FALSE
* se o arquivo não existir.
* Parâmetros:
* char *file_path - String com o caminho do arquivo procurado
* Retorno:
* bool_t - Inteiro 1 ou 0 que representam respectivamente os booleanos
* TRUE (verdadeiro) ou FALSE (falso).
*/
bool_t exists_file(char *file_path)
{
FILE *fp = NULL;
fp = fopen(file_path, "r");
if (fp) {
fclose(fp);
return TRUE;
}
return FALSE;
}
/* database_update_ram_indexes
* (Só pode ser chamada se a base de dados em disco estiver compactada)
* Função que atualiza a estrutura de indices em ram a partir do arquivo
* da base de dados em disco, se, verificar que ambos em disco diferem
*/
void database_update_ram_indexes(database_t db)
{
FILE *database_fp = NULL, *flag_fp = NULL;
int key = 0;
int i = 0, offset = 0;
// Se não existir a flag em disco, já está atualizado, return.
if (!exists_file(db->ndx->_flag)) {return;}
// Se a base de dados não está compactada, não faço o update
if (exists_file(db->_flag)) {
exception("Não foi possível atualizar os indices em ram.\n Base de dados em disco não compactada");
}
// Abertura da base de dados em disco e flag com o número de registros válidos
database_fp = fopen(db->path, "r");
if (!database_fp) {
exception("Falha ao abrir arquivo da base de dados");
}
flag_fp = fopen(db->ndx->_flag, "r");
if (!flag_fp) {
exception("Falha ao abrir arquivo sinalizador c/ numero de registros");
}
// Quantidade de registros válidos na base de dados
fscanf(flag_fp, "%lu", &db->size);
fclose(flag_fp);
db->ndx->size = db->size;
// Leitura do arquivo da base de dados em disco e upload para ram
db->ndx->index = realloc(db->ndx->index, db->size*sizeof(int *));
for (i = 0; i < db->size; i++) {
db->ndx->index[i] = (int *) malloc(2*sizeof(int));
fscanf(database_fp, "%d", &key);
db->ndx->index[i][RRN] = offset;
db->ndx->index[i][PKEY] = key;
// while consome os caracteres até o fim de cada linha
while (fgetc(database_fp) != '\n');
offset += ftell(database_fp);
}
fclose(database_fp);
db->next_offset = offset;
// Ordena a tabela de indices primária antes de escreve-la no disco
qsort(db->ndx->index, db->size, sizeof(int *), cmp);
}
/** database_update_file_indexes
* Função que verifica se o arquivo de indices contido em disco está
* desatualizado pela existência ou não de um arquivo de verificação com nome
* ".arquivo.ndx-outOfDate", caso exista, é feita atualização do "arquivo.ndx"
* e exclusão do arquivo de verificação.
* Parâmetros:
* ndx - Estrutura da tabela de indices na ram, qual será usada para
* atualizar sua correspondente em disco.
*/
void database_update_file_indexes(database_t db)
{
FILE *fp = NULL;
size_t i;
/* Se exists_file retornar "FALSE", o arquivo de flag não existe, assim,
não é necessário atualizar os indices*/
if (!exists_file(db->ndx->_flag)) { return; }
fp = fopen(db->ndx->path, "w");
if (!fp) exception("Problemas em abrir ndx para atualização dos indices");
// Sobrescrevo, linha por linha, as alterações feitas na tabela de indices
for (i = 0; i < db->ndx->size; i++) {
fprintf(fp, "%03d|%05d\n", db->ndx->index[i][PKEY], db->ndx->index[i][RRN]);
}
if (remove(db->ndx->_flag) == -1) {
exception("Problemas ao apagar o arquivo sinalizador de atualização");
}
fclose(fp);
}
/** database_init_indexes
* Função que inicializa e retorna uma estrutura de indices primários na ram
* a partir de seu caminho no disco passado por parâmetro.
* Parâmetros:
* char *path: caminho para o arquivo no disco
*/
void database_init_indexes(database_t db, char *path)
{
FILE *fp;
size_t size = 0, i, j;
char line_counter[NDX_LINE_SIZE];
db->ndx = (indextable_t) malloc(sizeof(struct indextable_s));
if (!db->ndx) { exception("Problemas na alocação de memória para ndx");}
db->ndx->path = path;
// Gerando o nome do arquivo que sinalizará quando as chaves em disco
// estiverem desatualizadas
size = strlen(db->ndx->path) + strlen(OUT_OF_DATE_STR) + 1;
db->ndx->_flag = (char *) malloc(sizeof(char)*size);
db->ndx->_flag[0] = '.'; // '.' oculta arquivo nas distribuições linux
// ndx->_flag = "." + "nomeDoArquivo.ndx" + OUT_OF_DATE_STR
for (i = 1; i <= strlen(db->ndx->path); i++) {
db->ndx->_flag[i] = db->ndx->path[i-1];
}
for (i = i, j = 0; i < size; i++, j++) {
db->ndx->_flag[i] = OUT_OF_DATE_STR[j];
}
size = 0;
// Verifico se o arquivo de indices em disco condiz com a base de dados
if (exists_file(db->ndx->_flag)) { // Se existir, inicio a recuperação
fprintf(stderr, "Tabela de indices em disco incompatível com base de dados\n");
fprintf(stderr, "Recuperando tabela de indices...\n");
database_update_ram_indexes(db);
//database_update_file_indexes(db);
return;
}
// Obtendo o tamanho do arquivo de indicesold_path
fp = fopen(db->ndx->path, "r");
while (fscanf(fp, "%s", line_counter) > 0) {
size++;
}
db->size = size;
db->ndx->size = size;
fseek(fp, 0, SEEK_SET); // Cabeça de leitura no início
db->ndx->index = (int **) malloc(db->ndx->size*sizeof(int *));
if (!db->ndx->index) {
exception("Problemas na alocação de memória para ndx->index");
}
// Subindo a tabela de indices para memória principal
for (i = 0; i < db->ndx->size; i++) {
db->ndx->index[i] = (int *) malloc(2*sizeof(int)); // 2 colunas
if (!db->ndx->index[i]) {
exception("Erro na alocação de memória para ndx->index[i]");
}
fscanf(fp, "%d|%d", &db->ndx->index[i][PKEY], &db->ndx->index[i][RRN]);
}
fclose(fp);
}
/** init_database **
* Função que inicializa um banco de dados a partir de seu arquivo base e
* sobe sua tabela de índices primários na memória principal.
* Parâmetros:
* char *path_database_file - Caminho para o arquivo do banco de dados
* char *path_index_file - Caminho para a tabela de indices do banco
* Retorno:
* database_t - uma entidade contendo a base de dados inicializada
*/
database_t init_database(char *path_database_file, char *path_index_file)
{
int i;
FILE *database_fp = NULL;
database_t db = (database_t) malloc(sizeof(struct database_s));
if (!db) exception("Problema na alocação de memória da base de dados");
db->path = path_database_file;
database_fp = fopen(db->path, "r");
if (!database_fp) exception("Problema na inicialização da base de dados");
fseek(database_fp, 0, SEEK_END);
db->next_offset = ftell(database_fp);
fclose(database_fp);
// nome para arquivo sinalizador de base de dados não compactada
i = strlen(db->path) + 1;
db->_flag = (char *) malloc(sizeof(char)*(i + 5));
db->_flag[0] = '.'; // arquivo oculto no linux
strcpy(&(db->_flag[1]), db->path);
db->_flag[i++] = '.';
db->_flag[i++] = 't';
db->_flag[i++] = 'm';
db->_flag[i++] = 'p';
db->_flag[i] = '\0';
database_init_indexes(db, path_index_file);
return db;
}
/** database_compact
* Função que compacta o arquivo da base de dados em disco removendo relmente
* os registros marcados como apagados com o caracter '#' e enfim, recalculando
* os valores de offset para cada chave na estrutura de indices.
*/
void database_compact(database_t db)
{
FILE *old_fp, *new_fp;
char c;
// Se não existe o arquivo que indica a não compactação, finaliza.
if (!exists_file(db->_flag)) {return;}
/*Passo tudo para o arquivo antigo temporario*/
fduplicate(db->path, db->_flag);
/*Depois de duplicado, copio do temporário só os dados não apagados */
new_fp = fopen(db->path, "w");
old_fp = fopen(db->_flag, "r");
while ((c = fgetc(old_fp)) != EOF ) {
if (c == '#') { // Se for um registro apagado, pula ele
while (fgetc(old_fp) != '\n');
}
else { // Escreve o resto no arquivo novo
fputc(c, new_fp);
}
}
fclose(new_fp);
fclose(old_fp);
// Apago a flag, indicando que agora está compactado
remove(db->_flag);
/* Com a base de dados em disco atualizada, atualizo os "RRN's" (offsets)*/
database_update_ram_indexes(db);
}
/** database_search
* Função que realiza a busca de uma determinada informação dentro da base
* de dados do tipo "database_t" por sua respectiva chave utilizando algoritmo
* de busca binária.
* Parâmetros:
* - db: Estrutura que representa o banco de dados inicializado
* - target: Chave da informação buscada
* Retorno:
* O índice do registro se encontrado, se não, índice próximo negativo
*/
int database_search(database_t db, int target)
{
int left = 0, right = db->size-1, mid;
// Busca binária iterativa, mais rápida que a recursiva
while (left <= right) {
mid = (left + right) / 2;
if (db->ndx->index[mid][PKEY] > target) {
right = mid - 1;
}
else if (db->ndx->index[mid][PKEY] < target) {
left = mid + 1;
}
else {
return mid;
}
}
return mid == 0 ? -1 : -1*mid;
}
/** database_insert
* Função que insere um registro na base de dados.
* Parâmetros:
* campos
*/
int database_insert(database_t db, int n, char *name, char *car)
{
FILE *fp;
int index = database_search(db, n), i;
int *new;
if (index >= 0) {
return FAILED_OP;
}
db->ndx->size++;
db->size = db->ndx->size;
db->ndx->index = realloc(db->ndx->index, db->size*sizeof(int *));
new = (int *) malloc(sizeof(int)*2);
new[PKEY] = n;
new[RRN] = db->next_offset;
/* quando a busca não encontra, ela retorna o vizinho negativo, onde
* poderia estar a chave caso a encontrasse, assim sendo, podemos usar
* esse retorno a nosso favor: */
index = abs(index); // modulo, ou, valor absoluto
// Insere em cima (desce todos a partir de "index" um para baixo)
if (db->ndx->index[index][PKEY] > n) {
for (i = db->size-1; i > index; i--) {
db->ndx->index[i] = db->ndx->index[i-1];
}
db->ndx->index[i] = new;
}
// Insere em baixo (depois) - avança uma posição todos depois de "index"
else if (db->ndx->index[index][PKEY] < n) {
for (i = db->size-1; i > index + 1; i--) {
db->ndx->index[i] = db->ndx->index[i-1];
}
db->ndx->index[i] = new;
}
// Atualizo a base de dados em disco inserindo no final
fp = fopen(db->path, "a");
db->next_offset += fprintf(fp, "%03d|%s|%s\n", n, name, car);
fclose(fp);
// Agora a base de dados e a tabela de indices em disco diferem -> flag
indexes_out_of_date(db);
return SUCCESS_OP;
}
/** database_remove
* Função que remove um registro na base de dados.
* Parâmetros:
* campos
*/
int database_remove(database_t db, int n)
{
FILE *fp;
int index = database_search(db, n), i;
if (index < 0) {
return FAILED_OP;
}
// Index agora tem a posição do registro na tabela de indices
// Com o offset dele (RRN), podemos remove-lo da base de dados em disco
fp = fopen(db->path, "r+");
rewind(fp);
fseek(fp, db->ndx->index[index][RRN], SEEK_SET);
fputc('#', fp); // caracter que indica que a informação foi removida
fclose(fp);
// Agora é necessário re-organizar os indices na ram
// Subo todos os elementos uma casa para mais próximo da primeira posição
db->size--;
db->ndx->size--;
for (i = index; i < db->size; i++) {
db->ndx->index[i] = db->ndx->index[i+1];
}
// A base de dados e a tabela de indices em disco diferem, crio uma flag
indexes_out_of_date(db);
database_not_compacted(db);
return SUCCESS_OP;
}
/** database_change
* Função que manipula as alterações dos registros na base de dados.
* Para melhor eficiencia, a alteração segue o seguinte algoritmo:
* Primeiro verifica se o indice existe, se sim, qual campo será alterado,
* a partir daí, guarda-se os campos que mantém-se o valor, remove o antigo
* e adiciona um novo registro com os novos valores, assim, há menos
* manipulação em disco para calcular novos offsets, e mais e ram para
* organizar a estrutura que contém a tabela de indices.
*/
void database_change(database_t db, int key)
{
FILE *fp;
int index = database_search(db, key), field, num, offset_bkp, i;
char str1[NAME_SIZE], str2[CAR_NAME_SIZE];
char c;
printf("key = %d index = %d\n", key, index);
if (index < 0) {
printf("Erro! Número de registro inexistente na base de dados.");
return;
}
// Se existir, capturar qual campo será alterado
printf("Escolha o campo que deseja alterar:\n");
printf("(1) - Número\t(2) - Nome\t(3) - Carro\n");
scanf("%d", &field);
printf("Digite o novo valor: ");
offset_bkp = db->ndx->index[index][RRN];
fp = fopen(db->path, "r+");
// Primeiro guardo as informações antigas do registro
fseek(fp, offset_bkp, SEEK_SET);
fscanf(fp, "%d", &index); // Leitura da chave
fgetc(fp); // Para consumir o primeiro delimitador '|'
for (i = 0; i < NAME_SIZE; i++) { // Leitura do nome
c = fgetc(fp);
if (c == '|') {
str1[i] = '\0';
break;
}
str1[i] = c;
}
for (i = 0; i < CAR_NAME_SIZE; i++) { // Leitura do carro
c = fgetc(fp);
if (c == '\n') {
str2[i] = '\0';
break;
}
str2[i] = c;
}
fclose(fp);
switch (field) {
case 1: // Alteração da "key"
// Busca pelo numero, se não existir, sobreescreve o desejado
scanf("%d", &num);
if (database_search(db, num) > 0) {
fprintf(stderr, "Não foi possível realizar alteração. Número");
fprintf(stderr, " duplicado.\n");
} else {
database_remove(db, index);
database_insert(db, num, str1, str2);
}
break;
case 2: // Alteração do Nome
scanf("%s", str1);
database_remove(db, index);
database_insert(db, index, str1, str2);
break;
case 3: // Alteração do Carro
scanf("%s", str2);
database_remove(db, index);
database_insert(db, index, str1, str2);
break;
}
}
/** database_driver
* Função que oferece ao usuário do programa no console, comandos para
* gerenciar o banco de dados, como: inserção, busca, remoção, etc.
*/
bool_t database_driver(database_t db)
{
bool_t _exit = FALSE;
int operation;
// Variaveis para argumento das funções do Menu
int arg1;
char arg2[NAME_SIZE], arg3[CAR_NAME_SIZE];
printf("Menu de gerenciamento\nBase de dados: %s\n", db->path);
while (!_exit) {
printf("\nOperações:\n");
printf("\t1) Inserir\n");
printf("\t2) Remover\n");
printf("\t3) Alterar\n");
printf("\t4) Procurar\n");
printf("\t5) Compactar\n");
printf("\t6) Sair\n");
printf("Digite o número da operação desejada: ");
scanf("%d", &operation);
switch (operation) {
case INSERT:
printf("Digite o Numero, Nome e o Veiculo que deseja inserir:\n");
scanf("%d%s%s", &arg1, arg2, arg3);
// Inserção e Feedback
if (database_insert(db, arg1, arg2, arg3) == SUCCESS_OP) {
printf("Registro inserido com sucesso!\n");
}
else {
printf("Erro! Número de chave já existente.\n");
}
break;
case REMOVE:
printf("Digite o número do registro que deseja remover: ");
scanf("%d", &arg1);
// Remoção e Feedback
if (database_remove(db, arg1) == SUCCESS_OP) {
printf("Remoção efetuada com sucesso!\n");
}
else {
fprintf(stderr, "Erro! Número de registro inexistente na base de dados.\n");
}
break;
case CHANGE:
printf("Digite o número do registro em que fará alteração: ");
scanf("%d", &arg1);
database_change(db, arg1);
break;
case SEARCH:
printf("Digite o número do registro que deseja buscar: ");
scanf("%d", &arg1);
// Busca e Feedback
if (database_search(db, arg1) >= 0) {
printf("Chave encontrada!\n");
} else {
printf("Chave não encontrada!\n");
}
break;
case COMPACT:
database_compact(db);
printf("Compactação realizada com sucesso!\n");
break;
case EXIT:
_exit = TRUE;
break;
}
}
return FALSE;
}
void database_close_save(database_t db) {
int i;
database_update_file_indexes(db);
// Liberação da memória alocada para a tabela de indices na ram
for (i = 0; i < db->ndx->size; i++) {
free(db->ndx->index[i]);
}
free(db->ndx->index);
free(db->ndx);
// Liberação da memória alocada para a estrutura database_t
free(db);
}
/** main
* Função main que gerencia a chamada das funções que inicializa e manipula
* a base de dados.
*/
int main(int argc, char **argv)
{
database_t database;
// Se o banco de dados não existir, cria um novo banco de dados
if (!exists_file("dados.txt")) {
create_database_with_file_table("TabelaInicial.txt", "dados.txt",
"primario.ndx");
}
// Inicio a base de dados já criada com seu respectivo arquivo de chaves
database = init_database("dados.txt", "primario.ndx");
// Menu principal para manipular a base de dados pelo terminal
database_driver(database);
database_close_save(database);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment