summaryrefslogtreecommitdiff
path: root/xbase64/xbdbf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbase64/xbdbf.cpp')
-rwxr-xr-xxbase64/xbdbf.cpp2671
1 files changed, 0 insertions, 2671 deletions
diff --git a/xbase64/xbdbf.cpp b/xbase64/xbdbf.cpp
deleted file mode 100755
index d3790cb..0000000
--- a/xbase64/xbdbf.cpp
+++ /dev/null
@@ -1,2671 +0,0 @@
-/* xbdbf.cpp
-
- Xbase64 project source code
-
- This file contains the basic Xbase routines for reading and writing
- Xbase .DBF files.
-
- Copyright (C) 1997,2003 Gary A Kunkel
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
- Contact:
-
- Email:
-
- xdb-devel@lists.sourceforge.net
- xdb-users@lists.sourceforge.net
-
-
- Regular Mail:
-
- XBase Support
- 149C South Main St
- Keller Texas, 76248
- USA
-
-*/
-
-#ifdef __GNU LesserG__
- #pragma implementation "xbdbf.h"
-#endif
-
-#ifdef __WIN32__
-#include <xbase64/xbwincfg.h>
-#else
-#include <xbase64/xbconfig.h>
-#endif
-
-#include <xbase64/xbase64.h>
-
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-#include <errno.h>
-
-/*! \file xbdbf.cpp
-*/
-
-/************************************************************************/
-//! Constructor
-/*!
- \param x pointer to the global xbXbase class
-*/
-xbDbf::xbDbf( xbXBase * x )
-{
- xbase = x;
- InitVars();
-}
-/************************************************************************/
-//! Destructor
-/*!
-*/
-xbDbf::~xbDbf()
-{
- CloseDatabase(true);
-}
-/************************************************************************/
-//! Initialize private data members.
-/*!
- Internal use only.
-*/
-void xbDbf::InitVars()
-{
- SetFileName(NULL);
- NoOfFields = 0;
- DbfStatus = XB_CLOSED;
- fp = NULL;
- CurRec = 0L;
- SchemaPtr = NULL;
- RecBuf = NULL;
- RecBuf2 = NULL;
- Version = 0x00;
- UpdateYY = 0x00;
- UpdateMM = 0x00;
- UpdateDD = 0x00;
- NoOfRecs = 0L;
- HeaderLen = 0x00;
- RecordLen = 0x00;
- NdxList = NULL;
- FreeIxList = NULL;
- XFV = 3; /* Xbase file version */
-
-#ifdef XB_LOCKING_ON
- xblfh = NULL; /* lock file for XB_XBASE_LOCK_MODE */
- LockMode = xbase->GetLockMode();
- TableLockCnt = 0;
- IndexLockCnt = 0;
-#ifdef XB_MEMO_FIELDS
- MemoLockCnt = 0;
-#endif
-
- AutoLock = 1;
- CurLockType = -1;
- CurLockCount = 0;
- CurLockedRecNo = 0L;
- CurRecLockType = -1;
- CurRecLockCount = 0;
- CurMemoLockType = -1;
- CurMemoLockCount = 0;
-#else
- AutoLock = 0;
-#endif
-
-#ifdef XB_MEMO_FIELDS
- MemofileName = "";
- MemoHeader.BlockSize = XB_DBT_BLOCK_SIZE;
- MemoHeader.Version = 0x03;
- mfp = NULL;
- mbb = NULL;
- CurMemoBlockNo = -1;
- mfield1 = 0;
- MStartPos = 0;
- MFieldLen = 0;
- NextFreeBlock = 0L;
- FreeBlockCnt = 0L;
- MNextBlockNo = 0L;
- MNoOfFreeBlocks = 0L;
-#endif
-
-//#ifdef XB_REAL_DELETE
- RealDelete = 0;
- FirstFreeRec = 0L;
- RealNumRecs = 0L;
-//#endif
-}
-/************************************************************************/
-//! Set dbase version for the dbf file.
-/*!
- Set dbase version. Should only be used before creating a database with
- xbDbf::CreateDatabase().
-
- \param v version, either 3 or 4.
-*/
-xbShort xbDbf::SetVersion(xbShort v) {
- if (v == 0)
- return XFV;
- else
- if(v == 3) {
- XFV = 3;
-#ifdef XB_MEMO_FIELDS
- MemoHeader.Version = 0x03;
-#endif
- return XFV;
- } else
- if (v == 4) {
- XFV = 4;
-#ifdef XB_MEMO_FIELDS
- MemoHeader.Version = 0x00;
-#endif
- return XFV;
- }
-
- return XB_INVALID_OPTION;
-}
-/************************************************************************/
-//! Write the dbf header
-/*!
- Internal use only.
-
- \param PositionOption flag that indicates whether file postition should
- be moved. non-zero if so, zero if not.
-*/
-xbShort xbDbf::WriteHeader( xbShort PositionOption )
-{
- char buf[32];
- memset(buf, 0, 32);
- if(PositionOption)
- rewind(fp);
-
- memcpy(&buf[0], &Version, 4);
- xbase->PutLong(&buf[4], NoOfRecs);
- xbase->PutShort(&buf[8], HeaderLen );
- xbase->PutShort(&buf[10], RecordLen );
-
-#ifdef XB_REAL_DELETE
- if(RealDelete){
- xbase->PutULong(&buf[12], FirstFreeRec);
- xbase->PutULong(&buf[16], RealNumRecs);
- }
-#endif
- if(fwrite(buf, 32, 1, fp) != 1)
- return XB_WRITE_ERROR;
-
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Read the dbf header.
-/*!
- Internal use only.
-
- \param PositionOption
-*/
-xbShort xbDbf::ReadHeader( xbShort PositionOption )
-{
-#if 0
- char buf[4];
- if (PositionOption)
- rewind(fp);
- if (fread(&Version, 4, 1, fp) != 1)
- xb_error(XB_READ_ERROR);
-
- if (fread(buf, 4, 1, fp ) != 1)
- xb_error(XB_READ_ERROR);
-
- NoOfRecs = xbase->GetLong( buf );
- if(fread(buf, 2, 1, fp) != 1)
- xb_error(XB_READ_ERROR);
-
- HeaderLen = xbase->GetShort( buf );
- if(fread(buf, 2, 1, fp) != 1)
- xb_error(XB_READ_ERROR);
-
- RecordLen = xbase->GetShort(buf);
-
-#ifdef XB_REAL_DELETE
- if(RealDelete)
- {
- if (fread(buf, 4, 1, fp ) != 1)
- xb_error(XB_READ_ERROR);
- FirstFreeRec = xbase->GetULong( buf );
-
- if (fread(buf, 4, 1, fp ) != 1)
- xb_error(XB_READ_ERROR);
- RealNumRecs = xbase->GetULong( buf );
- }
-#endif
-#else
- char buf[32];
-
- if(PositionOption)
- rewind(fp);
-
- if(fread(buf, 32, 1, fp) != 1)
- return XB_READ_ERROR;
-
- memcpy(&Version, buf, 4);
- NoOfRecs = xbase->GetLong(&buf[4]);
- HeaderLen = xbase->GetShort(&buf[8]);
- RecordLen = xbase->GetShort(&buf[10]);
-
-#ifdef XB_REAL_DELETE
- if(RealDelete)
- {
- FirstFreeRec = xbase->GetULong(&buf[12]);
- RealNumRecs = xbase->GetULong(&buf[16]);
- }
-#endif
-#endif
-
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Determine if file name suffix is missing
-/*!
- Internal use only.
-*/
-xbShort xbDbf::NameSuffixMissing( xbShort type, const char * name )
-{
- /* type 1 is DBF check
- type 2 is NDX check
- type 3 is MDX check
- type 4 is NTX check
-
- Returns 0 if suffix found
- 1 if suffix not found, lower case
- 2 is suffix not found, upper, case
-*/
-
- xbShort len;
-
- len = strlen( name );
- if( len <= 4 )
- if( name[len-1] >= 'A' && name[len-1] <= 'Z' )
- return 2;
- else
- return 1;
-
- if( type == 1 && name[len-4] == '.' &&
- ( name[len-3] == 'd' || name[len-3] == 'D' ) &&
- ( name[len-2] == 'b' || name[len-2] == 'B' ) &&
- ( name[len-1] == 'f' || name[len-1] == 'F' )
- )
- return 0;
-
- if( type == 2 && name[len-4] == '.' &&
- ( name[len-3] == 'n' || name[len-3] == 'N' ) &&
- ( name[len-2] == 'd' || name[len-2] == 'D' ) &&
- ( name[len-1] == 'x' || name[len-1] == 'X' )
- )
- return 0;
-
- if( type == 4 && name[len-4] == '.' &&
- ( name[len-3] == 'n' || name[len-3] == 'N' ) &&
- ( name[len-2] == 't' || name[len-2] == 'T' ) &&
- ( name[len-1] == 'x' || name[len-1] == 'X' )
- )
- return 0;
-
- if( name[len-5] >= 'A' && name[len-5] <= 'Z' )
- return 2;
- else
- return 1;
-}
-/************************************************************************/
-//! Create the dbf file.
-/*!
- This method attempts to create the DBF file with the specified
- name (TableName) and schema (xbSchema s). The OverLay switch is used to determine
- if an existing file should be overwritten or an error flagged if the
- file already exists. The record buffer is blanked (set to spaces).
-
- \param TableName name of the table
- \param s xbSchema
- \param Overlay One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>OverLay</th><th>Description</th></tr>
- <tr><td>XB_OVERLAY</td><td>Overwrite existing file if it exists</td></tr>
- <tr><td>XB_DONTOVERLAY</td><td>Report an error if file exists</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{OverLay} & \textbf{Description} \\ \hline \hline
- XB\_OVERLAY & Overwrite existing file if it exists \\ \hline
- XB\_DONTOVERLAY & Report an error if file exists \\ \hline
- \end{tabular}
- \endlatexonly
- \returns One of the following return codes:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_FILE_EXISTS</td><td>If the file exists and OverLay is XB_DONTOVERLAY</td></tr>
- <tr><td>XB_OPEN_ERROR</td><td>Couldn't open the file</td></tr> <tr><td>XB_NO_MEMORY</td><td>Memory allocation error</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Couldn't write to disk</td><tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No Error \\ \hline
- XB\_FILE\_EXISTS & If the file exists and OverLay is XB\_DONTOVERAY \\ \hline
- XB\_OPEN\_ERROR & Couldn't open the file \\ \hline
- XB\_WRITE\_ERROR & Couldn't write to disk \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::CreateDatabase( const char * TableName, xbSchema * s,
- const xbShort Overlay )
-{
- xbShort i, j, k, k2, rc; /* , count; */
-
-#ifdef XB_MEMO_FIELDS
- xbShort MemoSw = 0;
-#endif
-
- DbfStatus = XB_CLOSED;
- SetFileName( TableName );
-
- /* check if the file already exists */
- if((( fp = fopen( GetFileName(), "r" )) != NULL ) && !Overlay ){
- fclose( fp );
- return XB_FILE_EXISTS;
- }
- else if( fp ) fclose( fp );
-
- if(( fp = fopen( GetFileName(), "w+b" )) == NULL )
- return XB_OPEN_ERROR;
-
-#ifdef XB_LOCKING_ON
- /* no buffering in multi user mode */
- setbuf( fp, NULL );
-
- /* open the lock file if XB_XBASE_LOCK_FLAVOR */
-// if( LockMode == XB_XBASE_LOCK_MODE )
-// if(( rc = OpenXbLockFile()) != XB_NO_ERROR )
-// return rc;
-#endif
-
- /* count the number of fields and check paramaters */
- i = 0;
- while( s[i].Type != 0 ){
- NoOfFields++;
-
-#ifdef XB_MEMO_FIELDS
- if(s[i].Type == 'M'){
- s[i].FieldLen = 10;
- s[i].NoOfDecs = 0;
- }
-#endif /* XB_MEMO_FIELDS */
-
- if(s[i].Type == 'D'){
- s[i].FieldLen = 8;
- s[i].NoOfDecs = 0;
- }
-
- if(s[i].Type == 'C')
- s[i].NoOfDecs = 0;
-
- RecordLen += s[i].FieldLen;
-
- if( s[i].Type != 'C' &&
- s[i].Type != 'N' &&
- s[i].Type != 'F' &&
- s[i].Type != 'D' &&
-#ifdef XB_MEMO_FIELDS
- s[i].Type != 'M' &&
-#endif /* XB_MEMO_FIELDS */
- s[i].Type != 'L' )
- {
- fclose( fp );
- InitVars();
- return XB_UNKNOWN_FIELD_TYPE;
- }
-
-#ifdef XB_MEMO_FIELDS
-// 8/18/03 types B and O dont exist yet - gkunkel
-// if( !MemoSw && ( s[i].Type=='M' || s[i].Type=='B' || s[i].Type=='O'))
- if( !MemoSw && ( s[i].Type=='M' ))
- MemoSw++;
-#endif
-
-// check for numeric fields which are too long
- if((s[i].Type == 'N' || s[i].Type == 'F') && s[i].FieldLen > 19 ){
- fclose( fp );
- InitVars();
- return XB_INVALID_FIELD_LEN;
- }
- i++;
- }
- RecordLen++; /* add one byte for 0x0D */
-
- if(( RecBuf = (char *) malloc( RecordLen )) == NULL ){
- fclose( fp );
- InitVars();
- return XB_NO_MEMORY;
- }
-
- if(( RecBuf2 = (char *) malloc( RecordLen )) == NULL ){
- free( RecBuf );
- fclose( fp );
- InitVars();
- return XB_NO_MEMORY;
- }
-
- /* BlankRecord(); */
- memset( RecBuf, 0x20, RecordLen );
- memset( RecBuf2, 0x20, RecordLen );
-
- /* set class variables */
- Version = XFV & 0x7; // file version - bit 0-2
-#ifdef XB_MEMO_FIELDS
- if(MemoSw){
- if((XFV & 0x7) == 3)
- Version |= 0x80; // memo presence - bit 7
- else
- Version = (char) 0x8b;
- }
-#endif
-
- CurRec = 0L;
- HeaderLen = 33 + NoOfFields * 32;
- xbDate d;
- UpdateYY = (d.YearOf() - 1900);
- if((XFV & 0x7) == 3)
- UpdateYY %= 100; // dBASE III seems to do this, but IV does not. DTB
-
- UpdateMM = d.MonthOf();
- UpdateDD = d.DayOf( XB_FMT_MONTH );
-
- /* write the header prolog */
- if(( rc = WriteHeader( 0 )) != XB_NO_ERROR ){
- free( RecBuf );
- free( RecBuf2 );
- fclose( fp );
- InitVars();
- return XB_WRITE_ERROR;
- }
-
- if((SchemaPtr=(xbSchemaRec *)malloc(NoOfFields*sizeof(xbSchemaRec)))==NULL){
- free( RecBuf );
- free( RecBuf2 );
- fclose( fp );
- InitVars();
- return XB_NO_MEMORY;
- }
- memset( SchemaPtr, 0x00, ( NoOfFields * sizeof(xbSchemaRec)));
-
- /* write the field information into the header */
- for( i = 0, k = 1; i < NoOfFields; i++ ){
- memset( SchemaPtr[i].FieldName, 0x00, 11 );
- strncpy( SchemaPtr[i].FieldName, s[i].FieldName, 10 );
-
- SchemaPtr[i].Type = s[i].Type;
- SchemaPtr[i].FieldLen = s[i].FieldLen;
- SchemaPtr[i].NoOfDecs = s[i].NoOfDecs;
-
- if( SchemaPtr[i].NoOfDecs > SchemaPtr[i].FieldLen ) {
- fclose( fp );
- free( SchemaPtr );
- free( RecBuf );
- free( RecBuf2 );
- InitVars();
- return XB_INVALID_SCHEMA;
- }
-
- k2 = k;
- k += SchemaPtr[i].FieldLen;
-
- if(( fwrite( &SchemaPtr[i], 1, 18, fp )) != 18 ) {
- fclose( fp );
- free( SchemaPtr );
- free( RecBuf );
- free( RecBuf2 );
- InitVars();
- return XB_WRITE_ERROR;
- }
-
- for( j = 0; j < 14; j++ ) {
- if(( fwrite( "\x00", 1, 1, fp )) != 1 ) {
- free( SchemaPtr );
- free( RecBuf );
- free( RecBuf2 );
- fclose( fp );
- InitVars();
- return XB_WRITE_ERROR;
- }
- }
- SchemaPtr[i].Address = RecBuf + k2;
- SchemaPtr[i].Address2 = RecBuf2 + k2;
- }
-
- /* write the header terminator */
- if(( fputc( XB_CHARHDR, fp )) != XB_CHARHDR ){
- fclose( fp );
- free( SchemaPtr );
- free( RecBuf );
- free( RecBuf2 );
- InitVars();
- return XB_WRITE_ERROR;
- }
-
-#ifdef XB_MEMO_FIELDS
- if( MemoSw )
- if((rc = CreateMemoFile()) != XB_NO_ERROR){
- fclose(fp);
- free(RecBuf);
- free(RecBuf2);
- InitVars();
- return rc;
- }
-#endif
-
- DbfStatus = XB_OPEN;
- return xbase->AddDbfToDbfList(this, GetFileName());
-}
-/************************************************************************/
-//! Close the dbf file.
-/*!
- This method attempts to close the DBF file which was previously
- opened with either CreateDatabase() or OpenDatabase(). Deletes any
- memory allocated. Automatically closes any open indexes associated
- with this data file.
-
- \param deleteIndexes if TRUE, the indexes (xbIndex instances) will also
- be deleted (index files will not be deleted)
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File was not open</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No Error \\ \hline
- XB\_NOT\_OPEN\_ERROR & File was not open \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::CloseDatabase( xbBool deleteIndexes )
-{
-#if defined(XB_INDEX_ANY)
- xbIxList *i, *ti;
-#endif
-
- if(DbfStatus == XB_CLOSED)
- return XB_NO_ERROR;
-
-
-#if defined(XB_INDEX_ANY)
- i = NdxList;
- while (i){
- i->index->CloseIndex();
- if(deleteIndexes)
- delete i->index;
- i = NdxList;
- }
-/* free up unused nodes */
- i = FreeIxList;
- while( i ) {
- ti = i;
- i = i->NextIx;
- free(ti);
- }
-#endif
-
- if(SchemaPtr){
- for( int j = 0; j < NoOfFields; j++ )
- if( SchemaPtr[j].fp ) delete SchemaPtr[j].fp;
- free( SchemaPtr );
- }
- if(RecBuf)
- free( RecBuf );
- if(RecBuf2)
- free( RecBuf2 );
-
-#ifdef XB_MEMO_FIELDS
- if( mbb )
- free( mbb ); /* memo block buffer */
- if( mfp )
- fclose( mfp ); /* memo file pointer */
-#endif
-
-#ifdef XB_LOCKING_ON
- if( xblfh ){
- fclose( xblfh );
- xblfh = NULL;
- }
-#endif
-
- xbase->RemoveDbfFromDbfList( this );
- if(fp)
- fclose( fp );
- InitVars();
- return XB_NO_ERROR;
-}
-/************************************************************************/
-/* options 1 = Print header only
- 2 = Field data only
- 3 = Header and Field data */
-
-//! Dump header information.
-/*!
- \param Option One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Option</th><th>Description</th></tr>
- <tr><td>1</td><td>Print header only</td></tr>
- <tr><td>2</td><td>Field data only</td></tr>
- <tr><td>3</td><td>Header and field data</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Option} & \textbf{Description} \\ \hline \hline
- 1 & Header only \\ \hline
- 2 & Field data only \\ \hline
- 3 & Header and field data \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-#ifdef XBASE_DEBUG
-xbShort xbDbf::DumpHeader( xbShort Option )
-{
- int i;
-
- if( Option < 1 || Option > 3 )
- return XB_INVALID_OPTION;
-
- if( DbfStatus == XB_CLOSED )
- return XB_NOT_OPEN;
-
- std::cout << "\nDatabase file " << GetFileName() << std::endl << std::endl;
-
- if( Option != 2 ){
- std::cout << "File header data:" << std::endl;
- if( Version == 3 )
- std::cout << "Dbase III file" << std::endl;
- else if ( Version == 83 )
- std::cout << "Dbase III file with memo fields" << std::endl << std::endl;
-
- std::cout << "Last update date = "
- << (int) UpdateMM << "/" << (int) UpdateDD << "/" << (int) UpdateYY % 100 << std::endl;
-
- std::cout << "Header length = " << HeaderLen << std::endl;
- std::cout << "Record length = " << RecordLen << std::endl;
- std::cout << "Records in file = " << NoOfRecs << std::endl << std::endl;
-#ifdef XB_REAL_DELETE
- std::cout << "First Free Rec = " << FirstFreeRec << std::endl << std::endl;
-#endif
- }
- if( Option != 1 ){
- std::cout << "Field Name Type Length Decimals" << std::endl;
- std::cout << "---------- ---- ------ --------" << std::endl;
- for( i = 0; i <NoOfFields; i++ ){
- if( SchemaPtr[i].Type == 'C' && SchemaPtr[i].NoOfDecs > 0 )
- printf( "%10s %1c %4d %4d\n", SchemaPtr[i].FieldName,
- SchemaPtr[i].Type, SchemaPtr[i].FieldLen, 0 );
- else
- printf( "%10s %1c %4d %4d\n", SchemaPtr[i].FieldName,
- SchemaPtr[i].Type, SchemaPtr[i].FieldLen, SchemaPtr[i].NoOfDecs );
- }
- }
- std::cout << std::endl;
- return XB_NO_ERROR;
-}
-#endif
-/************************************************************************/
-//! Open the DBF file.
-/*!
- This method attempts to open the DBF file with the specified
- name (TableName). This method does not position to any particular
- record in the file. The record buffer is blanked (set to spaces).
-
- \param TableName Name of table to open
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_OPEN_ERROR</td><td>Couldn't open file</td></tr>
- <tr><td>XB_NO_MEMORY</td><td>Memory allocation error</td></tr>
- <tr><td>XB_NOT_XBASE</td><td>Not an DBF file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_OPEN\_ERROR & Couldn't open file \\ \hline
- XB\_NO\_MEMORY & Memory allocation error \\ \hline
- XB\_NOT\_XBASE & Not an DBF file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::OpenDatabase( const char * TableName )
-{
- xbShort i, j, rc;
- char buf[33];
- char *p;
-
-#ifdef XB_MEMO_FIELDS
- xbShort MemoSw = 0;
-#endif
-
- /* verify the file is not already open */
- if( DbfStatus != XB_CLOSED )
- return XB_ALREADY_OPEN;
-
- /* copy the file name to the class variable */
- SetFileName( TableName );
-
- /* open the file */
- if(( fp = fopen(GetFileName(), "r+b")) == NULL ){
- //
- // Try to open read only if failed to open read/write
- //
- if(( fp = fopen(GetFileName(), "rb")) == NULL )
- return XB_OPEN_ERROR;
- }
-
-#ifdef XB_LOCKING_ON
- /* no buffering in multi user mode - may not see what others have updated */
- setbuf( fp, NULL );
-
- /* open the lock file if XB_XBASE_LOCK_MODE */
-// if( LockMode == XB_XBASE_LOCK_MODE )
-// if(( rc = OpenXbLockFile()) != XB_NO_ERROR )
-// return rc;
-#endif
-
-#ifdef XB_LOCKING_ON
-// if( AutoLock )
-// if(( rc = LockDatabase( XB_LOCK, 0L )) != XB_NO_ERROR)
-// return rc;
-#endif
-
- /* copy the header into memory */
- if(( rc = ReadHeader( 1 )) != XB_NO_ERROR ){
- InitVars();
- return rc;
- }
-
- /* check the version */
- if( Version == 3 || Version == (char)0x83 ){ /* dBASE III+ */
- XFV = 3;
-#ifdef XB_MEMO_FIELDS
- MemoHeader.Version = 0x03;
-#endif
- }
- else if( Version == 4 || Version == (char)0x8B ){ /* dBASE IV */
- XFV = 4;
-#ifdef XB_MEMO_FIELDS
- MemoHeader.Version = 0x00;
-#endif
- }
- else if( Version == (char)0xf5 ){ /* FoxPro */
- XFV = 4;
-#ifdef XB_MEMO_FIELDS
- MemoHeader.Version = 0x00;
-#endif
- }
- else if( Version == (char)0x30 ){ /* Visual Foxpro */
- XFV = 4;
-#ifdef XB_MEMO_FIELDS
- MemoHeader.Version = 0x00;
-#endif
- } else {
- InitVars();
- return XB_NOT_XBASE;
- }
-
- // it would seem that dBASE III+ generates an UpdateYY value
- // of 0 for 2000 and dBASE IV uses 100, so I have removed the
- // check for UpdateYY being 0 (which might be valid). DTB
-
- // Not all flavors of database tools use these fields
- // Found a month set to 0 in valid dbf file
- // Commented out this check 2/11/06 - GAK
-
- // if( UpdateMM == 0 || UpdateDD == 0 ){
- // InitVars();
- // return XB_NOT_XBASE;
- // }
-
- /* calculate the number of fields */
- if( Version == (char)0x30 ) {
- NoOfFields = ( HeaderLen - 296 ) / 32 ;
- } else {
- NoOfFields = ( HeaderLen - 33 ) / 32;
- }
-
- if(( RecBuf = (char *) malloc( RecordLen )) == NULL ) {
- fclose( fp );
- InitVars();
- return XB_NO_MEMORY;
- }
- if(( RecBuf2 = (char *) malloc( RecordLen )) == NULL ) {
- fclose( fp );
- free( RecBuf );
- InitVars();
- return XB_NO_MEMORY;
- }
-
- if((SchemaPtr=(xbSchemaRec *)malloc(NoOfFields*sizeof(xbSchemaRec)))==NULL){
- free( RecBuf );
- free( RecBuf2 );
- fclose( fp );
- InitVars();
- return XB_NO_MEMORY;
- }
- memset( SchemaPtr, 0x00, ( NoOfFields * sizeof(xbSchemaRec)));
-
- /* copy field info into memory */
- for( i = 0, j = 1; i < NoOfFields; i++ ){
- _fseek( fp,((xbOffT)i*32+32), 0 );
- fread( &buf, 1, 32, fp );
- p = buf;
- strncpy( SchemaPtr[i].FieldName, p, 10 );
- p += 11;
- SchemaPtr[i].Type = *p++;
-
- SchemaPtr[i].Address = RecBuf + j;
- SchemaPtr[i].Address2 = RecBuf2 + j;
-
- SchemaPtr[i].FieldLen = *( p + 4 );
- SchemaPtr[i].NoOfDecs = *( p + 5 );
-
- if( SchemaPtr[i].Type == 'C' && SchemaPtr[i].NoOfDecs > 0 ){
- SchemaPtr[i].LongFieldLen = xbase->GetShort( p + 4 );
- j += SchemaPtr[i].LongFieldLen;
- }
- else
- j += SchemaPtr[i].FieldLen;
-#ifdef XB_MEMO_FIELDS
- if( !MemoSw && (SchemaPtr[i].Type == 'M' ||
- SchemaPtr[i].Type == 'B' || SchemaPtr[i].Type == 'O' ))
- MemoSw++;
-#endif
- }
- CurRec = 0L;
- BlankRecord();
- DbfStatus = XB_OPEN;
-
-#ifdef XB_MEMO_FIELDS
- if( MemoSw ) /* does this table have memo fields ? */
- if(( rc = OpenMemoFile()) != XB_NO_ERROR ){
- free( RecBuf );
- free( RecBuf2 );
- free( SchemaPtr );
- fclose( fp );
- InitVars();
- return rc;
- }
-#endif
-
-#ifdef XB_LOCKING_ON
-// if( AutoLock )
-// LockDatabase( XB_UNLOCK, 0L );
-#endif /* XB_LOCKING_ON */
-
- return xbase->AddDbfToDbfList( this, GetFileName() );
-}
-/************************************************************************/
-//! Blank the record buffer.
-/*!
- Sets the record to spaces.
-*/
-xbShort xbDbf::BlankRecord()
-{
- if( DbfStatus == XB_CLOSED )
- return XB_NOT_OPEN;
-
- if( DbfStatus != XB_UPDATED ){
- DbfStatus = XB_UPDATED;
- memcpy( RecBuf2, RecBuf, RecordLen );
- }
-
- memset( RecBuf, 0x20, RecordLen );
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Append the current record to the data file
-/*!
- This method attempts to append the contents of the current record buffer
- to the end of the DBF file and updates the file date and number of
- records in the file. Also updates any open indices associated with
- this data file.
-
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::AppendRecord()
-{
- xbShort rc;
- xbULong nextRecNo;
-
-#if defined(XB_INDEX_ANY)
- xbIxList *i;
-#endif
-
-/* lock the database */
-#ifdef XB_LOCKING_ON
-// if( AutoLock )
-// if(( rc = LockDatabase( XB_LOCK, 0L )) != XB_NO_ERROR)
-// return rc;
-
- rc = ReadHeader(1);
-
-// if(AutoLock)
-// LockDatabase( XB_UNLOCK, 0L );
-
- if( rc )
- return rc;
-
-#endif
-
-/* lock any indexes */
-#if defined(XB_INDEX_ANY)
-#ifdef XB_LOCKING_ON
- i = NdxList;
- while( i && AutoLock ){
-// if(( rc = i->index->LockIndex( XB_LOCK )) != XB_NO_ERROR )
-// return rc;
- i = i->NextIx;
- }
-#endif /* XB_LOCKING_ON */
-#endif
-
-// if there are no duplicates, and no records set the CurRec to the
-// last record + 1. This is for EXP::RECNO()
-
-/* check for any duplicate keys */
-#if defined(XB_INDEX_ANY)
- i = NdxList;
- while( i ){
- if( i->index->UniqueIndex() ){
- i->index->CreateKey( 0, 0 );
- if( i->index->FindKey() == XB_FOUND )
- return XB_KEY_NOT_UNIQUE;
- }
- i = i->NextIx;
- }
-#endif
-
-#ifdef XB_REAL_DELETE
- if(RealDelete && FirstFreeRec)
- nextRecNo = FirstFreeRec;
- else
- nextRecNo = NoOfRecs + 1;
-#else
- nextRecNo = NoOfRecs + 1;
-#endif
-
- CurRec = NoOfRecs + 1;
-
-#if defined(XB_INDEX_ANY)
-/* update the indexes */
- i = NdxList;
- while( i ){
- if( !i->index->UniqueIndex() ) /* if we didn't prepare the key */
- if(( rc = i->index->CreateKey( 0, 0 )) != XB_NO_ERROR ) /* then do it before the add */
- return rc;
- if(( rc = i->index->AddKey(nextRecNo)) != XB_NO_ERROR )
- return rc;
- i->index->TouchIndex();
- i = i->NextIx;
- }
-#endif /* XB_INDEX_ANY */
-
-#ifdef XB_REAL_DELETE
- char buf[4];
-
- if(RealDelete && FirstFreeRec){
- /*
- ** Grab the next free rec no and put it in FirstFreeRec
- */
- if(_fseek(fp, (HeaderLen+(((xbOffT)FirstFreeRec-1)*RecordLen)+1), 0) != 0)
- return XB_SEEK_ERROR;
-
- if(fread(buf, 4, 1, fp) != 1)
- return XB_READ_ERROR;
-
- FirstFreeRec = xbase->GetULong(buf);
- }
-
- /*
- ** Okay, seek and write the record out
- */
- if(_fseek(fp, (HeaderLen+(((xbOffT)nextRecNo-1)*RecordLen)), 0) != 0)
- return XB_SEEK_ERROR;
-
- if(fwrite( RecBuf, RecordLen, 1, fp) != 1)
- return XB_WRITE_ERROR;
-
- /*
- ** If we just appended the record to the file, then write the EOF char
- */
- if(nextRecNo == NoOfRecs + 1){
- if( fputc( XB_CHAREOF, fp ) != XB_CHAREOF )
- return XB_WRITE_ERROR;
- }
-#else
- /* write the last record */
- if( _fseek( fp,(HeaderLen+((xbOffT)NoOfRecs*RecordLen)), 0 ) != 0 )
- return XB_SEEK_ERROR;
-
- if( fwrite( RecBuf, RecordLen, 1, fp ) != 1 )
- return XB_WRITE_ERROR;
-
- /* write the end of file marker */
- if( fputc( XB_CHAREOF, fp ) != XB_CHAREOF )
- return XB_WRITE_ERROR;
-#endif
-
- /* calculate the latest header information */
- xbDate d;
- UpdateYY = d.YearOf() - 1900;
- if(XFV == 3)
- UpdateYY %= 100; // dBASE III seems to do this, IV does not. DTB
- UpdateMM = d.MonthOf();
- UpdateDD = d.DayOf( XB_FMT_MONTH );
-#ifndef XB_REAL_DELETE
- NoOfRecs++;
-#else
- if(RealDelete){
- if(nextRecNo == NoOfRecs + 1)
- NoOfRecs++;
- RealNumRecs++;
- }
- else
- NoOfRecs++;
-#endif
- CurRec = nextRecNo;
-
- /* rewrite the header record */
- if(( rc = WriteHeader( 1 )) != XB_NO_ERROR )
- return rc;
-
-#ifdef XB_LOCKING_ON
-// if( AutoLock )
-// LockDatabase( XB_UNLOCK, 0L );
-
-#if defined(XB_INDEX_ANY)
- i = NdxList;
- while( i && AutoLock ){
-// i->index->LockIndex( XB_UNLOCK );
- i = i->NextIx;
- }
-#endif /* XB_INDEX_ANY */
-#endif /* XB_LOCKING_ON */
-
- DbfStatus = XB_OPEN;
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Get a record from the data file
-/*!
- This method attempts to retrieve the record specified by RecNo from the
- data file into the record buffer.
-
- \param RecNo Record number to retrieve
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File is not open</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_NOT\_OPEN & File is not open \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::GetRecord( xbULong RecNo )
-{
- xbShort rc;
- if( DbfStatus == XB_CLOSED )
- return XB_NOT_OPEN;
-
-#ifdef XB_LOCKING_ON
-// if( AutoLock )
-// if(( rc = LockDatabase( XB_LOCK, RecNo )) != 0 ) return rc;
-
- rc = ReadHeader(1);
-
-// if(AutoLock)
-// LockDatabase( XB_UNLOCK, RecNo );
-
- if( rc )
- return rc;
-
-#endif
-
- if( RecNo > NoOfRecs || RecNo == 0L )
- return XB_INVALID_RECORD;
-
- if( _fseek( fp, (HeaderLen+(((xbOffT)RecNo-1L)*RecordLen)), SEEK_SET )){
-#ifdef XB_LOCKING_ON
-// LockDatabase( XB_UNLOCK, RecNo );
-#endif
- return XB_SEEK_ERROR;
- }
-
- if( fread( RecBuf, RecordLen, 1, fp ) != 1 ){
-#ifdef XB_LOCKING_ON
-// LockDatabase( XB_UNLOCK, RecNo );
-#endif
- return XB_READ_ERROR;
- }
-
-#ifdef XB_LOCKING_ON
-// if( AutoLock )
-// LockDatabase( XB_LOCK, RecNo );
-#endif
-
- DbfStatus = XB_OPEN;
- CurRec = RecNo;
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Get the first physical record in the data file
-/*!
- Attempts to retrieve the first physical record from the data file into
- the record buffer.
-
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File is not open</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- <tr><td>XB_SEEK_ERROR</td><td>Error seeking file</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_NOT\_OPEN & File is not open \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- XB\_SEEK\_ERROR & Error seeking file \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::GetFirstRecord()
-{
- xbShort rc;
- if( NoOfRecs == 0 )
- return XB_INVALID_RECORD;
-
- rc = GetRecord( 1L );
-#ifdef XB_REAL_DELETE
- if(!rc && RealDelete && RecordDeleted())
- rc = GetNextRecord();
-#endif
-
- return rc;
-}
-/************************************************************************/
-//! Get the last phyiscal record in the data file
-/*!
- Attempts to retrieve the last physical record from the data file into
- the record buffer.
-
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_EOF</td><td>At end of file</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File is not open</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- <tr><td>XB_SEEK_ERROR</td><td>Error seeking file</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_EOF & At end of file \\ \hline
- XB\_NOT\_OPEN & File is not open \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- XB\_SEEK\_ERROR & Error seeking file \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::GetLastRecord()
-{
- xbShort rc;
- if( NoOfRecs == 0 )
- return XB_INVALID_RECORD;
-
- rc = GetRecord( NoOfRecs );
-#ifdef XB_REAL_DELETE
- if(!rc && RealDelete && RecordDeleted())
- rc = GetPrevRecord();
-#endif
-
- return rc;
-}
-/************************************************************************/
-//! Get the next physical record in the data file
-/*!
- Attempts to retrieve the next physical record from the data file into
- the record buffer.
-
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_EOF</td><td>At end of file</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File is not open</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- <tr><td>XB_SEEK_ERROR</td><td>Error seeking file</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_EOF & At end of file \\ \hline
- XB\_NOT\_OPEN & File is not open \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- XB\_SEEK\_ERROR & Error seeking file \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::GetNextRecord()
-{
- xbShort rc;
- if( NoOfRecs == 0 )
- return XB_INVALID_RECORD;
- else if( CurRec >= NoOfRecs )
- return XB_EOF;
-
- rc = GetRecord( ++CurRec );
-
-#ifdef XB_REAL_DELETE
- while(!rc && RealDelete && RecordDeleted())
- rc = GetRecord(++CurRec);
-#endif
-
- return rc;
-}
-/************************************************************************/
-//! Get the previous physical record in the data file
-/*!
- Attempts to retrieve the previous physical record from the data file into
- the record buffer.
-
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_BOF</td><td>At beginning of file</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File is not open</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- <tr><td>XB_SEEK_ERROR</td><td>Error seeking file</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_BOF & At beginning of file \\ \hline
- XB\_NOT\_OPEN & File is not open \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- XB\_SEEK\_ERROR & Error seeking file \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::GetPrevRecord()
-{
- xbShort rc;
- if( NoOfRecs == 0 )
- return XB_INVALID_RECORD;
- else if( CurRec <= 1L )
- return XB_EOF;
-
- rc = GetRecord( --CurRec );
-
-#ifdef XB_REAL_DELETE
- while(!rc && RealDelete && RecordDeleted())
- rc = GetRecord(--CurRec);
-#endif
-
- return rc;
-}
-/************************************************************************/
-//! Dump record
-/*!
- Dump the contents of the specified record to stdout.
-
- \param RecNo Record number of record to be dumped.
- \returns An error code (same as GetRecord()).
-*/
-xbShort xbDbf::DumpRecord( xbULong RecNo )
-{
- int i, rc;
- char buf[4096];
-
- if( RecNo == 0 || RecNo > NoOfRecs )
- return XB_INVALID_RECORD;
-
- rc = GetRecord( RecNo );
- if( rc != XB_NO_ERROR )
- return rc;
-
- std::cout << "\nREC NUMBER " << RecNo << "\n";
-
- if( RecordDeleted() )
- std::cout << "\nRecord deleted...\n";
-
- for( i = 0; i < NoOfFields; i++ ){
-#ifdef XB_MEMO_FIELDS
- if(SchemaPtr[i].Type == 'M'){
- if( MemoFieldExists( i )){
- std::cout << SchemaPtr[i].Type << " " << SchemaPtr[i].FieldName
- << " len = " << GetMemoFieldLen( i ) << std::endl;
- memset( buf, 0x00, 4095 );
- rc = GetMemoField(i, 4095, buf, 0);
- if(rc != XB_NO_ERROR)
- return rc;
- } else {
- buf[0] = 0x00;
- }
- }
- else
- GetField( i, buf );
- std::cout << SchemaPtr[i].Type << " " << SchemaPtr[i].FieldName << " = '" << buf << "'\n";
-#else
- GetField( i, buf );
- std::cout << SchemaPtr[i].FieldName << " = '" << buf << "'\n";
-#endif
- }
- std::cout << std::endl;
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Write the current record buffer to the current record in the data file.
-/*!
- Attempts to write the contents of the record buffer to the current
- record in the data file. Updates any open indexes.
-
- \sa PutRecord(xbULong RecNo)
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File is not open</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- <tr><td>XB_SEEK_ERROR</td><td>Error seeking file</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_NOT\_OPEN & File is not open \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- XB\_SEEK\_ERROR & Error seeking file \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-
-/************************************************************************/
-xbShort xbDbf::PutRecord() {
- return PutRecord(CurRec);
-}
-
-//! Write the current record buffer to the specified record in the data file.
-/*!
- Attempts to write the contents of the record buffer to the record specified
- by RecNo. Updates any open indexes.
-
- \param RecNo Record number to which data should be written
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Couldn't lock file</td></tr>
- <tr><td>XB_NOT_OPEN</td><td>File is not open</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- <tr><td>XB_SEEK_ERROR</td><td>Error seeking file</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Error writing to file</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_LOCK\_FAILED & Couldn't lock file \\ \hline
- XB\_NOT\_OPEN & File is not open \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- XB\_SEEK\_ERROR & Error seeking file \\ \hline
- XB\_WRITE\_ERROR & Error writing to file \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::PutRecord(xbULong RecNo)
-{
- xbShort rc;
-
-#if defined(XB_INDEX_ANY)
- xbIxList *i;
-#endif
-
- if( DbfStatus == XB_CLOSED )
- return XB_NOT_OPEN;
-
-/* lock the database */
-#ifdef XB_LOCKING_ON
- if( AutoLock ){
-// if(( rc = LockDatabase( XB_LOCK, RecNo )) != XB_NO_ERROR )
-// return rc;
-// if(( rc = LockDatabase( XB_LOCK, 0L )) != XB_NO_ERROR ){
-// LockDatabase( XB_UNLOCK, RecNo );
-// return rc;
-// }
-
- if((rc = ReadHeader(1)) != XB_NO_ERROR){
-// if(AutoLock){
-// LockDatabase( XB_UNLOCK, RecNo );
-// LockDatabase( XB_UNLOCK, 0L );
-// }
- return rc;
- }
- }
-#endif
-
- if( RecNo > NoOfRecs || RecNo == 0L )
- return XB_INVALID_RECORD;
-
-/* lock the indexes */
-#if defined(XB_INDEX_ANY)
-#ifdef XB_LOCKING_ON
- i = NdxList;
- while( i && AutoLock ){
-// if(( rc = i->index->LockIndex( XB_LOCK )) != XB_NO_ERROR )
-// return rc;
- i = i->NextIx;
- }
-#endif /* XB_LOCKING_ON */
-#endif
-
-#if defined(XB_INDEX_ANY)
- /* for any unique indexes that were updated, verify no unique keys exist */
- i = NdxList;
- while( i ){
- if( i->index->UniqueIndex() ){
- if(( i->KeyUpdated = i->index->KeyWasChanged()) == 1 ){
- i->index->CreateKey(0, 0);
- if( i->index->FindKey() == XB_FOUND && i->index->GetCurDbfRec() != RecNo)
- return XB_KEY_NOT_UNIQUE;
- }
- }
- i = i->NextIx;
- }
-#endif
-
-#if defined(XB_INDEX_ANY)
- /* loop through deleting old index keys and adding new index keys */
- i = NdxList;
- while( i ){
- if( !i->index->UniqueIndex() )
- i->KeyUpdated = i->index->KeyWasChanged();
- if( i->KeyUpdated ){
- i->index->CreateKey( 1, 0 ); /* load key buf w/ old values */
- if((rc = i->index->DeleteKey( CurRec )) != XB_NO_ERROR){
-#ifdef XB_LOCKING_ON
-// if( AutoLock ){
-// LockDatabase( XB_UNLOCK, RecNo );
-// LockDatabase( XB_UNLOCK, 0L );
-// }
-#if defined(XB_INDEX_ANY)
- i = NdxList;
- while( i && AutoLock ){
-// i->index->LockIndex( XB_UNLOCK );
- i = i->NextIx;
- }
-#endif /* XB_INDEX_ANY */
-#endif /* XB_LOCKING_ON */
- return rc;
- }
-
- i->index->CreateKey( 0, 0 );
- if(( rc = i->index->AddKey(CurRec)) != XB_NO_ERROR ){
-#ifdef XB_LOCKING_ON
-// if( AutoLock ){
-// LockDatabase( XB_UNLOCK, RecNo );
-// LockDatabase( XB_UNLOCK, 0L );
-// }
-#if defined(XB_INDEX_ANY)
- i = NdxList;
- while( i && AutoLock ){
-// i->index->LockIndex( XB_UNLOCK );
- i = i->NextIx;
- }
-#endif /* XB_INDEX_ANY */
-#endif /* XB_LOCKING_ON */
- return rc;
- }
- i->index->TouchIndex();
- }
- i = i->NextIx;
- }
-#endif /* XB_INDEX_ANY */
-
- if( _fseek( fp, (HeaderLen+(((xbOffT)RecNo-1L)*RecordLen)),0 ))
- return XB_SEEK_ERROR;
-
- if( fwrite( RecBuf, RecordLen, 1, fp ) != 1 )
- return XB_WRITE_ERROR;
-
- /* calculate the latest header information */
- xbDate d;
- UpdateYY = d.YearOf() - 1900;
- if(XFV == 3)
- UpdateYY %= 100; // dBASE III seems to do this, IV does not. DTB
- UpdateMM = d.MonthOf();
- UpdateDD = d.DayOf( XB_FMT_MONTH );
-
- /* rewrite the header record */
- if(( rc = WriteHeader( 1 )) != XB_NO_ERROR )
- return rc;
-
-#ifdef XB_LOCKING_ON
-// if( AutoLock ){
-// LockDatabase( XB_UNLOCK, RecNo );
-// LockDatabase( XB_UNLOCK, 0L );
-// }
-
-#if defined(XB_INDEX_ANY)
- i = NdxList;
- while( i && AutoLock ){
-// i->index->LockIndex( XB_UNLOCK );
- i = i->NextIx;
- }
-#endif /* XB_INDEX_ANY */
-#endif /* XB_LOCKING_ON */
-
- CurRec = RecNo;
- DbfStatus = XB_OPEN;
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Delete the current record
-/*!
- Marks the current record as deleted or if "real" deletes are turned
- on (xbDbf::RealDeleteOn()) will delete the record and add it to the
- free record list. Normal dBase behavior is to simply mark the record
- as deleted; the record will actually be deleted when the the DBF file
- "packed" (xbDbf::PackDatabase()). If "real" deletes are not on, a
- record may be undeleted using xbDbf::UndeleteRecord().
-
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::DeleteRecord()
-{
- xbULong newCurRec = 0;
- xbShort rc = XB_NO_ERROR;
-
-#if defined(XB_INDEX_ANY)
- xbIxList *i;
-#endif
-
- if(!RecBuf)
- return XB_INVALID_RECORD;
-
- if(CurRec < 1 || CurRec > NoOfRecs)
- return XB_INVALID_RECORD;
-
-/* lock the database */
-#ifdef XB_LOCKING_ON
-
- if( AutoLock ){
-/*
- if(( rc = LockDatabase( XB_LOCK, CurRec )) != XB_NO_ERROR )
- return rc;
- if(( rc = LockDatabase( XB_LOCK, 0L )) != XB_NO_ERROR ){
- LockDatabase( XB_UNLOCK, CurRec );
- return rc;
- }
- */
- if((rc = ReadHeader(1)) != XB_NO_ERROR){
-// if(AutoLock){
-// LockDatabase( XB_UNLOCK, CurRec );
-// LockDatabase( XB_UNLOCK, 0L );
-// }
- return rc;
- }
- }
-#endif
-
-/* lock the indexes */
-#if defined(XB_INDEX_ANY) && defined(XB_LOCKING_ON) && defined(XB_REAL_DELETE)
- i = NdxList;
- while( i && AutoLock ){
-// if(( rc = i->index->LockIndex( XB_LOCK )) != XB_NO_ERROR )
-// return rc;
- i = i->NextIx;
- }
-#endif
-
-/* remove keys from indexes */
-#if defined(XB_REAL_DELETE) && defined(XB_INDEX_ANY)
-
- if(RealDelete){
- i = NdxList;
- while(i){
- i->index->CreateKey(0, 0); /* load key buf */
- if(i->index->GetCurDbfRec() == (xbULong)CurRec){
- i->index->DeleteKey(CurRec);
- newCurRec = i->index->GetCurDbfRec();
- }
- else
- i->index->DeleteKey(CurRec);
- i->index->TouchIndex();
- i = i->NextIx;
- }
- }
-
-#endif
-
- RecBuf[0] = 0x2a;
-
-
-#ifdef XB_REAL_DELETE
- if(RealDelete){
-#ifdef XB_MEMO_FIELDS
- //
- // Delete memo data for memo fields.
- //
- for(int f = 0; f < NoOfFields; f++ )
- if(GetFieldType(f) == 'M' && MemoFieldExists(f))
- UpdateMemoData(f, 0, 0, XB_LOCK);
-#endif
- xbase->PutULong(&RecBuf[1], FirstFreeRec);
- FirstFreeRec = CurRec;
- RealNumRecs--;
- WriteHeader(1);
- }
-#endif
-
- if(!RealDelete){
- if( DbfStatus != XB_UPDATED ){
- DbfStatus = XB_UPDATED;
- memcpy( RecBuf2, RecBuf, RecordLen );
- }
- rc = PutRecord( CurRec );
- }
- else
- {
- if(_fseek( fp, (HeaderLen+(((xbOffT)CurRec-1L)*RecordLen)), 0))
- return XB_SEEK_ERROR;
- if(fwrite( RecBuf, RecordLen, 1, fp ) != 1 )
- return XB_WRITE_ERROR;
-
- //
- // Attempt to read in the record for the current location
- // in the active index.
- //
- CurRec = newCurRec;
- if(CurRec)
- rc = GetRecord(CurRec);
- else
- BlankRecord();
- }
-
-#ifdef XB_LOCKING_ON
-// if(AutoLock){
-// LockDatabase( XB_UNLOCK, CurRec );
-// LockDatabase( XB_UNLOCK, 0L );
-// }
-
-#if defined(XB_INDEX_ANY) && defined(XB_REAL_DELETE)
- i = NdxList;
- while( i && AutoLock ){
-// i->index->LockIndex( XB_UNLOCK );
- i = i->NextIx;
- }
-#endif /* XB_INDEX_ANY */
-#endif /* XB_LOCKING_ON */
-
- return rc;
-}
-/************************************************************************/
-//! Undelete the current record
-/*!
- Marks the currect record as not deleted (i.e. removes the flag indicating
- the record is deleted). This method may not be used (and will return
- an error code) if "real" deletes are on.
-
- \returns One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_INVALID_RECORD</td><td>Invalid record number</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No error \\ \hline
- XB\_INVALID\_RECORD & Invalid record number \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::UndeleteRecord()
-{
- xbShort rc;
-
-#ifdef XB_REAL_DELETE
- if(RealDelete)
- return XB_INVALID_RECORD;
-#endif
- if( RecBuf ){
- if( DbfStatus != XB_UPDATED ){
- DbfStatus = XB_UPDATED;
- memcpy( RecBuf2, RecBuf, RecordLen );
- }
-
- RecBuf[0] = 0x20;
- if(( rc = PutRecord( CurRec )) != 0 )
- return rc;
- }
- else
- return XB_INVALID_RECORD;
-
- return 0;
-}
-/************************************************************************/
-//! Determine if current record is deleted
-/*!
- \returns TRUE (1) if the current record is marked as deleted or FALSE
- (0) if not.
-*/
-xbShort xbDbf::RecordDeleted()
-{
- if( RecBuf && RecBuf[0] == 0x2a )
- return 1;
- else
- return 0;
-}
-/************************************************************************/
-//! Create a unique file name
-/*!
-*/
-xbShort xbDbf::CreateUniqueDbfName( xbString & sDbfn, xbString & sDbtn )
-{
- xbShort dnf; /* directory in name flag */
- xbShort unique = 0;
- xbLong l = 1;
- char dbfn[13];
- char dbtn[13];
-
- dnf = xbase->DirectoryExistsInName( GetFileName() );
- sprintf( dbfn, "xb%06d.dbf", l );
- sprintf( dbtn, "xb%06d.dbt", l++ );
-
- if( dnf ){
- sDbfn.assign( GetFileName(), 0, dnf );
- sDbfn += dbfn;
- sDbtn.assign( GetFileName(), 0, dnf );
- sDbtn += dbtn;
- } else {
- sDbfn = dbfn;
- sDbtn = dbtn;
- }
-
- while( !unique ){
- if( access( sDbfn.getData(), 0 ) == -1 &&
- access( sDbtn.getData(), 0 ) == -1 )
- unique++;
- else{
- sprintf( dbfn, "xb%06d.dbf", l );
- sprintf( dbtn, "xb%06d.dbt", l++ );
-
- if( dnf ){
- sDbfn.assign( GetFileName(), 0, dnf );
- sDbfn += dbfn;
- sDbtn.assign( GetFileName(), 0, dnf );
- sDbtn += dbtn;
- } else {
- sDbfn = dbfn;
- sDbtn = dbtn;
- }
- }
- }
- return 0;
-}
-
-/************************************************************************/
-//! Pack data file
-/*!
-*/
-xbShort xbDbf::PackDatafiles(void (*statusFunc)(xbLong itemNum, xbLong numItems))
-{
- xbShort rc, i;
- FILE *t;
- xbLong l;
- char *target, *source;
- xbString TempDbfName;
- xbString TempDbtName;
- char * Buf = 0;
-
-#ifdef XB_MEMO_FIELDS
- char tbuf[4];
-#endif
-
-#ifdef XB_MEMO_FIELDS
- xbLong len, BufSize;
- xbShort MemoFields;
-#endif /* XB_MEMO_FIELDS */
-
- xbDbf Temp( xbase );
- CreateUniqueDbfName( TempDbfName, TempDbtName );
-
- if(( t = fopen( TempDbfName, "w+b" )) == NULL )
- return XB_OPEN_ERROR;
-
- /* copy file header */
- if(( rc = _fseek( fp, 0, SEEK_SET )) != 0 )
- return XB_SEEK_ERROR;
-
- for( i = 0; i < HeaderLen; i++ )
- fputc( fgetc( fp ), t );
- fputc( 0x1a, t );
-
- if( fclose( t ) != 0 )
- return XB_CLOSE_ERROR;
-
-#ifdef XB_MEMO_FIELDS
- if(( MemoFields = MemoFieldsPresent()) > 0 ){
-
- if((t = fopen( TempDbtName, "w+b" )) == NULL)
- return XB_OPEN_ERROR;
-
- l = 1L;
- memset( tbuf, 0x00, 4 );
- xbase->PutLong( tbuf, l );
-
- if((fwrite(&tbuf, 4, 1, t)) != 1)
- return XB_WRITE_ERROR;
-
- if( MemoHeader.Version == 0x03 ){
- for( i = 0; i < 12; i++ ) fputc( 0x00, t );
- fputc( 0x03, t );
- for( i = 0; i < 495; i++ ) fputc( 0x00, t );
- } else {
- for( i = 0; i < 4; i++ ) fputc( 0x00, t );
- if ((fwrite(&MemoHeader.FileName, 8, 1, t)) != 1)
- return XB_WRITE_ERROR;
- for( i = 0; i < 4; i++ ) fputc( 0x00, t );
- memset( tbuf, 0x00, 2 );
- xbase->PutShort( tbuf, MemoHeader.BlockSize );
- if ((fwrite(&tbuf, 2, 1, t)) != 1)
- return XB_WRITE_ERROR;
-
- for( i = 22; i < MemoHeader.BlockSize; i++ ) fputc( 0x00, t );
- }
-
- if( fclose( t ) != 0 )
- return XB_CLOSE_ERROR;
- }
-#endif /* XB_MEMO_FIELDS */
-
- /* reopen as database */
- if(( rc = Temp.OpenDatabase( TempDbfName )) != XB_NO_ERROR )
- return rc;
-
-#ifdef XB_REAL_DELETE
- if(RealDelete)
- Temp.RealDeleteOn();
- Temp.FirstFreeRec = 0;
- Temp.RealNumRecs = 0;
-#endif
- Temp.ResetNoOfRecs();
- Temp.WriteHeader(2); // flush NoOfRecs=0 to disk
- target = Temp.GetRecordBuf();
- source = GetRecordBuf();
-
- for( l = 1; l <= PhysicalNoOfRecords(); l++ ){
- if(statusFunc && (l == 1 || !(l % 100) || l == PhysicalNoOfRecords()))
- statusFunc(l, PhysicalNoOfRecords());
-
- if(( rc = GetRecord( l )) != XB_NO_ERROR )
- return rc;
-
- if( !RecordDeleted() ){
- memcpy( target, source, GetRecordLen());
-
-#ifdef XB_MEMO_FIELDS
- BufSize = 0L;
-// Buf = NULL; Already set to 0, this statement flags as memory leak
-
- for( i = 0; i < NoOfFields; i++ ){
- if( GetFieldType( i ) == 'M' && MemoFieldExists( i )){
- Temp.PutLongField(i, 0L);
- len = GetMemoFieldLen( i );
- if( len > BufSize ){
- if( Buf )
- free( Buf );
- if((Buf = (char *)malloc(len)) == NULL)
- return XB_NO_MEMORY;
- BufSize = len;
- }
- GetMemoField( i, len, Buf, -1 );
- Temp.UpdateMemoData( i, len, Buf, -1 );
- }
- }
-#endif
- if(( rc = Temp.AppendRecord()) != XB_NO_ERROR ){
- if(Buf) free(Buf);
- return rc;
- }
- }
- }
- if( Buf ) free( Buf );
- Temp.CloseDatabase();
-
- if(fclose(fp) != 0)
- return XB_CLOSE_ERROR;
-
- if(remove(GetFileName()) != 0)
- return XB_WRITE_ERROR;
-
- if(rename(TempDbfName, GetFileName()) != 0)
- return XB_WRITE_ERROR;
-
-#ifdef XB_MEMO_FIELDS
- if( MemoFields ){
- if(fclose(mfp) != 0)
- return XB_CLOSE_ERROR;
-
- if(remove(MemofileName) != 0)
- return XB_WRITE_ERROR;
- if( rename( TempDbtName, MemofileName ) != 0 )
- return XB_WRITE_ERROR;
- if(( mfp = fopen( MemofileName, "r+b" )) == NULL )
- return XB_OPEN_ERROR;
- if(( rc = GetDbtHeader(1)) != 0 ){
- fclose( mfp );
- return rc;
- }
-#ifdef XB_LOCKING_ON
- /* no buffering in multi user mode */
- setbuf( mfp, NULL );
-#endif
- }
-
-#endif /* XB_MEMO_FIELDS */
-
- if(( fp = fopen( GetFileName(), "r+b" )) == NULL )
- return XB_OPEN_ERROR;
-
-#ifdef XB_LOCKING_ON
- /* no buffering in multi user mode */
- setbuf( fp, NULL );
-#endif
-
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Pack the database
-/*!
- This method removes all records marked for deletion from an Xbase (.DBF)
- file, reindexes any open index files, and also reorganizes any memo fields
- stored in a .DBT memo file.
-
- \param packStatusFunc status function
- \param indexStatusFunc index status function
-
- \param LockWaitOption One of the following:
- \htmlonly
- <p>
- <table border=2><tr><th>LockWaitOption</th><th>Description</th></tr>
- <tr><td>F_SETLK</td><td>Return immediately if the DBF file cannot be locked</td></tr>
- <tr><td>XB_LOCK</td><td>Wait for lock on DBF file to succeed</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{LockWaitOption} & \textbf{Description} \\ \hline \hline
- F\_SETLK & Return immediately if DBF file cannot be locked \\ \hline
- F\_SETLKW & Wait for lock on DBF file to succeed \\ \hline
- \end{tabular}
- \endlatexonly
-
- \returns One of the following return codes:
- \htmlonly
- <p>
- <table border=2><tr><th>Return Code</th><th>Description</th></tr>
- <tr><td>XB_NO_ERROR</td><td>No error</td></tr>
- <tr><td>XB_CLOSE_ERROR</td><td>Unable to close intermediate work file</td></tr>
- <tr><td>XB_OPEN_ERROR</td><td>Could not open file</td></tr>
- <tr><td>XB_NO_MEMORY</td><td>Memory allocation error</td></tr>
- <tr><td>XB_WRITE_ERROR</td><td>Couldn't write to disk</td></tr>
- <tr><td>XB_SEEK_ERROR</td><td>Error seeking file</td></tr>
- <tr><td>XB_LOCK_FAILED</td><td>Unable to lock file or index</td></tr>
- </table>
- \endhtmlonly
- \latexonly
- \\
- \\
- \begin{tabular}{|l|l|} \hline
- \textbf{Return Code} & \textbf{Description} \\ \hline \hline
- XB\_NO\_ERROR & No Error \\ \hline
- XB\_CLOSE\_ERROR & Unable to close intermediate work file \\ \hline
- XB\_OPEN\_ERROR & Couldn't open the file \\ \hline
- XB\_NO\_MEMORY & Memory allocation error \\ \hline
- XB\_WRITE\_ERROR & Couldn't write to disk \\ \hline
- XB\_SEEK\_ERROR & Error seeking file \\ \hline
- XB\_LOCK\_FAILED & Unable to lock file or index \\ \hline
- \end{tabular}
- \endlatexonly
-*/
-xbShort xbDbf::PackDatabase(xbShort LockWaitOption,
- void (*packStatusFunc)(xbLong itemNum, xbLong numItems),
- void (*indexStatusFunc)(xbLong itemNum, xbLong numItems))
-{
- xbShort rc;
-
- /* lock all open files and indexes */
-// if(( rc = ExclusiveLock( LockWaitOption )) != XB_NO_ERROR ) return rc;
-
- if(( rc = PackDatafiles(packStatusFunc)) != XB_NO_ERROR ){
-// ExclusiveUnlock();
- return rc;
- }
-
- /* refresh file header */
- if(( rc = ReadHeader(1)) != XB_NO_ERROR )
- return rc;
-
- if(( rc = RebuildAllIndices(indexStatusFunc)) != XB_NO_ERROR )
- return rc;
-
-// ExclusiveUnlock();
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Copy DBF structure
-/*!
-*/
-xbShort xbDbf::CopyDbfStructure(const char *NewFileName, xbShort Overlay) {
-
- xbShort rc, i;
- xbString ndfn; /* new dbf file name */
- char ch;
-
-#ifdef XB_MEMO_FIELDS
- char buf[9];
- xbShort ct, NameLen;
- xbString MemoName;
-#endif
- FILE *t;
-
- /* build the new file name */
- rc = NameSuffixMissing( 1, NewFileName );
- ndfn = NewFileName;
- if( rc == 1 )
- ndfn += ".dbf";
- else if( rc == 2 )
- ndfn += ".DBF";
-
- /* check if the file exists and Overlay is on */
- if(((t = fopen( ndfn, "r" )) != NULL ) && !Overlay) {
- fclose(t);
- return XB_FILE_EXISTS;
- }
-
- /* open new file */
- if((t = fopen(ndfn, "w+b")) == NULL)
- return XB_OPEN_ERROR;
-
- /* copy the file header */
- if(( rc = _fseek( fp, 0, SEEK_SET )) != 0 )
- return XB_SEEK_ERROR;
-
- fputc( fgetc( fp ), t );
-
- /* do the date */
- xbDate d;
- ch = d.YearOf() - 1900;
- if(XFV == 3)
- ch %= 100; // dBASE III+ does this, dBASE IV does not.
- fputc( ch, t );
- ch = d.MonthOf();
- fputc( ch, t );
- ch = d.DayOf( XB_FMT_MONTH );
- fputc( ch, t );
-
- /* record count */
- for( i = 0; i < 4; i++ ) fputc( 0x00, t );
-
- if((rc = _fseek(fp, 7, SEEK_CUR)) != 0) {
- fclose( t );
- return XB_SEEK_ERROR;
- }
- for( i = 0; i < 4; i++ )
- fputc( fgetc( fp ), t );
-
- for( i = 0; i < 17; i++ )
- fputc( 0x00, t );
-
- if((rc = _fseek( fp, 17, SEEK_CUR )) != 0) {
- fclose( t );
- return XB_SEEK_ERROR;
- }
-
- for( i = 29; i < HeaderLen; i++ )
- fputc( fgetc( fp ), t );
-
- fputc( 0x1a, t );
- fclose( t );
-
-#ifdef XB_MEMO_FIELDS
- if( MemoFieldsPresent()){
- MemoName = ndfn;
-
- NameLen = MemoName.len();
- NameLen--;
- if( MemoName.getCharacter( NameLen ) == 'F' )
- MemoName.putAt(NameLen, 'T');
- else
- MemoName.putAt(NameLen, 't');
-
- if(( t = fopen( MemoName, "w+b" )) == NULL )
- return XB_OPEN_ERROR;
-
- memset( buf, 0x00, 4 );
- xbase->PutLong( buf, 1L );
- if(( fwrite( &buf, 4, 1, t )) != 1 ){
- fclose( t );
- return XB_WRITE_ERROR;
- }
- if( MemoHeader.Version == 0x03 ){
- for( i = 0; i < 12; i++ ) fputc( 0x00, t );
- fputc( 0x03, t );
- for( i = 0; i < 495; i++ ) fputc( 0x00, t );
- }
- else
- {
- for( i = 0; i < 4; i++ ) fputc( 0x00, t ); // put 4 bytes 0x00
- memset( buf, 0x00, 9 );
- NameLen = ndfn.len();
- for( i = 0, ct = 0; i < NameLen; i++ )
- if( ndfn.getCharacter( i ) == PATH_SEPARATOR ){
- ct = i;
- ct++;
- }
-
- for( i = 0; i < 8 && ndfn[i+ct] != '.'; i++ )
- buf[i] = ndfn[i+ct];
-
- fwrite( &buf, 8, 1, t );
- for( i = 0; i < 4; i++ ) fputc( 0x00, t );
- memset( buf, 0x00, 2 );
- xbase->PutShort( buf, MemoHeader.BlockSize );
- if(( fwrite( &buf, 2, 1, t )) != 1 ){
- fclose(t);
- return XB_WRITE_ERROR;
- }
- for( i = 22; i < MemoHeader.BlockSize; i++ ) fputc( 0x00, t );
- }
- }
- fclose( t );
-#endif // XB_MEMO_FIELDS
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Add index to list
-/*!
- Adds the specified index to the list of indexes maintained by the
- dbf.
-
- \param n index to add
- \param IndexName name of index
-*/
-#if defined(XB_INDEX_ANY)
-xbShort xbDbf::AddIndexToIxList(xbIndex * n, const char *IndexName)
-{
- xbIxList *i, *s, *t;
-
- if( !FreeIxList ){
- if((i = (xbIxList *) malloc(sizeof(xbIxList))) == NULL)
- return XB_NO_MEMORY;
- }
- else
- {
- i = FreeIxList;
- FreeIxList = i->NextIx;
- }
- memset(i, 0x00, sizeof(xbIxList));
-
- i->IxName = IndexName;
- i->index = n;
-
- s = NULL;
- t = NdxList;
- while( t && strcmp( t->IxName, IndexName ) < 0 ){
- s = t;
- t = t->NextIx;
- }
- i->NextIx = t;
- if( s == NULL )
- NdxList = i;
- else
- s->NextIx = i;
- return 0;
-}
-#endif
-/************************************************************************/
-//! Rebuild all index files
-/*!
-*/
-xbShort xbDbf::RebuildAllIndices(void (*statusFunc)(xbLong itemNum, xbLong numItems))
-{
-#if defined(XB_INDEX_ANY)
- xbShort rc;
- xbIxList *n;
-
- n = NdxList;
- while( n ){
- if(( rc = n->index->ReIndex(statusFunc)) != XB_NO_ERROR ){
-// ExclusiveUnlock();
- return rc;
- }
- n = n->NextIx;
- }
-#endif
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Delete all records
-/*!
-*/
-xbShort xbDbf::DeleteAll( xbShort Option )
-{
- xbShort rc;
-
- if(( NoOfRecords()) == 0 )
- return XB_NO_ERROR;
- if(( rc = GetFirstRecord()) != XB_NO_ERROR )
- return rc;
-
- if( Option == 0 ){ /* delete all option */
- while( 1 ){
- if( !RecordDeleted())
- if(( rc = DeleteRecord()) != XB_NO_ERROR )
- return rc;
- if(( rc = GetNextRecord()) != XB_NO_ERROR )
- break;
- }
- }
- else /* undelete all option */
- {
- while( 1 ){
- if( RecordDeleted())
- if(( rc = UndeleteRecord()) != XB_NO_ERROR )
- return rc;
- if(( rc = GetNextRecord()) != XB_NO_ERROR )
- break;
- }
- }
- if( rc == XB_EOF )
- return XB_NO_ERROR;
- else
- return rc;
-}
-/************************************************************************/
-//! Delete all records and pack data file
-/*!
-*/
-xbShort xbDbf::Zap( xbShort WaitOption )
-{
- xbShort rc;
- xbString TempDbfName, TempDbtName;
-
- CreateUniqueDbfName( TempDbfName, TempDbtName );
- if(( rc = CopyDbfStructure( TempDbfName, 1 )) != XB_NO_ERROR) {
- return rc;
- }
-
- if( fp ){
- fclose( fp );
- fp = 0;
- }
-
- if(( rc = remove( GetFileName() )) != 0 )
- return XB_WRITE_ERROR;
-
- if(( rc = rename( TempDbfName, GetFileName() )) != 0 )
- return XB_WRITE_ERROR;
-
- if((fp = fopen( GetFileName(), "r+b" )) == NULL)
- return XB_OPEN_ERROR;
-
-#ifdef XB_LOCKING_ON
- setbuf( fp, NULL );
-#endif
- ReadHeader( 1 );
-
-#ifdef XB_MEMO_FIELDS
- if( MemoFieldsPresent() ){
- fclose( mfp );
-
- if(( rc = remove( MemofileName )) != 0 )
- return XB_WRITE_ERROR;
-
- if(( rc = rename( TempDbtName, MemofileName )) != 0 )
- return XB_WRITE_ERROR;
-
- if(( mfp = fopen( MemofileName, "r+b" )) == NULL)
- return XB_OPEN_ERROR;
-
- }
-#endif // XB_MEMO_FIELDS
-
- if(( rc = RebuildAllIndices()) != XB_NO_ERROR )
- return rc;
-
- return XB_NO_ERROR;
-}
-/************************************************************************/
-//! Remove an index from the list
-/*!
-*/
-#if defined(XB_INDEX_ANY)
-xbShort xbDbf::RemoveIndexFromIxList(xbIndex * n) {
- xbIxList *i, *s;
-
- i = NdxList;
- s = NULL;
- while( i ){
- if( i->index == n ){
- /* remove it from current chain */
- if( s )
- s->NextIx = i->NextIx;
- else
- NdxList = i->NextIx;
-
- /* add i to the current free chain */
- i->NextIx = FreeIxList;
- FreeIxList = i;
- FreeIxList->IxName = (const char *)NULL;
- FreeIxList->index = NULL;
- break;
- }
- else
- {
- s = i;
- i = i->NextIx;
- }
- }
- return XB_NO_ERROR;
-}
-#endif
-
-/************************************************************************/
-//! Gets the number of records in the data file
-/*!
-*/
-xbLong xbDbf::NoOfRecords()
-{
- xbLong numRecs;
-
-/* lock the database */
-#ifdef XB_LOCKING_ON
- xbShort rc;
-
- if( AutoLock ){
-// if(( rc = LockDatabase( XB_LOCK, 0L )) != XB_NO_ERROR )
-// return rc;
-
- if((rc = ReadHeader(1)) != XB_NO_ERROR){
-// if(AutoLock)
-// LockDatabase( XB_UNLOCK, 0L );
- return rc;
- }
- }
-#endif
-
-#ifndef XB_REAL_DELETE
- numRecs = NoOfRecs;
-#else
- numRecs = RealDelete ? RealNumRecs : NoOfRecs;
-#endif
-
-#ifdef XB_LOCKING_ON
-// if(AutoLock)
-// LockDatabase( XB_UNLOCK, 0L );
-#endif
-
- return numRecs;
-}
-/************************************************************************/
-//! Get the physical number of records in the data file
-/*!
-*/
-xbLong xbDbf::PhysicalNoOfRecords()
-{
- xbShort rc;
-
-/* lock the database */
-#ifdef XB_LOCKING_ON
-// if( AutoLock )
-// if(( rc = LockDatabase( XB_LOCK, 0L )) != XB_NO_ERROR )
-// return rc;
-#endif
-
- rc = ReadHeader(1);
-
-#ifdef XB_LOCKING_ON
-// if(AutoLock)
-// if(( rc = LockDatabase( XB_UNLOCK, 0L )) != XB_NO_ERROR )
-// return rc;
-#endif
-
- if( rc )
- return rc;
-
- return NoOfRecs;
-}
-
-/************************************************************************/
-#if defined(XB_INDEX_ANY)
-//! Get the number of currently open indexes for data file
-/*!
-*/
-xbShort xbDbf::IndexCount()
-{
- xbShort count;
- xbIxList *i;
-
- for(count = 0, i = NdxList; i; i = i->NextIx, count++) ;
-
- return count;
-}
-/************************************************************************/
-//! Get a specific index
-/*!
-*/
-xbIndex * xbDbf::GetIndex(xbShort indexNum)
-{
- xbIxList *i;
-
- i = NdxList;
- while(indexNum && i){
- indexNum--;
- i = i->NextIx;
- }
-
- if(i)
- return i->index;
-
- return 0;
-}
-
-#endif // XB_INDEX_ANY
-/************************************************************************/
-void xbDbf::Flush()
-{
- if(fp)
- fflush(fp);
-
-#ifdef XB_MEMO_FIELDS
- if(mfp)
- fflush(mfp);
-#endif
-
-#if defined(XB_INDEX_ANY)
- xbIxList
- *i;
-
- i = NdxList;
- while(i) {
- i->index->Flush();
- i = i->NextIx;
- }
-#endif
-}
-/************************************************************************/
-#ifdef XB_LOCKING_ON
-xbShort xbDbf::SetLockMode( xbShort nlm )
-{
-/*
- xbShort rc;
- if( LockMode != XB_XBASE_LOCK_MODE &&
- nlm == XB_XBASE_LOCK_MODE &&
- !xblfh ){
- rc = OpenXbLockFile();
- if( rc )
- return rc;
- }
-*/
- LockMode = nlm;
- return XB_NO_ERROR;
-}
-#endif
-/************************************************************************/
-const char * xbDbf::GetExtWithDot( bool lower )
-{
- return lower ? ".dbf" : ".DBF";
-}