📄 dbf.cpp
字号:
#include "stdafx.h"
#include "dbf.h"
#include "xntoy.h"
//*************************************************************
// DBF读写类库跨平台版本,在windows、linux、Sco下编译通过。
// 修改:袁斌
// oldworm@21cn.com
// http://yb.nos.com.cn/index.html
// 时间:2000年4月11日
// bug report: 内部->yb@compagis.com
// 外部->oldworm@21cn.com
//
// 主要修改内容:
// 一、速度方面的修改。
// 1、将原先通过多个sprintf、sscanf等写一条记录的方式改为
// 通过调用xntoy系列函数取代,速度提高不少。
// 2、将原先采用单链表方式组织的字段结构改成hash链表方式,
// 查找字段基本上为常数级别O(1),速度有一定提高。
//
// 二、安全性方面的修改。
// 1、使用snprintf取代以前的sprintf。
// 2、使用xntoy系列函数保证缓冲区不越界。
//
// 三、移植性方面的修改。
// 1、将全部_???函数换成???函数。
// 2、将全部_???参数换成???参数。
// 3、针对Linux下面没有的几个函数在xntoy里面作了实现。
//
// 四、其它修改内容。
// 1、将函数位置进行了调整,相同功能部分放在了一起。
// 2、将函数名称进行了调整,基本上采用ODBC一致的名称。
// 3、将有副作用的Append函数和读字段值函数进行了调整。
// 4、对相关数据结构进行了调整。
// 5、对一次读写多条记录的函数及相关内容全部删除。
//*************************************************************
#define LOCK_F_OFFSET 0x40000000L // Foxpro Table without CDX Index file
#define LOCK_C_OFFSET 1000000000L // Code base use this
#define LOCK_FILE_LEN 0x3FFFFFFFL
#define LOCK_DBF_BEGIN LOCK_C_OFFSET
#define LOCK_DBF_LENGTH (LOCK_FILE_LEN + (LOCK_F_OFFSET - LOCK_C_OFFSET) + 1)
#define LOCK_CDX_TABLE_OFFSET 0x7FFFFFFE // Foxpro Table with CDX Index file, decrement
#define WAIT_TIME 1L
static void _dos_getdate ( struct _dosdate_t *ddate )
{
time_t t;
struct tm * ptm;
time(&t);
ptm = localtime(&t);
ddate-> year = ptm->tm_year+1990; //t. GetYear ();
ddate-> month = ptm->tm_mon + 1; //t. GetMonth ();
ddate-> day = ptm->tm_mday; //t. GetDay ();
}
static long GetDate( void )
{
struct _dosdate_t ddate;
_dos_getdate( &ddate );
return ( ( ddate.year ) * 10000L + ddate.month * 100L + ddate.day ) ;
}
static long GetTime( void )
{
struct tm * cur_time ;
time_t long_time ;
time( &long_time ) ;
cur_time = localtime ( &long_time ) ;
return (cur_time->tm_hour * 10000lu +
cur_time->tm_min * 100lu +
cur_time->tm_sec ) ;
}
char * formatstr(char *str)
{
char * tmp;
char * tmp2;
tmp = str;
while (*tmp) tmp++;
if(*str) tmp--;
while (*tmp==' ') tmp--;
*(tmp+1) = 0;
tmp = str;
tmp2 = str;
while ( *tmp2 == ' ' ) tmp2 ++ ;
while ( *tmp2 != 0 )
{
*tmp = *tmp2; tmp ++; tmp2 ++;
}
*tmp = 0;
return str;
}
char * Trim(char *str)
{
char *p;
int i,len;
if((str==NULL) || (*str==0))
return (char *)str;
for(p=str, len=0; *p; p++) len++;
for(p=str,i=len-1;(i>=0) && (p[i]==' ');i--)
len--;
str[i+1] = 0;
for(; (*p==' '); p++) len--;
memmove(str,p,len+1);
return (char *)str;
}
inline void Dbf::_SetDosDate(DBF_HEAD *phead)
{
struct _dosdate_t datep ;
if(phead)
{
_dos_getdate( &datep );
phead->last_update[0] = (uchar)(datep.year % 100);
phead->last_update[1] = (uchar)(datep.month);
phead->last_update[2] = (uchar)(datep.day);
}
}
/******************************************************************************/
uint shash(const char *s, int n)
{
uint h;
int i;
uchar *p;
for (h=i=0,p=(uchar *)s; (i<n) && (*p); p++, i++)
h = 31 * h + *p;
return (h % MAX_FIELDS);
}
inline BOOL Dbf::insert_field_hashnode(FIELD_HASHNODE *pnode)
{
int index;
FIELD_HASHNODE *ptmp, *p;
index = shash(dbf_handle->field_list[pnode->index]->field_rec.field_name, 11);
ptmp = dbf_handle->field_hashnode[index];
if(ptmp)
{
p = ptmp;
while(p)
{
if(strnicmp(dbf_handle->field_list[pnode->index]->field_rec.field_name,
dbf_handle->field_list[p->index]->field_rec.field_name, 11)==0)
return FALSE;
p = p->next;
}
pnode->next = ptmp;
dbf_handle->field_hashnode[index] = pnode;
}
else
{
dbf_handle->field_hashnode[index] = pnode;
pnode->next = NULL;
}
return TRUE;
}
FIELD_LIST * Dbf::look_field(const char *field_name)
{
char fname[12];
int index;
FIELD_HASHNODE *pnode;
FIELD_LIST *plist;
strncpy(fname, field_name, sizeof(fname));
fname[sizeof(fname)-1] = 0;
strupr(fname);
index = shash(fname, sizeof(fname)); //field_name, strlen(field_name));
pnode = dbf_handle->field_hashnode[index];
if(pnode==NULL) return NULL;
while(pnode)
{
plist = dbf_handle->field_list[pnode->index];
if(strnicmp(plist->field_rec.field_name,field_name,11)==0)
return plist;
pnode = pnode->next;
}
return NULL;
}
/******************************************************************************/
Dbf::Dbf( void )
{
dbf_handle = NULL;
lock = 0;
open_way = RDWR;
}
Dbf::~Dbf()
{
if( (dbf_handle != NULL ) && (dbf_handle->handle != -1) )
{
Close() ;
}
}
int Dbf::read_dbfhead( void )
{
int start = 1;
FIELD_REC field_rec;
FIELD_HASHNODE *field_node;
FIELD_LIST * flist_ptr;
if ( (dbf_handle == NULL ) || (dbf_handle->handle==-1) )
return -1 ;
if( read( dbf_handle->handle, (char *)(&dbf_handle->dbf_head),sizeof(DBF_HEAD))!= sizeof(DBF_HEAD))
return -1 ;
dbf_handle->field_num = 0;
for(;;)
{
//文件终止。
if( read(dbf_handle->handle, (char *)&field_rec, sizeof(FIELD_REC)) != sizeof(FIELD_REC))
break;
if(field_rec.field_name[0] == 0x0d) //字段结束
break;
flist_ptr = new FIELD_LIST ;
field_node = new FIELD_HASHNODE;
if ((flist_ptr == NULL) || (field_node==NULL))
{
printf("Error allocate memory.\n");
return -1;
}
flist_ptr->m_start = start;
flist_ptr->cname = NULL;
memcpy( (char *)&flist_ptr->field_rec, (char *)&field_rec, sizeof(FIELD_REC));
start += FieldLen(flist_ptr);
dbf_handle->field_list[dbf_handle->field_num] = flist_ptr;
field_node->index = dbf_handle->field_num;
field_node->next = NULL;
if(insert_field_hashnode(field_node)==FALSE)
{//存在重复的字段。
delete field_node;
delete flist_ptr;
dbf_handle->field_list[dbf_handle->field_num] = NULL;
continue;
}
dbf_handle->field_num ++;
if(dbf_handle->field_num==MAX_FIELDS)
break;
}
return 1;
}
BOOL Dbf::Open(const char * filename,char openway)
{
int strLen1 ;
if( dbf_handle != NULL)
Close();
dbf_handle = new DBF_HANDLE ;
if ( !dbf_handle )
return FALSE;
memset(dbf_handle, 0, sizeof(DBF_HANDLE));
dbf_handle->curr_rec = 1L ;
open_way = openway;
if( open_way == RDONLY )
dbf_handle->handle = open( filename, O_RDONLY | O_BINARY, S_IREAD );
// dbf_handle->handle = _sopen( filename, _O_RDONLY | _O_BINARY, _SH_DENYNO, _S_IREAD );
else
dbf_handle->handle = open( filename, O_RDWR | O_BINARY, S_IREAD | S_IWRITE );
// dbf_handle->handle = _sopen( filename, _O_RDWR | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE );
if (dbf_handle->handle == -1)
goto error;
if (read_dbfhead() == -1)
goto error2;
dbf_handle->record_buf = new char[dbf_handle->dbf_head.rec_size];
if ( dbf_handle->record_buf == NULL )
goto error2;
strLen1 = strlen( filename );
dbf_handle->file_name = new char [ strLen1 + 1 ];
if(dbf_handle->file_name == NULL)
goto error2;
strcpy(dbf_handle->file_name, filename);
return TRUE;
error2:
close(dbf_handle->handle);
error:
delete dbf_handle;
dbf_handle = NULL ;
return FALSE ;
}
void Dbf::Close( void )
{
FIELD_HASHNODE *pnode, *p;
FIELD_LIST *plist;
if( dbf_handle == NULL)
return ;
if(dbf_handle->handle != -1)
{
close(dbf_handle->handle);
dbf_handle->handle = -1;
}
for(int i=0;i<MAX_FIELDS;i++)
{
plist = dbf_handle->field_list[i];
if(plist)
{
if(plist->cname)
delete plist->cname;
delete plist;
}
pnode = dbf_handle->field_hashnode [i];
while(pnode)
{
p = pnode;
pnode = pnode->next;
delete p;
}
}
if(dbf_handle->record_buf)
delete dbf_handle->record_buf;
if(dbf_handle->file_name)
delete dbf_handle->file_name;
delete dbf_handle;
dbf_handle = NULL ;
}
BOOL Dbf::Create(const char * file_name, FIELD_REC * field)
{
int fd, i;
char ch[2];
DBF_HEAD * phead = new DBF_HEAD;
memset( phead, 0, sizeof( DBF_HEAD ));
phead->dbf_id = 3;
_SetDosDate(phead);
phead->last_rec = 0L;
phead->data_offset = 33;
phead->rec_size = 1;
for(i=0; (strlen( ( field + i )->field_name) != 0) ; i++)
{
strupr( ( field + i )->field_name);
if ( ( field + i )->field_type != 'N')
phead->rec_size += (ushort)( field + i )->linfo.wlen;
else
phead->rec_size += (ushort)( field + i )->linfo.N.len;
phead->data_offset += 32;
}
if ((fd = open(file_name, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE)) == -1)
{
delete phead ;
return FALSE ;
}
write(fd, phead, 32);
for(i=0; (strlen( ( field + i )->field_name) != 0); i++)
{
write(fd, (field + i ), sizeof( FIELD_REC ) );
}
ch[0] = 0x0d; ch[1] = 0x1a;
write(fd, ch, 2);
close(fd);
delete phead;
return ( Open( file_name ) );
}
BOOL Dbf::Zap( void )
{
DBF_HEAD * phead;
FIELD_REC * pfield;
FIELD_LIST * plist;
int i, fd;
char ch[2];
if(dbf_handle == NULL || dbf_handle->handle == -1)
return FALSE;
phead = &(dbf_handle->dbf_head);
_SetDosDate(phead);
phead->last_rec = 0L;
dbf_handle->curr_rec = 1L ;
close(dbf_handle->handle);
dbf_handle->handle = -1;
if ((fd = open(dbf_handle->file_name, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE)) == -1)
{// zap fail
return FALSE ;
}
write(fd, (char *)phead, 32);
for(i=0;i<MAX_FIELDS;i++)
{
plist = dbf_handle->field_list[i];
if(plist == NULL) break;
pfield = &(plist->field_rec);
write(fd, (char *)(pfield), 32);
}
ch[0] = 0x0d; ch[1] = 0x1a;
write(fd, ch, 2);
dbf_handle->handle = fd;
return TRUE ;
}
//cursor move function(s)
BOOL Dbf::Move(long rec_num)
{
size_t size;
if( dbf_handle == NULL || dbf_handle->handle == -1)
return ( FALSE ) ;
if(rec_num > ReadRecordCount())
rec_num = ReadRecordCount();
if(rec_num < 1)
rec_num = 1;
char * record_buf = dbf_handle->record_buf ;
if(lock)
{
if ( lock_dbf_rec( rec_num, 1 ) != TRUE )
return FALSE;
}
if ( lseek ( dbf_handle->handle, (long) dbf_handle->dbf_head.data_offset +
(long)(dbf_handle->dbf_head.rec_size) * ( rec_num -1 ), SEEK_SET) == -1)
goto error;
if ( ( size = read(dbf_handle->handle, record_buf,dbf_handle->dbf_head.rec_size) )
< (size_t)(dbf_handle->dbf_head.rec_size) )
goto error;
if(lock) unlock_dbf_rec(rec_num,1);
dbf_handle->curr_rec = rec_num ;
return TRUE;
error:
if(lock) unlock_dbf_rec( rec_num, 1);
return FALSE;
}
BOOL Dbf::MoveNext( long rec_num )
{
if( dbf_handle == NULL || dbf_handle->handle == -1)
return FALSE;
return ( Move( dbf_handle->curr_rec + rec_num ) ) ;
}
BOOL Dbf::MoveFirst( void )
{
return ( Move( 1l ) ) ;
}
BOOL Dbf::MoveLast( void )
{
return (Move(ReadRecordCount())) ;
}
long Dbf::RecNo( void )
{
if( dbf_handle == NULL || dbf_handle->handle == -1)
return 0;
return (GetRecordCount()<1) ? 0L : (dbf_handle->curr_rec) ;
}
long Dbf::GetRecordCount( void )
{
if (dbf_handle ==NULL || dbf_handle->handle == -1 )
return -1L;
return dbf_handle->dbf_head.last_rec;
}
long Dbf::ReadRecordCount( void )
{
if (dbf_handle == NULL || dbf_handle->handle == -1 )
return -1L;
lseek(dbf_handle->handle, 4L, SEEK_SET);
read(dbf_handle->handle, &(dbf_handle->dbf_head.last_rec),
sizeof(dbf_handle->dbf_head.last_rec) );
return ( dbf_handle->dbf_head.last_rec ) ;
}
void Dbf::ClearRecBuf( void )
{
if( dbf_handle == NULL || dbf_handle->handle == -1 )
return ;
char * record_buf = dbf_handle->record_buf ;
memset( record_buf , 0, dbf_handle->dbf_head.rec_size);
}
////
BOOL Dbf::Delete( long rec_num )
{
if( dbf_handle == NULL || dbf_handle->handle == -1 )
return ( FALSE ) ;
if( rec_num == 0L ) rec_num = dbf_handle->curr_rec ;
if (rec_num < 1 || rec_num > dbf_handle->dbf_head.last_rec)
return FALSE ;
dbf_handle->record_buf[ 0 ] = '*';
return _Update(rec_num, 1);
}
BOOL Dbf::IsDelete ( void )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -