#include #include #include #include #define __BDatos_CPP #include "d:\program\src_dos\libs\bdatos\BDatos.hh" // ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ #define PROG_NAME "BDatos::JD::" // ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ #define VER_HI 1 #define VER_LOW 0 #define ARCH_LEN 12 #define FALSO 0 #define CIERTO 1 typedef struct { char code; long pos; } BTree; /**************************************************************************\ | | | Contructor de Clase | | | | Descripcion: | | Se encarga de poner a cero todas las variables utilizadas | | | | | | Entradas: (ninguna) | | | | Salidas: (ninguna) | | | \**************************************************************************/ BDatos::BDatos() { BDatosHeader.NRegistros = 0; BDatosHeader.NRegTotal = 0; BDatosHeader.SizeReg = 0; BDatosHeader.VerHi = VER_HI; BDatosHeader.VerLow = VER_LOW; BDatosHeader.Eof_Code = 26; strcpy( BDatosHeader.NBD, "BDatos::JD::" ); memset( BDatosHeader.MyHeader.ProgName, 32, sizeof(char)* 15 ); BDatosHeader.MyHeader.VerHi = 0; BDatosHeader.MyHeader.VerLow = 0; memset( BDatosHeader.MyHeader.Other, 32, sizeof(char)*200 ); NRegActual = 0; lError = 0x00; *cError = 0x00; rError = ERROR; } /**************************************************************************\ | | | Destructor de clase | | | | Descripcion: | | Finaliza las operaciones pendientes. | | | | | | Entradas: (ninguno) | | | | Salidas: (ninguna) | | | | | \**************************************************************************/ BDatos::~BDatos() { if ( rError == ERROR ) return; fclose( handle_BDatos ); } /**************************************************************************\ | | | Registros | | | | Descripcion: | | Obtiene el n£mero de registros total de la base de datos. | | | | | | Entradas: (ninguna) | | | | Salidas: numero de registros | | | \**************************************************************************/ long BDatos::Registros(void) { return BDatosHeader.NRegistros; } /**************************************************************************\ | | | NRegTotal | | | | Descripcion: | | Obtiene el n£mero de registros total, total del la base. | | | | | | Entradas: (ninguna) | | | | Salidas: numero de registros | | | \**************************************************************************/ long BDatos::NRegTotal(void) { return BDatosHeader.NRegTotal; } /**************************************************************************\ | | | RegActual | | | | Descripcion: | | Obtiene el n£mero de registro actual. | | | | | | Entradas: (ninguna) | | | | Salidas: numero de registro en tratamiento | | | \**************************************************************************/ long BDatos::RegActual(void) { return NRegActual; } /**************************************************************************\ | | | AbrirReg | | | | Descripcion: | | Abre los ficheros indices y datos. | | | | | | Entradas: nombre fichero "sin comodines" | | longitud de un registro "en bytes" | | | | Salidas: OK ( todo va bien ) | | ERROR ( error ) | | | | | \**************************************************************************/ int BDatos::AbrirReg(char *file, long sizereg) { // char bdatos[ARCH_LEN]; char *bdatos; bdatos = file; BDatosHeader.MyHeader = MyHeader; Header NewHeader = BDatosHeader; rError = OK; strncpy( bdatos, file, ARCH_LEN ); if ( (handle_BDatos = fopen( bdatos, "r+b" ) ) == NULL ) { // Inicializamos una nueva base de datos if ( (handle_BDatos = fopen( bdatos, "w" ) ) == NULL ) { lError = 0x01; ObtenError( lError ); return (rError = ERROR); } rewind( handle_BDatos ); BDatosHeader.SizeReg = sizereg; fwrite( &BDatosHeader, sizeof( BDatosHeader ), 1, handle_BDatos ); fclose( handle_BDatos ); if ( (handle_BDatos = fopen( bdatos, "r+b" ) ) == NULL ) { lError = 0x01; ObtenError( lError ); return (rError = ERROR); } } else { rewind( handle_BDatos ); fread( &BDatosHeader, sizeof(BDatosHeader), 1, handle_BDatos); if ( BDatosHeader.SizeReg != sizereg || BDatosHeader.VerHi != NewHeader.VerHi ) { lError = 0x03; ObtenError( lError ); fclose( handle_BDatos ); return (rError = ERROR); } } return OK; } /**************************************************************************\ | | | CerrarReg | | | | Descripcion: | | Cierra la base de datos. | | | | | | Entradas: (ninguno) | | | | Salidas: OK ( todo va bien ) | | ERROR ( error ) | | | \**************************************************************************/ void BDatos::CerrarReg( void ) { if ( rError == ERROR ) return; fclose( handle_BDatos ); rError = ERROR; } /**************************************************************************\ | | | LeeReg | | | | Descripcion: | | Lee el registro de la posici¢n 'pos' y lo almacena en 'dato' | | | | | | Entradas: puntero a los datos | | posicion a leer | | | | Salidas: OK ( todo va bien ) | | ERROR ( error ) | | | \**************************************************************************/ int BDatos::LeeReg( void *dato, long pos ) { BTree inx; if ( rError == ERROR ) { lError = 0x05; ObtenError( lError ); return ERROR; } if ( pos > BDatosHeader.NRegistros || pos < 0 ) { lError = 0x04; ObtenError( lError ); return ERROR; } NRegActual = pos; fseek( handle_BDatos, (long)( pos * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &inx, sizeof( BTree ), 1, handle_BDatos ); if ( inx.pos < 0 || inx.code != ' ' ) { lError = 0x04; ObtenError( lError ); return ERROR; } fseek( handle_BDatos, (long)( inx.pos * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) + sizeof( BTree ) ), SEEK_SET ); fread ( dato, BDatosHeader.SizeReg, 1, handle_BDatos ); return OK; } /**************************************************************************\ | | | EscribeReg | | | | Descripcion: | | Escribe el registro en la posici¢n 'pos' de 'dato' | | | | | | Entradas: puntero a los datos | | posicion a escribir | | | | Salidas: OK ( todo va bien ) | | ERROR ( error ) | | | \**************************************************************************/ int BDatos::EscribeReg( void *dato, long pos ) { BTree inx; if ( rError == ERROR ) { lError = 0x05; ObtenError( lError ); return ERROR; } if ( pos > BDatosHeader.NRegistros || pos < 0 ) { lError = 0x04; ObtenError( lError ); return ERROR; } NRegActual = pos; fseek( handle_BDatos, (long)( pos * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &inx, sizeof( BTree ), 1, handle_BDatos ); if ( inx.pos < 0 || inx.code != ' ' ) { lError = 0x04; ObtenError( lError ); return ERROR; } fseek( handle_BDatos, (long)( inx.pos * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) + sizeof( BTree ) ), SEEK_SET ); fwrite( dato, BDatosHeader.SizeReg, 1, handle_BDatos ); return OK; } /**************************************************************************\ | | | InsReg | | | | Descripcion: | | Inserta un registro, en la posici¢n 'pos' por arriba o abajo | | | | | | Entradas: puntero a los datos a insertar, posici¢n, ARRIBA o ABAJO | | | | Salidas: (ninguna) | | | \**************************************************************************/ int BDatos::InsReg( void *dato, long pos, char ab ) { BTree inx, old_inx; unsigned long avance; long RegTot; if ( rError == ERROR ) { lError = 0x05; ObtenError( lError ); return ERROR; } // Filtro los datos conflictivos if ( pos == 0 && BDatosHeader.NRegistros == 1 && ab == ARRIBA ) { pos = 1; } else if ( pos == (BDatosHeader.NRegistros - 1) && ab == ARRIBA ) { pos = BDatosHeader.NRegistros; } BDatosHeader.NRegistros++; if ( pos > (BDatosHeader.NRegistros-1) || pos < 0 ) // if ( pos >= (BDatosHeader.NRegistros-1) && BDatosHeader.NRegistros!=1 ) { BDatosHeader.NRegistros--; lError = 0x04; ObtenError( lError ); return ERROR; } // Si hay fichas eliminadas, utilizamos sus direcciones intermedias. if ( (BDatosHeader.NRegTotal - ( BDatosHeader.NRegistros - 1 ) ) > 0 ) { fseek( handle_BDatos, (long)( ( BDatosHeader.NRegistros - 1 ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &old_inx, sizeof( BTree ), 1, handle_BDatos ); } else { old_inx.pos = ( BDatosHeader.NRegistros - 1 ); BDatosHeader.NRegTotal++; } // |<---------- RegTot ----------->| // |<----- NRegistros ---->| | // ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ // ³ 1 ³ 2 ³ 5 ³ 6 ³ 4 ³ 3 ³ * ³ * ³ ³ ³ ³ ³ ³ // ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ // // 2 up Âpos+1 // ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ // ³ 1 ³ 2 ³ * ³ 5 ³ 6 ³ 4 ³ 3 ³ * ³ ³ ³ ³ ³ ³ // ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ // 2 down Âpos // ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ // ³ 1 ³ * ³ 2 ³ 5 ³ 6 ³ 4 ³ 3 ³ * ³ ³ ³ ³ ³ ³ // ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ avance = ( BDatosHeader.NRegistros - 1 ); while ( avance > ( pos + ab ) ) { fseek( handle_BDatos, (long)( ( avance - 1 ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &inx, sizeof( BTree ), 1, handle_BDatos ); fseek( handle_BDatos, (long)( ( avance ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fwrite( &inx, sizeof( BTree ), 1, handle_BDatos ); avance--; }; if ( ( BDatosHeader.NRegistros - 1 ) == 0 ) fseek( handle_BDatos, sizeof( Header ), SEEK_SET); else { ab = ( ( BDatosHeader.NRegistros - 1 ) <= ( pos + ab ) ) ? 0 : ab; fseek( handle_BDatos, (long)( ( pos + ab ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); } NRegActual = ( BDatosHeader.NRegistros - 1 ) == 0 ? 0 : pos + ab; old_inx.code = ' '; fwrite( &old_inx, sizeof( BTree ), 1, handle_BDatos ); fseek( handle_BDatos, (long)( ( old_inx.pos ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) + sizeof( BTree ) ), SEEK_SET ); fwrite( dato, BDatosHeader.SizeReg, 1, handle_BDatos ); rewind( handle_BDatos ); fwrite( &BDatosHeader, sizeof( Header ), 1, handle_BDatos ); return OK; } /**************************************************************************\ | | | DelReg | | | | Descripcion: | | Borra un registro, de la posici¢n 'pos' | | | | | | Entradas: posici¢n a borrar | | | | Salidas: (ninguna) | | | \**************************************************************************/ int BDatos::DelReg( long pos ) { BTree inx, old_inx; if ( rError == ERROR ) { lError = 0x05; ObtenError( lError ); return ERROR; } BDatosHeader.NRegistros--; if ( pos > BDatosHeader.NRegistros || pos < 0) { BDatosHeader.NRegistros++; lError = 0x04; ObtenError( lError ); return ERROR; } fseek( handle_BDatos, (long)( ( pos ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &old_inx, sizeof( BTree ), 1, handle_BDatos ); // |<---------- RegTot ----------->| // |<----- NRegistros ---->| | // ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ // ³ 1 ³ 2 ³ 5 ³ 6 ³ 4 ³ 3 ³ * ³ * ³ ³ ³ ³ ³ ³ // ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ // unsigned long avance; avance = pos; while ( avance < BDatosHeader.NRegistros ) { fseek ( handle_BDatos, (long)( ( avance + 1 ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread ( &inx, sizeof( BTree ), 1, handle_BDatos ); fseek ( handle_BDatos, (long)( ( avance ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fwrite( &inx, sizeof( BTree ), 1, handle_BDatos ); avance++; }; NRegActual = BDatosHeader.NRegistros == 1 ? 0 : ( BDatosHeader.NRegistros - 1); fseek( handle_BDatos, (long)( ( BDatosHeader.NRegistros ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); old_inx.code = '*'; fwrite( &old_inx, sizeof( BTree ), 1, handle_BDatos ); rewind( handle_BDatos ); fwrite( &BDatosHeader, sizeof( Header ), 1, handle_BDatos ); return OK; } /**************************************************************************\ | | | ShortReg | | | | Descripcion: | | Corta el fichero y lo hace mas peque¤o. | | | | | | Entradas: (ninguna) | | | | Salidas: (ninguna) | | | \**************************************************************************/ int BDatos::ShortReg(void) { long avance, recorrido; BTree inx, curr_inx; void *SWAPdatos; char enc; if ( ( BDatosHeader.NRegTotal - BDatosHeader.NRegistros ) <= 0 ) return OK; if ( ( SWAPdatos = calloc( 1, BDatosHeader.SizeReg ) ) == NULL ) { lError = 0x07; ObtenError( lError ); return ERROR; } avance = BDatosHeader.NRegTotal-1; while( avance >= BDatosHeader.NRegistros ) { // Obtengo la direcci¢n del campo que est  libre y el dato. fseek( handle_BDatos, (long)( ( avance ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &inx, sizeof( BTree ), 1, handle_BDatos ); fread( SWAPdatos, BDatosHeader.SizeReg, 1, handle_BDatos ); // Busco la direcci¢n del indice para la ficha actual. recorrido = avance; enc = FALSO; while( recorrido >= 0 && !enc ) { fseek( handle_BDatos, (long)( ( recorrido ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &curr_inx, sizeof( BTree ), 1, handle_BDatos ); if ( curr_inx.pos == avance ) enc = CIERTO; else recorrido--; } // Si alguien de fuera referencia a esa ficha... if ( enc ) { curr_inx.pos = inx.pos; //Actualizo el indice para comunicarle la nueva posici¢n. fseek( handle_BDatos, (long)( ( recorrido ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fwrite( &curr_inx, sizeof( BTree ), 1, handle_BDatos ); // Pongo la ficha actual en la direcci¢n libre. fseek ( handle_BDatos, (long)( ( curr_inx.pos ) * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) + sizeof( BTree ) ), SEEK_SET ); fwrite( SWAPdatos, BDatosHeader.SizeReg, 1, handle_BDatos ); } avance--; }; // Actualizo la base de registros NRegActual = BDatosHeader.NRegistros - 1; BDatosHeader.NRegTotal = BDatosHeader.NRegistros; rewind( handle_BDatos ); fwrite( &BDatosHeader, sizeof( Header ), 1, handle_BDatos ); // Corto todo lo que sobra de fichero if ( chsize( fileno(handle_BDatos), (long)(sizeof( Header ) + ( BDatosHeader.NRegistros * ( sizeof( BTree ) + BDatosHeader.SizeReg ) )) ) == -1 ) { lError = 0x08; ObtenError( lError ); return OK; // Este error no es del todo grave, pero se avisa. } free( SWAPdatos ); return OK; } /**************************************************************************\ | | | ObtenError | | | | Descripcion: | | Obtiene el error correspondiente al codigo dado. | | | | | | Entradas: codigo de error | | | | Salidas: (ninguna) | | | \**************************************************************************/ void BDatos::ObtenError( int code ) { switch( code ) { case 0x00: strcpy( cError, "No hay errores" ); break; case 0x01: strcpy( cError, "Imposible inicializar base de datos" ); break; case 0x02: strcpy( cError, "No se puede abrir el fichero" ); break; case 0x03: strcpy( cError, "Version de fich. incompatible" ); break; case 0x04: strcpy( cError, "No se pudo acceder a esa posici¢n." ); break; case 0x05: strcpy( cError, "No hay base de datos en uso..." ); break; case 0x06: strcpy( cError, "Tama¤os de estructuras no coinciden" ); break; case 0x07: strcpy( cError, "Memoria insuficiente. Operaci¢n cancelada" ); break; case 0x08: strcpy( cError, "Acceso de operacion no permitida." ); break; } } /**************************************************************************\ | | | SortReg | | | | Descripcion: | | Ordena la base de datos seg£n especifique el usuario en su | | funci¢n fcmp... | | | | Entradas: /**************************************************************\ | | | fcmp || | | || | | Descripcion: || | | funci¢n de entrada a SortReg, debe ser realizada || | | por el usuario y debe ce¤irse a sus par metros.. || | | || | | Entradas: ptrs. a dos estructuras de usuario. ( ejm. A, B ) || | | Salidas: >> 0 si A >> B || | | == 0 si A == B || | | << 0 si A << B || | \************************************************************** | | | | | | | | | | Salidas: ERROR se cargan los registros con el codigo de error esp. | | OK todo ha ido bien | | | \**************************************************************************/ int BDatos::SortReg( int (*fcmp)(const void *, const void *) ) { char dev; // Pido memoria para mantener dos elementos auxiliares if ( ( A = calloc( 1, BDatosHeader.SizeReg ) ) == NULL || ( B = calloc( 1, BDatosHeader.SizeReg ) ) == NULL ) { lError = 0x07; ObtenError( lError ); return ERROR; } dev = SortRegi( fcmp, 0, BDatosHeader.NRegistros-1 ); free(A); free(B); return dev; } int BDatos::SortRegi( int (*fcmp)(const void *, const void *), long izquierda, long derecha ) { BTree inx1, inx2; register long i, j; i = izquierda; j = derecha; if ( LeeReg( A, (long)(izquierda+derecha)/2 + 1 ) != OK ) { lError = 0x04; ObtenError( lError ); return ERROR; } do { if ( LeeReg( B, i )!= OK ) { lError = 0x04; ObtenError( lError ); return ERROR; } while( i < derecha && fcmp( B, A ) < 0 ) { i++; if ( LeeReg( B, i ) != OK ) { lError = 0x04; ObtenError( lError ); return ERROR; } }; LeeReg( B, j ); while( j > izquierda && fcmp( A, B ) < 0 ) { j--; if ( LeeReg( B, j ) != OK ) { lError = 0x04; ObtenError( lError ); return ERROR; } }; if ( i <= j ) { // Intercambiamos solo los indices sin chequear si son // accesibles, ( si no lo fueran, se abria abortado ) fseek( handle_BDatos, (long)( i * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &inx1, sizeof( BTree ), 1, handle_BDatos ); fseek( handle_BDatos, (long)( j * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fread( &inx2, sizeof( BTree ), 1, handle_BDatos ); fseek( handle_BDatos, (long)( j * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fwrite( &inx1, sizeof( BTree ), 1, handle_BDatos ); fseek( handle_BDatos, (long)( i * ( sizeof( BTree ) + BDatosHeader.SizeReg ) + sizeof( Header ) ), SEEK_SET ); fwrite( &inx2, sizeof( BTree ), 1, handle_BDatos ); i++; j--; } } while( i <= j ); if ( izquierda < j ) SortRegi( fcmp, izquierda, j ); if ( i < derecha ) SortRegi( fcmp, i, derecha ); return OK; }