#include Banco_Dados::Banco_Dados(String arquivo, Lista_Simples &campos) { this->arquivo = arquivo; this->campos = campos.Copia(); // Coloca as bibliotecas string.h em modo portugues String foo; foo.Localizacao("pt_BR"); if ((fp = fopen(this->arquivo.Texto(),"r+")) == NULL) // provavelmente o arquivo nao existe if ((fp = fopen(this->arquivo.Texto(),"w+")) == NULL) // provavelemente não se tem permissao de escrita fprintf(stderr,"ERROR: could not open file '%s' to read and write. Check your permissions and disk space.\n",this->arquivo.Texto()); Indice_Numero = new Indice_Arvore_Binaria("indice.dat","NUMERO","POSICAO",INTEIRO,LONG); Indice_Nome = new Indice_Secundario_Arvore_Binaria("indice_nome.dat","NOME","NUMERO",STRING,INTEIRO); Indice_Idade = new Indice_Secundario_Arvore_Binaria("indice_idade.dat","IDADE","NUMERO",INTEIRO,INTEIRO); Indice_Diagnostico = new Indice_Secundario_Arvore_Binaria("indice_diagnostico.dat","DIAGNOSTICO","NUMERO",STRING,INTEIRO); Indice_Tratamento = new Indice_Secundario_Arvore_Binaria("indice_tratamento.dat","TRATAMENTO","NUMERO",STRING,INTEIRO); estado_le_cabecalho = Le_Cabecalho(); PrimeiraPosicao = Pega_Posicao(); Inicia_Indices(); } void Banco_Dados::Inicia_Indices() { Registro *reg; if ( (Indice_Numero->Le() < 0) || (Indice_Nome->Le() < 0) || (Indice_Idade->Le() < 0) || (Indice_Diagnostico->Le() < 0) || (Indice_Tratamento->Le() < 0) ) { Indice_Numero->Apaga(); Indice_Nome->Apaga(); Indice_Idade->Apaga(); Indice_Diagnostico->Apaga(); Indice_Tratamento->Apaga(); Muda_Posicao(PrimeiraPosicao); long posicao; bool continua=true; while (continua) { if (Registro_Removido()) Le_Registro_Texto(); // Isso avança a posicao no disco para o proximo registro else if ((reg=Le_Registro())!= NULL) { Insere_Indices(reg,posicao); } else continua=false; posicao = Pega_Posicao(); } } } void Banco_Dados::Insere_Indices(Registro *reg, long posicao) { Lista_Simples *aux, *laux; // Insere no Indice Numero Indice_Numero->Insere(reg->Numero(),posicao); // Insere no Indice Nome. Insere cada subcampo aux = reg->Nome().Quebra(' '); laux = aux; while (laux != NULL) { Indice_Nome->Insere(laux->Valor(),reg->Numero()); laux = laux->Proximo(); } delete aux; // Insere no Indice Idade. Indice_Idade->Insere(reg->Idade(),reg->Numero()); // Insere no Indice Diagnostico. Indice_Diagnostico->Insere(reg->Diagnostico(),reg->Numero()); // Insere no Indice Tratamento. Insere cada subcampo aux = reg->Tratamento().Quebra('/'); laux = aux; while (laux != NULL) { Indice_Tratamento->Insere(laux->Valor(),reg->Numero()); laux = laux->Proximo(); } delete aux; } Banco_Dados::~Banco_Dados() { Indice_Numero->Escreve(); delete Indice_Numero; Indice_Nome->Escreve(); delete Indice_Nome; Indice_Idade->Escreve(); delete Indice_Idade; Indice_Diagnostico->Escreve(); delete Indice_Diagnostico; Indice_Tratamento->Escreve(); delete Indice_Tratamento; fclose(fp); if (campos != NULL) delete campos; } void Banco_Dados::Apaga() { fclose(fp); fp = fopen(this->arquivo.Texto(),"w+"); Indice_Numero->Apaga(); Indice_Nome->Apaga(); Indice_Idade->Apaga(); Indice_Diagnostico->Apaga(); Indice_Tratamento->Apaga(); Escreve_Cabecalho(); } bool Banco_Dados::Insere(int numero, String nome, int idade, String diagnostico, String tratamento) { Registro reg(delimitador); if (Indice_Numero->Procura(numero,NULL) == true) // Existe return false; else { reg.Muda_Valor(numero,nome,idade,diagnostico,tratamento); // vai para a ultima posicao, remover isto quando fizer uma inserção no lugar do último excluído Muda_Posicao(0,SEEK_END); posicao = Pega_Posicao(); fprintf(fp,"%s%c",reg.Texto().Texto(), delimitador_registro); Muda_Posicao(0,SEEK_CUR); // assegura sincronismo Insere_Indices(®,posicao); return true; } } bool Banco_Dados::Remove(int numero) { Registro *reg = NULL; long posicao; if ((Indice_Numero->Procura(numero, &posicao)) == false) return false; Muda_Posicao(posicao); // Início de frescura reg = Le_Registro(); Muda_Posicao(posicao); String preenche; for (unsigned int i=0; i < strlen(reg->Texto().Texto()); i++) preenche += char_removido; // Fim da frescura. // Obs.: Se for tirar a frescura, mude abaixo, tirando o preenche.Texto() e substitua por "#" fprintf(fp, preenche.Texto()); Muda_Posicao(0,SEEK_CUR); //assegura sincronismo Indice_Numero->Remove(numero ,posicao); // Remover de outros indices return true; } Registro *Banco_Dados::Procura_Numero(int valor) { long posicao=0; if (Indice_Numero->Procura(valor ,&posicao) == true) { Muda_Posicao(posicao); return Le_Registro(); } return NULL; } void Banco_Dados::Escreve_Cabecalho() { Muda_Posicao(0); fprintf(fp,"%c%c%c",char_removido,delimitador,delimitador_registro); if (campos != NULL) { Lista_Simples *laux = campos; while (laux != NULL) { fprintf(fp,"%s",laux->Valor().Texto()); if (laux->Proximo() != NULL) fprintf(fp,"%c",delimitador); laux = laux->Proximo(); } fprintf(fp,"%c",delimitador_registro); } else { fprintf(stderr,"ERRO: campos == NULL ! (Impossível)\n"); } }; /** * Le_Cabecalho: lê o cabeçalho deste índice do arquivo apontado por 'fp' e retorna se é compatível ao índice atual. *@param fp apontador para FILE, onde deve ser lido o caceçalho */ int Banco_Dados::Le_Cabecalho() { char char_removido_padrao='#'; char delimitador_padrao=';'; char delimitador_registro_padrao='\n'; String registro_texto; Muda_Posicao(0); if (fscanf(fp,"%c%c%c",&char_removido,&delimitador,&delimitador_registro) == EOF) { char_removido=char_removido_padrao; delimitador=delimitador_padrao; delimitador_registro=delimitador_registro_padrao; Escreve_Cabecalho(); return -2; } registro_texto = Le_Registro_Texto(); Lista_Simples *lista = registro_texto.Quebra(delimitador); registro_texto = ""; Lista_Simples *aux1 = lista; Lista_Simples *aux2 = campos; // conferência para ver se o que o usuário quer é o que existe no arquivo bool continua = true; while ((continua) && (aux1 != NULL) && (aux2 != NULL)) { if (aux1->Valor() != aux2->Valor()) continua = false; aux1 = aux1->Proximo(); aux2 = aux2->Proximo(); } delete lista; if ((continua==false) || ((aux1!=NULL) && (aux2==NULL)) || ((aux1==NULL) && (aux2 != NULL))) return -3; return 0; }; long Banco_Dados::Pega_Posicao() { return ftell(fp); } bool Banco_Dados::Muda_Posicao(long posicao, int onde) { return (fseek(fp,posicao,onde) == 0); } bool Banco_Dados::Muda_Posicao(long posicao) { return Muda_Posicao(posicao,SEEK_SET); } bool Banco_Dados::Registro_Removido() { long posicao=Pega_Posicao(); bool removido=false; if ((char)fgetc(fp) == char_removido) removido=true; Muda_Posicao(posicao); return removido; } String Banco_Dados::Le_Registro_Texto() { String linha(""); char c; while (((c=fgetc(fp)) != EOF) && (c!=delimitador_registro)) linha += c; if (linha.Texto()[0] == char_removido) linha=""; return linha; } Registro *Banco_Dados::Le_Registro() { String texto; Registro *registro = NULL; texto = Le_Registro_Texto(); if (!texto.Vazia()) registro = new Registro(delimitador,texto); return registro; } int Banco_Dados::Estado_Le_Cabecalho() { return estado_le_cabecalho; } bool Banco_Dados::Media(String campo, double *media) { Registro *reg; int i=0; double soma = 0; if (campo == "idade") { Muda_Posicao(PrimeiraPosicao); while ((reg = Le_Registro()) != NULL) { i++; soma+=reg->Idade(); delete reg; } } if (i == 0) { if (media != NULL) *media = 0; return false; } else { if (media != NULL) *media = (soma/i); return true; } } Lista_Simples *Banco_Dados::Procura(String nome, String idade, String diagnostico, String tratamento) { Lista_Simples *resultado_final = NULL; Lista_Simples *> *resultado = NULL; Lista_Simples *> *aponta = NULL; Lista_Simples *lista_resultado = NULL, *lista_resultado_aux = NULL; Lista_Simples *lista_a = NULL; Lista_Simples *lista_b = NULL; Lista_Simples *aponta_a = NULL; Lista_Simples *aponta_b = NULL; /* * Procura nos índices secundários, obtendo uma lista com chaves primárias para cada. */ if (!nome.Vazia()) { Lista_Simples *nomes,*nomes_tmp; nomes = nome.Quebra(' '); nomes_tmp = nomes; while (nomes_tmp != NULL) { if (resultado == NULL) { resultado = new Lista_Simples *>(Insere_Ordenado(Indice_Nome->Procura(nomes_tmp->Valor()))); } else { resultado->Add_Depois(Insere_Ordenado(Indice_Nome->Procura(nomes_tmp->Valor()))); } nomes_tmp = nomes_tmp->Proximo(); } delete(nomes); } if (!idade.Vazia()) { if (resultado == NULL) { resultado = new Lista_Simples *>(Insere_Ordenado(Indice_Idade->Procura(idade.Para_Int()))); } else { resultado->Add_Depois(Insere_Ordenado(Indice_Idade->Procura(idade.Para_Int()))); } } if (!diagnostico.Vazia()) { if (resultado == NULL) { resultado = new Lista_Simples *>(Insere_Ordenado(Indice_Diagnostico->Procura(diagnostico))); } else { resultado->Add_Depois(Insere_Ordenado(Indice_Diagnostico->Procura(diagnostico))); } } if (!tratamento.Vazia()) { Lista_Simples *tratamentos, *tratamentos_tmp; tratamentos = tratamento.Quebra('/'); tratamentos_tmp = tratamentos; while (tratamentos_tmp != NULL) { if (resultado == NULL) { resultado = new Lista_Simples *>(Insere_Ordenado(Indice_Tratamento->Procura(tratamentos_tmp->Valor()))); } else { resultado->Add_Depois(Insere_Ordenado(Indice_Tratamento->Procura(tratamentos_tmp->Valor()))); } tratamentos_tmp = tratamentos_tmp->Proximo(); } delete(tratamentos); } aponta = resultado; if (resultado != NULL) { if (resultado->Valor() != NULL) lista_resultado = resultado->Valor()->Copia(); // 1a lista com resultados, tem que ser cópia para não ser liberada duas vezes no loop else return NULL; } else return NULL; while (aponta != NULL) { lista_a = aponta_a = lista_resultado; // compara resultado antigo lista_b = aponta_b = aponta->Valor(); // com a proxima lista de resultado lista_resultado = NULL; // vai ser preenchida depois lista_resultado_aux = NULL; while ((aponta_a != NULL) && (aponta_b != NULL)) { if (aponta_a->Valor() > aponta_b->Valor()) aponta_b = aponta_b->Proximo(); else if (aponta_a->Valor() < aponta_b->Valor()) { aponta_a = aponta_a->Proximo(); } else { // São iguais if (lista_resultado == NULL) { lista_resultado = new Lista_Simples(aponta_a->Valor()); lista_resultado_aux = lista_resultado; } else { lista_resultado_aux->Add_Depois(aponta_a->Valor()); lista_resultado_aux = lista_resultado_aux->Proximo(); } aponta_a = aponta_a->Proximo(); aponta_b = aponta_b->Proximo(); } } delete lista_a; // apaga o resultado antigo delete lista_b; // apaga a lista com resultados para um determinado subíndice aponta = aponta->Proximo(); } delete resultado; // apaga toda a lista com resultados aponta_a = lista_resultado; // Cria lista com os Registros-Resultado Lista_Simples *resultado_final_aux = NULL; Registro *reg=NULL; while (aponta_a != NULL) { reg = Procura_Numero(aponta_a->Valor()); if (reg != NULL) { if (resultado_final == NULL) { resultado_final = new Lista_Simples(*reg); resultado_final_aux = resultado_final; } else { resultado_final_aux->Add_Depois(*reg); resultado_final_aux = resultado_final_aux->Proximo(); } delete reg; } aponta_a = aponta_a->Proximo(); } delete(lista_resultado); return(resultado_final); } Lista_Simples *Banco_Dados::Insere_Ordenado(Lista_Simples *lista) { Lista_Simples *lista_ord = new Lista_Simples; Lista_Simples *aponta = lista_ord; Lista_Simples *aponta_antes = lista_ord; Lista_Simples *lista_tmp = lista; bool boo; if (lista_tmp == NULL) return(NULL); lista_ord->Muda_Valor(-1); while (lista_tmp != NULL) { if (Indice_Numero->Procura(lista_tmp->Valor(),NULL)) { aponta_antes = lista_ord; aponta = aponta_antes->Proximo(); boo = false; while (boo == false) { if (aponta != NULL) { if ((aponta_antes->Valor() < lista_tmp->Valor()) && (aponta->Valor() > lista_tmp->Valor())) { aponta_antes->Add_Depois(lista_tmp->Valor()); boo = true; } else { aponta_antes = aponta; aponta = aponta->Proximo(); } } else { aponta_antes->Add_Depois(lista_tmp->Valor()); boo = true; } } } lista_tmp = lista_tmp->Proximo(); } aponta = lista_ord->Remove(); delete(lista_ord); return(aponta); }