📄 memo.cpp
字号:
/*************************************************************************** memo.cpp - description ------------------- begin : Thu Jan 17 2002 copyright : (C) 2002 by email : ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************//* $Id: memo.cpp,v 1.5 2000/11/07 20:31:20 dbryson Exp $ Xbase project source code This file contains the basic Xbase routines for handling dBASE III+ and dBASE IV style memo .dbt files Copyright (C) 1997 StarTech, Gary A. Kunkel This library 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.1 of the License, or (at your option) any later version. This library 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 library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Mail: Technology Associates, Inc. XBase Project 1455 Deming Way #11 Sparks, NV 89434 USA Email: xbase@techass.com See our website at: xdb.sourceforge.net V 1.0 10/10/97 - Initial release of software V 1.5 1/2/98 - Added memo field support V 1.6a 4/1/98 - Added expression support V 1.6b 4/8/98 - Numeric index keys V 1.7.1 5/25/98 - Added support for dBase III+ type memo files*/#ifdef __WIN32__#include "xbconfigw32.h"#else#include "xbconfig.h"#endif#include "xbase.h"#ifdef XB_MEMO_FIELDS#include <stdio.h>#include "xbexcept.h"/*! \file memo.cpp*//************************************************************************///! Short description/*!*/xbLong xbDbf::CalcLastDataBlock(){ xbShort rc; if(( rc = fseek( mfp, 0, SEEK_END )) != 0 ) xb_error( XB_SEEK_ERROR ); return ( ftell( mfp ) / MemoHeader.BlockSize );}/************************************************************************///! Short description/*! \param BlocksNeeded \param Location \param PrevNode*/xbShort xbDbf::GetBlockSetFromChain( const xbLong BlocksNeeded, const xbLong Location, const xbLong PrevNode )/* this routine grabs a set of blocks out of the free block chain */ { xbShort rc; xbLong NextFreeBlock2, NewFreeBlocks, SaveNextFreeBlock; if(( rc = ReadMemoBlock( Location, 2 )) != XB_NO_ERROR ) xb_error( rc ); if( BlocksNeeded == FreeBlockCnt ) /* grab this whole set of blocks */ { if( PrevNode == 0 ) /* first in the chain */ { MemoHeader.NextBlock = NextFreeBlock; if(( rc = UpdateHeadNextNode()) != XB_NO_ERROR ) xb_error( rc ); } else /* remove out of the middle or end */ { NextFreeBlock2 = NextFreeBlock; if(( rc = ReadMemoBlock( PrevNode, 2 )) != XB_NO_ERROR ) xb_error( rc ); NextFreeBlock = NextFreeBlock2; if(( rc = WriteMemoBlock( PrevNode, 2 )) != XB_NO_ERROR ) xb_error( rc ); } } else /* only take a portion of this set */ { if( PrevNode == 0 ) /* first in the set */ { MemoHeader.NextBlock = Location + BlocksNeeded; if(( rc = UpdateHeadNextNode()) != XB_NO_ERROR ) xb_error( rc ); FreeBlockCnt -= BlocksNeeded; if(( rc = WriteMemoBlock( MemoHeader.NextBlock, 2 )) != XB_NO_ERROR ) xb_error( rc ); } else /* remove out of the middle or end */ { NewFreeBlocks = FreeBlockCnt - BlocksNeeded; SaveNextFreeBlock = NextFreeBlock; NextFreeBlock2= Location + BlocksNeeded; if(( rc = ReadMemoBlock( PrevNode, 2 )) != XB_NO_ERROR ) xb_error( rc ); NextFreeBlock = NextFreeBlock2; if(( rc = WriteMemoBlock( PrevNode, 2 )) != XB_NO_ERROR ) xb_error( rc ); FreeBlockCnt = NewFreeBlocks; NextFreeBlock = SaveNextFreeBlock; if(( rc = WriteMemoBlock( NextFreeBlock2, 2 )) != XB_NO_ERROR ) xb_error( rc ); } } return 0;} /************************************************************************///! Short description/*! \param BlocksNeeded \param LastDataBlock \param Location \param PreviousNode*/xbShort xbDbf::FindBlockSetInChain( const xbLong BlocksNeeded, const xbLong LastDataBlock, xbLong &Location, xbLong &PreviousNode )/* this routine searches thru the free node chain in a dbase IV type memo file searching for a place to grab some free blocks for reuse LastDataBlock- is the last data block in the file, enter 0 for the routine to calculate it. BlocksNeeded - is the size to look in the chain for Location - is the location it finds PreviousNode - is the block number of the node imediately previous to this node in the chain - 0 if header node returns - 0 if no spot in chain found 1 if spot in chain is found*/{ xbShort rc; xbLong LDB, PrevNode, CurNode; if( LastDataBlock == 0 ) LDB = CalcLastDataBlock(); else LDB = LastDataBlock; if( MemoHeader.NextBlock < LDB ){ PrevNode = 0L; CurNode = MemoHeader.NextBlock; if(( rc = ReadMemoBlock( MemoHeader.NextBlock, 2 )) != XB_NO_ERROR ) return rc; while( BlocksNeeded > FreeBlockCnt && NextFreeBlock < LDB ){ PrevNode = CurNode; CurNode = NextFreeBlock; if(( rc = ReadMemoBlock( NextFreeBlock, 2 )) != XB_NO_ERROR ) return rc; } if( BlocksNeeded <= FreeBlockCnt ){ Location = CurNode; PreviousNode = PrevNode; return 1; } else{ /* no data found and at end of chain */ PreviousNode = CurNode; return 0; } } else{ PreviousNode = 0; return 0; }}/************************************************************************///! Short description/*! \param BlockSize*/xbShort xbDbf::SetMemoBlockSize( const xbShort BlockSize ){ if(IsType3Dbt()) return XB_NO_ERROR; // not applicable for type 3 if( BlockSize % 512 != 0 ) xb_error(XB_INVALID_BLOCK_SIZE); MemoHeader.BlockSize = BlockSize; return XB_NO_ERROR;}/***********************************************************************///! Short description/*! \param Option*/xbShort xbDbf::GetDbtHeader( const xbShort Option ){ char *p; xbShort i; char MemoBlock[24]; /* Option = 0 --> read only first four bytes 1 --> read the entire thing */ if( !mfp ) xb_error(XB_NOT_OPEN); if( fseek( mfp, 0, SEEK_SET )) xb_error(XB_SEEK_ERROR); if(( fread( MemoBlock, 24, 1, mfp )) != 1 ) xb_error(XB_READ_ERROR); p = MemoBlock; MemoHeader.NextBlock = xbase->GetLong( p ); if(IsType3Dbt() || Option == 0) return XB_NO_ERROR; /* version IV stuff follows */ p+=8; for( i = 0; i < 8; i++, p++ ) MemoHeader.FileName[i] = *p; MemoHeader.Version = *p; p+=4; MemoHeader.BlockSize = xbase->GetShort( p ); return XB_NO_ERROR;}/***********************************************************************///! Short description/*!*/xbShort xbDbf::OpenMemoFile( void ){ xbLong Size, NewSize, l; xbShort len, rc; len = DatabaseName.len() - 1; char lb = DatabaseName.getCharacter( len ); if( lb == 'F' ) DatabaseName.putAt(len, 'T'); else if( lb == 'f' ) DatabaseName.putAt(len, 't'); else xb_error(XB_INVALID_NAME); if(( mfp = fopen( DatabaseName, "r+b" )) == NULL ){ DatabaseName.putAt(len, lb); xb_open_error(DatabaseName); }#ifdef XB_LOCKING_ON setbuf( mfp, NULL );#endif DatabaseName.putAt(len, lb); if(( rc = GetDbtHeader(1)) != 0 ) { fclose( mfp ); return rc; } len = GetMemoBlockSize(); if( len == 0 || ((len % 512) != 0 )) { fclose( mfp ); xb_error(XB_INVALID_BLOCK_SIZE); } /* logic to verify file size is a multiple of block size */ if(( rc = fseek( mfp, 0, SEEK_END )) != 0 ) { fclose( mfp ); xb_io_error(XB_SEEK_ERROR, DatabaseName); } /* if the file is not a multiple of block size, fix it, append nulls */ Size = ftell( mfp ); if(( Size % MemoHeader.BlockSize ) != 0 ) { NewSize = ( Size / MemoHeader.BlockSize + 1) * MemoHeader.BlockSize; for( l = Size; l < NewSize; l++ ) fputc( 0x00, mfp ); } if(( mbb = (void *) malloc(len)) == NULL ) { fclose( mfp ); xb_memory_error; } return XB_NO_ERROR;}/***********************************************************************///! Short description/*!*/xbShort xbDbf::CreateMemoFile( void ){ xbShort len,i; char *sp; char buf[4]; len = GetMemoBlockSize(); if( len == 0 || len % 512 != 0 ) xb_error(XB_INVALID_BLOCK_SIZE); if(( sp = (char*)strrchr(DatabaseName, PATH_SEPARATOR)) != NULL ) sp++; else sp = MemoHeader.FileName; memset( MemoHeader.FileName, 0x00, 8 ); for( i = 0; i < 8 && *sp != '.'; i++ ) MemoHeader.FileName[i] = *sp++; len = DatabaseName.len() - 1; char lb = DatabaseName.getCharacter( len ); if( lb == 'F' ) DatabaseName.putAt(len, 'T'); else if( lb == 'f' ) DatabaseName.putAt(len, 't'); else xb_io_error(XB_INVALID_NAME, DatabaseName); /* Initialize the variables */ MemoHeader.NextBlock = 1L; if(( mfp = fopen( DatabaseName, "w+b" )) == NULL ) { DatabaseName.putAt(len, lb); xb_open_error(DatabaseName); }#ifdef XB_LOCKING_ON setbuf( mfp, NULL );#endif DatabaseName.putAt(len, lb); if(( fseek( mfp, 0L, SEEK_SET )) != 0 ) { fclose( mfp ); xb_io_error(XB_SEEK_ERROR, DatabaseName); } memset( buf, 0x00, 4 ); xbase->PutLong( buf, MemoHeader.NextBlock ); if(( fwrite( &buf, 4, 1, mfp )) != 1 ) { fclose( mfp ); xb_io_error(XB_WRITE_ERROR, DatabaseName); } if( IsType3Dbt() ) /* dBASE III+ */ { for( i = 0; i < 12; i++ ) fputc( 0x00, mfp ); fputc( 0x03, mfp ); for( i = 0; i < 495; i++ ) fputc( 0x00, mfp ); } else { for( i = 0; i < 4; i++ ) fputc( 0x00, mfp ); fwrite( &MemoHeader.FileName, 8, 1, mfp ); for( i = 0; i < 4; i++ ) fputc( 0x00, mfp ); memset( buf, 0x00, 2 ); xbase->PutShort( buf, MemoHeader.BlockSize ); if(( fwrite( &buf, 2, 1, mfp )) != 1 ) { fclose( mfp ); xb_io_error(XB_WRITE_ERROR, DatabaseName); } for( i = 22; i < MemoHeader.BlockSize; i++ ) fputc( 0x00, mfp ); } if(( mbb = (void *) malloc( MemoHeader.BlockSize )) == NULL ) { fclose( mfp ); xb_memory_error; } return XB_NO_ERROR;}/***********************************************************************///! Short description/*! \param BlockNo \param Option*//* Option = 0 - 1st Block of a set of valid data blocks, load buckets *//* Option = 1 - subsequant block of data in a multi block set or db III*//* Option = 2 - 1st block of a set of free blocks, load buckets */ /* Option = 3 - read 8 bytes of a block, don't load any buckets *//* Option = 4 - read 8 bytes of a block, load data buckets */xbShort xbDbf::ReadMemoBlock( const xbLong BlockNo, const xbShort Option ){ xbLong ReadSize; CurMemoBlockNo = -1; if( BlockNo < 1L ) xb_error(XB_INVALID_BLOCK_NO); if( fseek( mfp,(xbLong) BlockNo * MemoHeader.BlockSize, SEEK_SET )) xb_error(XB_SEEK_ERROR); if( Option == 0 || Option == 1 ) ReadSize = MemoHeader.BlockSize; else ReadSize = 8L; if(fread( mbb, ReadSize, 1, mfp ) != 1 ) xb_error(XB_READ_ERROR); if( Option == 0 || Option == 4) // 1st block of a set of valid data blocks { mfield1 = xbase->GetShort( (char *) mbb ); MStartPos = xbase->GetShort( (char *) mbb+2 ); MFieldLen = xbase->GetLong ( (char *) mbb+4 ); } else if( Option == 2 ) // 1st block of a set of free blocks { NextFreeBlock = xbase->GetLong( (char *) mbb ); FreeBlockCnt = xbase->GetLong( (char *) mbb+4 ); } if( Option == 0 || Option == 1 ) CurMemoBlockNo = BlockNo; return XB_NO_ERROR;}/************************************************************************///! Short description/*! \param BlockNo \param Option*/xbShort xbDbf::WriteMemoBlock( const xbLong BlockNo, const xbShort Option ){/* Option = 0 - 1st Block of a set of valid data blocks, set buckets *//* Option = 1 - subsequant block of data in a multi block set or db III *//* Option = 2 - 1st block of a set offree blocks, set buckets */ xbLong WriteSize; if( BlockNo < 1L ) xb_error(XB_INVALID_BLOCK_NO); CurMemoBlockNo = -1; if( Option == 0 ) { xbase->PutShort( (char *) mbb, mfield1 ); xbase->PutShort( (char *) mbb+2, MStartPos ); xbase->PutLong ( (char *) mbb+4, MFieldLen ); WriteSize = MemoHeader.BlockSize; } else if( Option == 2 ) { xbase->PutLong((char *) mbb, NextFreeBlock ); xbase->PutLong((char *) mbb+4, FreeBlockCnt ); WriteSize = 8L; } else WriteSize = MemoHeader.BlockSize; if( fseek( mfp,(xbLong) BlockNo * MemoHeader.BlockSize, SEEK_SET )) xb_error(XB_SEEK_ERROR); if(( fwrite( mbb, WriteSize, 1, mfp )) != 1 ) xb_error(XB_WRITE_ERROR); if( Option == 0 || Option == 1 ) CurMemoBlockNo = BlockNo; return XB_NO_ERROR;}/***********************************************************************///! Short description/*! \param FieldNo \param len \param Buf \param LockOpt*/xbShort xbDbf::GetMemoField( const xbShort FieldNo, const xbLong len, char * Buf, const xbShort LockOpt ){ xbLong BlockNo, Tcnt, Scnt; char *tp, *sp; /* target and source pointers */ xbShort rc; xbShort Vswitch; if( FieldNo < 0 || FieldNo > ( NoOfFields - 1 )) xb_error(XB_INVALID_FIELDNO); if( GetFieldType( FieldNo ) != 'M' ) xb_error(XB_NOT_MEMO_FIELD);#ifdef XB_LOCKING_ON if( LockOpt != -1 ) if(( rc = LockMemoFile( LockOpt, F_RDLCK )) != XB_NO_ERROR ) return XB_LOCK_FAILED;#endif if(( BlockNo = GetLongField( FieldNo )) == 0 ) {#ifdef XB_LOCKING_ON if( LockOpt != -1 ) LockMemoFile( F_SETLK, F_UNLCK );#endif xb_error(XB_NO_MEMO_DATA); } if( IsType3Dbt() ) Vswitch = 1; else Vswitch = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -