📄 dbf.cpp
字号:
MemoHeader.Version = 0x03;#endif } else if( Version == 4 || Version == (char)0x8B ) /* dBASE IV */ { XFV = 4;#ifdef XB_MEMO_FIELDS MemoHeader.Version = 0x00;#endif } else { InitVars(); xb_error(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 if (/*UpdateYY == 0 ||*/ UpdateMM == 0 || UpdateDD == 0 ) { InitVars(); xb_error(XB_NOT_XBASE); } /* calculate the number of fields */ NoOfFields = ( HeaderLen - 33 ) / 32; if(( RecBuf = (char *) malloc( RecordLen )) == NULL ) { fclose( fp ); InitVars(); xb_memory_error; } if(( RecBuf2 = (char *) malloc( RecordLen )) == NULL ) { fclose( fp ); free( RecBuf ); InitVars(); xb_memory_error; } if((SchemaPtr=(xbSchemaRec *)malloc(NoOfFields*sizeof(xbSchemaRec)))==NULL){ free( RecBuf ); free( RecBuf2 ); fclose( fp ); InitVars(); xb_memory_error; } memset( SchemaPtr, 0x00, ( NoOfFields * sizeof(xbSchemaRec))); /* copy field info into memory */ for( i = 0, j = 1; i < NoOfFields; i++ ){ fseek( fp, i*32+32, 0 ); // fread( &SchemaPtr[i].FieldName, 1, 18, fp ); 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; DbfStatus = XB_OPEN; BlankRecord();#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( F_SETLK, F_UNLCK, 0L );#endif /* XB_LOCKING_ON */ return xbase->AddDbfToDbfList( this, DatabaseName );}/************************************************************************///! Blank the record buffer./*! Sets the record to spaces.*/xbShort xbDbf::BlankRecord( void ){ if( DbfStatus == XB_CLOSED ) xb_error(XB_NOT_OPEN); 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 XDB DBF file and updates the file date and number of records in the file. Also updates any open indexes 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( void ){ xbShort rc = 0; xbULong nextRecNo;#if defined(XB_INDEX_ANY) xbIxList *i;#endif/* lock the database */#ifdef XB_LOCKING_ON if( AutoLock ) if(( rc = LockDatabase( F_SETLKW, F_WRLCK, 0L )) != XB_NO_ERROR) return rc; if((rc = ReadHeader(1)) != XB_NO_ERROR) { if(AutoLock) LockDatabase( F_SETLK, F_UNLCK, 0L ); 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( F_SETLKW, F_WRLCK )) != 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 ) xb_error(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, ((long) HeaderLen + ((FirstFreeRec - 1) * RecordLen) + 1), 0) != 0) xb_error(XB_SEEK_ERROR); if(fread(buf, 4, 1, fp) != 1) xb_error(XB_READ_ERROR); FirstFreeRec = xbase->GetULong(buf); } /* ** Okay, seek and write the record out */ if(fseek(fp, ((long) HeaderLen + ((nextRecNo - 1) * RecordLen)), 0) != 0) xb_error(XB_SEEK_ERROR); if(fwrite( RecBuf, RecordLen, 1, fp) != 1) xb_error(XB_WRITE_ERROR); /* ** If we just appended the record to the file, then write the EOF char */ if(nextRecNo == NoOfRecs + 1) {// if(fwrite( EofChar, 1, 1, fp ) != 1 ) if( fputc( XB_CHAREOF, fp ) != XB_CHAREOF ) xb_error(XB_WRITE_ERROR); }#else /* write the last record */ if( fseek( fp, ((long) HeaderLen + ( NoOfRecs * RecordLen )), 0 ) != 0 ) xb_error(XB_SEEK_ERROR); if( fwrite( RecBuf, RecordLen, 1, fp ) != 1 ) xb_error(XB_WRITE_ERROR); /* write the end of file marker */// if( fwrite( "\x0d", 1, 1, fp ) != 1 )// if( fwrite( EofChar, 1, 1, fp ) != 1 ) if( fputc( XB_CHAREOF, fp ) != XB_CHAREOF ) xb_error(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;// CurRec = NoOfRecs; /* rewrite the header record */ if(( rc = WriteHeader( 1 )) != XB_NO_ERROR ) return rc;#ifdef XB_LOCKING_ON if( AutoLock ) LockDatabase( F_SETLK, F_UNLCK, 0L );#if defined(XB_INDEX_ANY) i = NdxList; while( i && AutoLock ){ i->index->LockIndex( F_SETLK, F_UNLCK ); 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 ){/* 4/16/2000 - gk - made mods to record locking logic */ int rc; if( DbfStatus == XB_CLOSED ) xb_error(XB_NOT_OPEN); #ifndef XB_LOCKING_ON if( DbfStatus == XB_UPDATED /*&& AutoUpdate*/ ) /* update previous rec if necessary */ if(( rc = PutRecord( CurRec )) != 0 ) return rc;#endif #ifdef XB_LOCKING_ON if( AutoLock ) if(( rc = LockDatabase( F_SETLKW, F_RDLCK, RecNo )) != 0 ) return rc; if((rc = ReadHeader(1)) != XB_NO_ERROR) { if(AutoLock) LockDatabase( F_SETLK, F_UNLCK, RecNo ); return rc; }#endif if( RecNo > NoOfRecs || RecNo == 0L ) xb_error(XB_INVALID_RECORD); /* michael - modified code to avoid unecessary fseek work */ /* commented out this code because it doesn't work in DOS/Win environments */// if( !CurRec || RecNo != CurRec+1 )// { if( fseek( fp, (long) HeaderLen+((RecNo-1L)*RecordLen), SEEK_SET )) {#ifdef XB_LOCKING_ON LockDatabase( F_SETLK, F_UNLCK, RecNo );#endif xb_error(XB_SEEK_ERROR); }// } if( fread( RecBuf, RecordLen, 1, fp ) != 1 ) {#ifdef XB_LOCKING_ON LockDatabase( F_SETLK, F_UNLCK, RecNo );#endif xb_error(XB_READ_ERROR); }#ifdef XB_LOCKING_ON if( AutoLock ) LockDatabase( F_SETLKW, F_UNLCK, 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( void ){ xbShort rc = 0; if( NoOfRecs == 0 ) xb_error(XB_INVALID_RECORD);#ifndef XB_LOCKING_ON if( DbfStatus == XB_UPDATED /*&& AutoUpdate*/ ) /* updatfe previous rec if necessary */ if(( rc = PutRecord( CurRec )) != 0 ) return rc;#endif 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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -