BDATOS/BDATOS.CPP
2021-09-03 17:42:38 +02:00

735 lines
30 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <io.h>
#include <mem.h>
#include <alloc.h>
#include <string.h>
#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;
}