Category : C++ Source Code
Archive   : TPXCLA.ZIP
Filename : TPXCLASS.CPP

 
Output of file : TPXCLASS.CPP contained in archive : TPXCLA.ZIP


// tpxclass.cpp
//--------------------------------------------------------------------------
// TPXCLASS.CPP & TPXCLASS.HPP are the sole proporty of
// Masterson Johnston, Inc. Feel free to modify and use this code in any
// way, but remember, though we wrote it, we are not responsibile for it's
// actions nor yours if anything goes wrong.
//
//--------------------------------------------------------------------------
#include "tpxclass.hpp"
//----------------------------------------------------------------------------

/*
Clear totals.
*/

PX_Table :: PX_Table()
{
field_count=0;
index_count=0;
secondary_index_count=0;
current_field_count=0;
current_index_count=0;
current_secondary_index_count=0;
memset(table_path,0,80);
}

//----------------------------------------------------------------------------

/*
get the address of the data buffer to be associated with this object.
This is the address of a C struct which will hold 1 record from the DB file.
Note that char strings will have 1 more byte than length
specified in the DB definition to account for NULL.
PDX "A10" field will be moved into a C char str[11] field.
*/

void PX_Table :: set_data_buf(char *dbuf)
{
data_buf=dbuf; // get pointer to the C structure in which to load a record
}

//----------------------------------------------------------------------------

/*
Set master path, usually a subdir where the program file resides
*/

void PX_Table :: set_path(char *dpath)
{
strcpy(table_path,dpath); // path to the program files. see below for details
}

//----------------------------------------------------------------------------

/*
Set file name to be associated with this object. For historical reasons
this routine was held seperate from the above function. The DB files
are expected to be in the DATA subdor off of table_path,
*/

void PX_Table :: set_name(char *fname)
{
strcat(table_path,"DATA\\");
strncat(table_path,fname,8);
}

//----------------------------------------------------------------------------

/*
This routine allocates the correct # of field & index pointers needed to
create the **list used by PXAPI to create files and indexes. It is a prime
candidate for recoding with operator overloading along with the associated
add_field & add_secondary_index functions. Note that there is no
add_primary_index function, since promary keys start at field 1 and are
icount in length. The create_data_file automatically creates the primary
index when called.
*/

int PX_Table :: init_descriptors(char fcount, char icount, char sicount)
{
register a;

field_count=0;
index_count=0;
secondary_index_count=0;
current_field_count=0;
current_index_count=0;
current_secondary_index_count=0;

if(fcount>0){

(void *)field_name=malloc(fcount * sizeof(char *));
if(!(long)field_name)
return(-1);

(void *)field_type=malloc(fcount * sizeof(char *));
if(!(long)field_type){
free(field_name);
return(-1);
}

field_count=fcount;
current_field_count=0;

}

if(icount>0){

(void *)index_field_handles=malloc(icount * sizeof(FIELDHANDLE));
if(!(long)index_field_handles){
free_descriptors();
return(-1);
}

index_count=icount;

}

if(sicount>0){

(void *)secondary_index_field_handles=malloc(sicount * sizeof(FIELDHANDLE));
if(!(long)secondary_index_field_handles){
free_descriptors();
return(-1);
}

secondary_index_count=sicount;
current_secondary_index_count=0;

}

return(0);

}

//----------------------------------------------------------------------------

/*
Clean up when done with the descriptors. Note that the loop for free each
list member (descriptor) is limited by the current_xxx_xxx count so if an
error occurs during init_descriptor or add_xxx, a simple call to this
fuinction clears up the proper number of pointers.
*/

void PX_Table :: free_descriptors()
{
register a;

if(field_count){
for(a=0;a free(field_name[a]);
free(field_type[a]);
}
free(field_name);
free(field_type);
}

if(index_count){
free(index_field_handles);
index_count=0;
}

if(secondary_index_count){
free(secondary_index_field_handles);
secondary_index_count=0;
}

}

//----------------------------------------------------------------------------

/*
Add a field definition (descriptor) to the **list. Clip name if too long.
The *type is the "A10" or "S" component and the *name is the field name.
*/

void PX_Table :: add_field(char *type, char *name)
{
if(current_field_count if(strlen(name)>25)
name[24]=0;
field_name[current_field_count]=strdup(name);
field_type[current_field_count]=strdup(type);
current_field_count++;
}
}

//----------------------------------------------------------------------------

/*
Add a secondary index definition to file. fh is the field handle (number)
of the desired field to have an index.
*/

void PX_Table :: add_secondary_index(FIELDHANDLE fh)
{
if(current_secondary_index_count (FIELDHANDLE)secondary_index_field_handles[current_secondary_index_count]=fh;
current_secondary_index_count++;
}
}

//----------------------------------------------------------------------------

/*
Check the actual descriptior counts vs the initial counts and then make DB
file if they are equal. If there was a primary index count specified, load
that array and create that index. If secondary indexes were specified,
create each one then free all descriptors.
*/

int PX_Table :: init_data_file()
{
register a,b;
char temp[80];

if(field_count!=current_field_count){
free_descriptors();
return(-1);
}

if(secondary_index_count!=current_secondary_index_count){
free_descriptors();
return(-2);
}

b=PXTblCreate(table_path, field_count, field_name, field_type);

if(!b)
if(index_count){

for(a=current_index_count;a (FIELDHANDLE)index_field_handles[a]=a+1;

b=PXKeyAdd(table_path,index_count,index_field_handles,PRIMARY);

}

if(!b)
if(secondary_index_count)
for(a=0;a b=PXKeyAdd(table_path,(int)1,(FIELDHANDLE *)secondary_index_field_handles+a,INCSECONDARY);

free_descriptors();

return(b);

}

//----------------------------------------------------------------------------
/*
From here on down to TPXFile, the PXENG functions are C plus-ized, with
the common variables taken out of the passed args. Usually this involves
the table path, field counts and data buffers shared among all the functions
*/
//----------------------------------------------------------------------------

int PX_Table :: pxtbladd(char *tpath)
{
register b;
b=PXTblAdd(table_path,tpath);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblclose()
{
register b;
b=PXTblClose(table_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblcopy(char *tpath)
{
register b;
b=PXTblCopy(table_path, tpath);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtbldecrypt()
{
register b;
b=PXTblDecrypt(table_path);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtbldelete()
{
register b;
b=PXTblDelete(table_path);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblempty()
{
register b;
b=PXTblEmpty(table_path);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblencrypt(char *psw)
{
register b;
b=PXTblEncrypt(table_path, psw);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblexist(int *exist_flag)
{
register b;
b=PXTblExist(table_path, exist_flag);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblname(int buflen, char *buf)
{
register b;
b=PXTblName(table_handle, buflen, buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblnrecs()
{
register b;
b=PXTblNRecs(table_handle, &total_records);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblopen()
{
register b;
b=PXTblOpen(table_path,&table_handle,0,1);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblprotected(int *protect_flag)
{
register b;
b=PXTblProtected(table_path,protect_flag);
return(b);
}

//----------------------------------------------------------------------------

int PX_Table :: pxtblrename(char *tpath)
{
register b;
b=PXTblRename(table_path,tpath);
return(b);
}

//----------------------------------------------------------------------------

PX_File :: PX_File()
{
record_handle=0;
record_number=0;
field_handle=0;
lock_handle=0;
}

//----------------------------------------------------------------------------

int PX_File :: pxfldblank(int *blank_flag)
{
register b;
b=PXFldBlank(record_handle,field_handle,blank_flag);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxfldblank(char *field_name, int *blank_flag)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXFldBlank(record_handle,field_handle,blank_flag);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxfldhandle(char *field_name)
{
register b;
b=PXFldHandle(table_handle,field_name,&field_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxfldname(char *field_name)
{
register b;
b=PXFldName(table_handle,field_handle,24,field_name);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxfldtype(char *field_type)
{
register b;
b=PXFldType(table_handle,field_handle,4,field_type);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxfldtype(char *field_name, char *field_type)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXFldType(table_handle,field_handle,4,field_type);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetalpha(int buf_size, char *buf)
{
register b;
b=PXGetAlpha(record_handle,field_handle,buf_size,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetalpha(char *field_name, int buf_size, char *buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXGetAlpha(record_handle,field_handle,buf_size,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetdate(DATE *buf)
{
register b;
b=PXGetDate(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetdate(char *field_name, DATE *buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXGetDate(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetdouble(double *buf)
{
register b;
b=PXGetDoub(record_handle,field_handle,buf);
return(b);
}


//----------------------------------------------------------------------------

int PX_File :: pxgetdouble(char *field_name, double *buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXGetDoub(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetlong(long *buf)
{
register b;
b=PXGetLong(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetlong(char *field_name, long *buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXGetLong(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetshort(short *buf)
{
register b;
b=PXGetShort(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxgetshort(char *field_name, short *buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXGetShort(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxneterruser(char *user)
{
register b;
b=PXNetErrUser(47,user);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnetfilelock(int lock_type)
{
register b;
b=PXNetFileLock(table_path,lock_type);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnetfileunlock(int lock_type)
{
register b;
b=PXNetFileUnlock(table_path,lock_type);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnetreclock()
{
register b;
b=PXNetRecLock(table_handle,&lock_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnetrecunlock()
{
register b;
b=PXNetRecUnlock(table_handle,lock_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnetreclocked(int *lock_flag)
{
register b;
b=PXNetRecLocked(table_handle,lock_flag);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnetrecgotolock()
{
register b;
b=PXNetRecGotoLock(table_handle,lock_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnettblchanged(int *change_flag)
{
register b;
b=PXNetTblChanged(table_handle,change_flag);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnettbllock(int lock_type)
{
register b;
b=PXNetTblLock(table_handle,lock_type);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnettblunlock(int lock_type)
{
register b;
b=PXNetTblUnlock(table_handle,lock_type);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnettblrefresh()
{
register b;
b=PXNetTblRefresh(table_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxnetusername(char *buf)
{
register b;
b=PXNetUserName(47,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputalpha(char *buf)
{
register b;
b=PXPutAlpha(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputalpha(char *field_name, char *buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXPutAlpha(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputblank()
{
register b;
b=PXPutBlank(record_handle,field_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputblank(char *field_name)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXPutBlank(record_handle,field_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputdate(DATE buf)
{
register b;
b=PXPutDate(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputdate(char *field_name, DATE buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXPutDate(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputdouble(double buf)
{
register b;
b=PXPutDoub(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputdouble(char *field_name, double buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXPutDoub(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputlong(long buf)
{
register b;
b=PXPutLong(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputlong(char *field_name, long buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXPutLong(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputshort(short buf)
{
register b;
b=PXPutShort(record_handle,field_handle,buf);

return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxputshort(char *field_name, short buf)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXPutShort(record_handle,field_handle,buf);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecappend()
{
register b;
b=PXRecAppend(table_handle,record_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecbufclose()
{
register b;
b=PXRecBufClose(record_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecbufcopy(RECORDHANDLE rhandle)
{
register b;
b=PXRecBufCopy(record_handle,rhandle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecbufempty()
{
register b;
b=PXRecBufEmpty(record_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecbufopen()
{
register b;
b=PXRecBufOpen(table_handle,&record_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecdelete()
{
register b;
b=PXRecDelete(table_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecfirst()
{
register b;
b=PXRecFirst(table_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecget()
{
register b;
b=PXRecGet(table_handle,record_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecgoto(RECORDNUMBER rnum)
{
register b;
b=PXRecGoto(table_handle,rnum);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecinsert()
{
register b;
b=PXRecInsert(table_handle,record_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxreclast()
{
register b;
b=PXRecLast(table_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecnext()
{
register b;
b=PXRecNext(table_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecnflds()
{
register b;
b=PXRecNFlds(table_handle,(int *)&total_fields);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecnum()
{
register b;
b=PXRecNum(table_handle,&record_number);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecprev()
{
register b;
b=PXRecPrev(table_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxrecupdate()
{
register b;
b=PXRecUpdate(table_handle,record_handle);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxsrchfld(int mode)
{
register b;
b=PXSrchFld(table_handle,record_handle,field_handle,mode);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxsrchfld(char *field_name, int mode)
{
register b;
b=pxfldhandle(field_name);
if(!b)
b=PXSrchFld(table_handle,record_handle,field_handle,mode);
return(b);
}

//----------------------------------------------------------------------------

int PX_File :: pxsrchkey(int num_key_fields, int mode)
{
register b;
b=PXSrchKey(table_handle,record_handle,num_key_fields,mode);
return(b);
}

//----------------------------------------------------------------------------
/*
Here's wher the fun begins, all the above wrapper code is designed to make
these functions work smoothly. Managing expected errors (exceptions) as
well as unexpected errors, searching for records, loading them into C
structs (data_buf) without explicit coding and other useful functions
are all here.
*/
//----------------------------------------------------------------------------

/*
Clear the exception list.
*/

TPXFile :: TPXFile()
{
exception_list=NULL;
}

//----------------------------------------------------------------------------

/*
Get a list of expected errors (exceptions) for use later. This is a simple
NULL terminated list int elist[]={PXERR_RECNOTFOUND,NULL};
*/

int TPXFile :: add_exceptions(int *list)
{
register a;

if(!(long)list)
return(0);

for(a=0;list[a];a++);
a++;

(void *)exception_list=malloc(a);
if(!(long)exception_list)
return(-1);

for(a=0;list[a];a++)
exception_list[a]=list[a];

exception_list[a]=0;

return(0);

}

//----------------------------------------------------------------------------

/*
In an error has occured during a PXENG call, check the supplied elist,
if a list was given, for a matching entry to the actual error (code). If
the error was in the exception list, return a positive value of its numeric
position in the list, otherwise return a -1 after printing the error. This is
kept primitve intentionally in this code to allow other authors to handle
errors in their own manner.
*/

int TPXFile :: check_exceptions(int code)
{
register a;
char found=0;

if(!code){
free_exceptions();
return(0);
}

if((long)exception_list){

for(a=0;exception_list[a];a++)
if((int)exception_list[a]==code){
found=1;
break;
}

free_exceptions();

}

if(found)
return(a+1);

printf("\n%s\n",PXErrMsg(code));

return(-1);

}

//----------------------------------------------------------------------------

/*
Free the list when the operation is through
*/

void TPXFile :: free_exceptions()
{
if((long)exception_list){
free(exception_list);
exception_list=NULL;
}
}

//----------------------------------------------------------------------------

/*
When opening a table, open all associated indexes, assign a rec buffer,
get the number of records and number of fields in each record. This is
very handy information to have.
*/

int TPXFile :: OpenTable()
{
register b;

b=pxtblopen();
if(b)
return(b);

b=pxrecbufopen();
if(b)
return(b);

b=pxtblnrecs();
if(b)
return(b);

b=pxrecnflds();
if(b)
return(b);

return(0);
}

//-----------------------------------------------------------------------------

/*
Was this really necessary?
*/

int TPXFile :: CloseTable()
{
register b;

b=pxtblclose();

return(b);

}

//-----------------------------------------------------------------------------

/*
This simple routine shows the power inherent in this class. The abilty to
get a record, load its (current) record #, then load that record into
the data_buf (C struct).
*/

int TPXFile :: GetFirstRecord()
{
register b;

b=pxrecfirst();
if(b)
return(b);

b=pxrecget();
if(b)
return(b);

b=pxrecnum();
if(b)
return(b);

b=get_field_values();
if(b)
return(b);

return(0);

}

//----------------------------------------------------------------------------

/*
Step through the file
*/

int TPXFile :: GetNextRecord()
{
register b;

b=pxrecnext();
if(b)
return(b);

b=pxrecget();
if(b)
return(b);

b=pxrecnum();
if(b)
return(b);

b=get_field_values();
if(b)
return(b);

return(0);

}

//----------------------------------------------------------------------------

/*
Searching for a record combines alot of the techniques above with the abilty
differentiate between a SEARCHFIRST, which loads the specified key fields into
the record buf so that the proper index is used and to selectively load the
matching records into the data_buf. The later is good for data validation
without overlaying the data in the data_buf, but rather checking the exception
code returned by the function.
start_field is the statging index field to be used in the search.
num_key_fields is the count, use 1 if using a secondary index.
elist is the exception list.
mode is SEARCHFIRST, SEARCHCLOSEST or SEARCHNEXT
load_flag is LOAD_RECORDS or NO_LOAD_RECORDS depending on if you want to
overlay the data in the data_buf.
*/

int TPXFile :: SearchRecord(char *fname, int num_key_fields, int *elist, int mode, char load_flag)
{
register field_num, b;

b=add_exceptions(elist);
if(b)
return(b);

b=pxfldhandle(fname);
if(b){
free_exceptions();
return(b);
}

if(mode!=SEARCHNEXT){

b=put_field_values(field_handle,num_key_fields);
if(b){
free_exceptions();
return(b);
}
}

b=pxsrchkey(num_key_fields,mode);
if(mode!=CLOSESTRECORD)
if(b!=PXERR_RECNOTFOUND){
b=check_exceptions(b);
if(b){
free_exceptions();
return(b);
}
}

if(load_flag==NO_LOAD_RECORDS){
free_exceptions();
return(0);
}

b=pxrecget();
if(b){
free_exceptions();
return(b);
}

b=pxrecnum();
if(b){
free_exceptions();
return(b);
}

b=get_field_values();
if(b){
free_exceptions();
return(b);
}

return(0);

}

//----------------------------------------------------------------------------

/*
What good is a file engine that cannot search for the last matching record?
This function takes a subset of the SearchRecord args, since it can supply
most of them itsself
*/

int TPXFile :: SearchLastRecord(char *fname, int num_key_fields, char load_flag)
{
register b;
int list[]={PXERR_RECNOTFOUND,PXERR_TABLEEMPTY,NULL};

b=SearchRecord(fname,num_key_fields,list,SEARCHFIRST,NO_LOAD_RECORDS);
if(b)
return(b);

for(;;){
b=pxsrchkey(num_key_fields,SEARCHNEXT);
if(b)
break;
}

if(b!=PXERR_RECNOTFOUND)
return(b);

b=pxrecnum();
if(b)
return(b);

if(load_flag==NO_LOAD_RECORDS)
return(0);

b=pxrecget();
if(b)
return(b);

b=get_field_values();
if(b)
return(b);

return(0);
}

//----------------------------------------------------------------------------

/*
Kind of like SearchRecord, but it uses no indexes. Insted you pass the
name of the field you want to search on, the exception_list, a valid mode
and a load flag, then wait...
*/

int TPXFile :: FindRecord(char *fname, int *elist, int mode, char load_flag)
{
register b;

b=add_exceptions(elist);
if(b)
return(b);

b=pxfldhandle(fname);
if(b){
free_exceptions();
return(b);
}

if(mode!=SEARCHNEXT){

b=put_field_values(field_handle,1);
if(b){
free_exceptions();
return(b);
}
}

b=pxsrchfld(mode);
if(mode!=CLOSESTRECORD)
if(b!=PXERR_RECNOTFOUND){
b=check_exceptions(b);
if(b){
free_exceptions();
return(b);
}
}

b=pxrecnum();
if(b){
free_exceptions();
return(b);
}

if(load_flag==NO_LOAD_RECORDS){
free_exceptions();
return(0);
}

b=pxrecget();
if(b){
free_exceptions();
return(b);
}

b=pxrecnum();
if(b){
free_exceptions();
return(b);
}

b=get_field_values();
if(b){
free_exceptions();
return(b);
}

return(0);

}

//----------------------------------------------------------------------------

/*
Like SearchLastRecord, but alot slower since it uses no index.
*/

int TPXFile :: FindLastRecord(char *fname, char load_flag)
{
register b;
int list[]={PXERR_RECNOTFOUND,PXERR_TABLEEMPTY,NULL};

b=FindRecord(fname,list,SEARCHFIRST,NO_LOAD_RECORDS);
if(b)
return(b);

for(;;){
b=pxsrchfld(fname,SEARCHNEXT);
if(b)
break;
}

if(b!=PXERR_RECNOTFOUND)
return(b);

b=pxrecnum();
if(b)
return(b);

if(load_flag==NO_LOAD_RECORDS)
return(0);

b=pxrecget();
if(b)
return(b);

b=get_field_values();
if(b)
return(b);

return(0);
}

//----------------------------------------------------------------------------

/*
Once you have loacted a record you can put the new values in the data_buf,
your C struct, and call this func to write the new data.
*/

int TPXFile :: UpdateRecord()
{
register b;

b=put_field_values(1,0);
if(b)
return(b);

b=pxrecupdate();
if(b)
return(b);

return(0);

}

//----------------------------------------------------------------------------

/*
Put the data into the data_bus, your C struct, and call this function.
*/

int TPXFile :: InsertRecord()
{
register b;

b=put_field_values(1,0);
if(b)
return(b);

b=pxrecinsert();
if(b)
return(b);

b=pxrecnum();
if(b)
return(b);

return(0);

}

//----------------------------------------------------------------------------

/*
This is the driver for the automated functions used in this class. You
pass this function the starting field # to be moved from the data_buf
into the record buf and the number of fields from that point to follow.
If nmu_fields is 0, then all fields will be moved from the data_buf,
your C struct, into the PXAPI record buf.
*/

int TPXFile :: put_field_values(int start_field, int num_fields)
{
register a,b;
int temp;

if(!num_fields)
num_fields=total_fields;

for(a=1;a b=put_field_value(a-1,'N');
if(b)
return(b);
}

for(;a b=put_field_value(a-1,'Y');
if(b)
return(b);
}

return(0);

}

//----------------------------------------------------------------------------

/*
This private function actually parses the field type and decides how to
move the data from C structure to paradox record buffer, then updates
internal pointers to the data_buf for the next read. The load flag is
set to 'N' when the starting field is not the 1st field in the data_buf,
and thusly the internal pointers need to be advanced to the proper point.
The reason I mention this, is that this method cuold probably be rewritten
to work alot better if I had time to think about it. Maybe you do...
*/

int TPXFile :: put_field_value(int field_number, char load_flag)
{
register a,b;
char field_type[6];
int month, day, year;
DATE date;
short *sptr;
double dval,
*dptr;
static int data_buf_offset;

if(!field_number)
data_buf_offset=0;

field_handle=field_number+1;

b=pxfldtype(field_type);
if(b)
return(b);

a=field_type[0];

b=0;
switch(a){
case 'A':
a=atoi(field_type+1);
if(!a)
return(-1);
if(load_flag=='Y')
b=pxputalpha((char *)data_buf+data_buf_offset);
data_buf_offset+=(a+1);
break;
case 'D':
disassemble_date((char *)data_buf+data_buf_offset, &month, &day, &year);
PXDateEncode(month, day, year, &date);
if(load_flag=='Y')
b=pxputdate(date);
data_buf_offset+=9;
break;
case 'N':
case '$':
dptr=(double *)(data_buf+data_buf_offset);
if(load_flag=='Y')
b=pxputdouble(*dptr);
data_buf_offset+=8;
break;
case 'S':
sptr=(short *)data_buf+data_buf_offset;
if(load_flag=='Y')
b=pxputshort(*sptr);
data_buf_offset+=2;
break;
}

return(b);

}

//----------------------------------------------------------------------------

/*
The reverse driver of the put functions
*/

int TPXFile :: get_field_values()
{
register a,b;
int num_fields;

for(a=0;a b=get_field_value(a);
if(b)
return(b);
}

return(0);

}

//----------------------------------------------------------------------------

/*
The reverse private function od the put function
*/

int TPXFile :: get_field_value(int field_number)
{
register a,b;
char temp[80],
field_type[6];
int month, day, year;
double *dptr;
DATE date;
static int data_buf_offset;

if(!field_number)
data_buf_offset=0;

field_handle=field_number+1;

b=pxfldtype(field_type);
if(b)
return(b);

a=field_type[0];

switch(a){
case 'A':
a=atoi(field_type+1);
if(!a)
return(-1);
b=pxgetalpha(a+1,temp);
setstrsz(temp,a);
strcpy((char *)data_buf+data_buf_offset,temp);
data_buf_offset+=(a+1);
break;
case 'D':
b=pxgetdate(&date);
b=PXDateDecode(date, &month, &day, &year);
reassemble_date((char *)data_buf+data_buf_offset, month, day, year);
data_buf_offset+=9;
break;
case 'N':
case '$':
dptr=(double *)(data_buf+data_buf_offset);
b=pxgetdouble((double *)dptr);
data_buf_offset+=8;
break;
case 'S':
b=pxgetshort((short *)data_buf+data_buf_offset);
data_buf_offset+=2;
break;
}

return(b);

}

//----------------------------------------------------------------------------

/*
Just point to a valid record and call this function.
*/

int TPXFile :: DeleteRecord()
{
register b;

b=pxrecdelete();
if(b)
return(b);

b=pxrecnum();
if(b)
return(b);

b=get_field_values();
if(b)
return(b);

return(0);

}

//----------------------------------------------------------------------------

/*
Ok, this may or may not work. The idea is to delete all matching records
based on a given key and its value. Nice in theory, easy to implement in
this code. Haven't had the chance to test it out..
*/

int TPXFile :: DeleteAllRecord(char *fname, int num_key_fields)
{
register b;
int list[]={PXERR_ENDOFTABLE,NULL};

for(;;){

b=pxrecdelete();
if(b)
return(b);

SearchRecord(fname,num_key_fields,list,SEARCHNEXT,NO_LOAD_RECORDS);
if(b)
break;

}

b=pxrecnum();
if(b)
return(b);

b=get_field_values();
if(b)
return(b);

return(0);

}

//----------------------------------------------------------------------------

/*
A quick function to get numeric vaues from a texttual date mm/dd/yyyy
*/

void TPXFile :: disassemble_date(char *buf, int *month, int *day, int *year)
{
char date[12];

memset(date,0,12);

strncpy(date,buf,2);
strncpy(date+3,buf+2,2);
strncpy(date+6,buf+4,2);
strncpy(date+9,buf+6,2);

*month=atoi(date);
*day=atoi(date+3);
*year=100*atoi(date+6);
*year+=atoi(date+9);

}

//-----------------------------------------------------------------------------

/*
And put it back together again, wee..
*/

void TPXFile :: reassemble_date(char *buf, int month, int day, int year)
{
sprintf(buf,"%2d/%2d/%2d",month,day,year);
}

//-----------------------------------------------------------------------------

/*
There must be 100 better/faster ways to code this string padding routine,
but I'm not gonna do it..
*/

void TPXFile :: setstrsz(char *buf, int size)
{
register b;

for(b=0;buf[b];b++);

if(b for(;b buf[b]=' ';

buf[size]=0;

}

//-----------------------------------------------------------------------------