home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-09-10 | 34.4 KB | 1,278 lines |
- Xref: sparky comp.lang.c:13461 comp.lang.c++:13475
- Newsgroups: comp.lang.c,comp.lang.c++
- Path: sparky!uunet!mnemosyne.cs.du.edu!arrakis!thor
- From: thor@arrakis.denver.co.us (Robert B. Hood)
- Subject: cBASE - Part 1
- Message-ID: <1992Sep10.134151.8451@arrakis.denver.co.us>
- Summary: A dBASE III+ Class in C++
- Reply-To: thor@arrakis.denver.co.us
- Organization: Bob's Programming Paradise, Lakewood, CO, USA
- Date: Thu, 10 Sep 1992 13:41:51 GMT
- Lines: 1265
-
- I have received over 20 `me too's in two days, so I guess that
- warrants a post. Here is the C++ class to access and modify
- dBASE III+ .DBF files. It is still under construction (doesn't
- do indexing or currently handle memo fields), but it is a start.
-
- I will also include two test programs (sans databases) that actually
- use the class. This article contains CBASE.CPP, and subsequent
- posts will contains the header file and test programs.
-
- Enjoy!
-
- ------------------------- CBASE.CPP -----------------------------
- // cBASE - A dBASE III+ class for accessing and manipulating .DBF files.
- // Copyright (C) 1992 Bob Hood
- //
- // Author : Bob Hood (thor@arrakis.denver.co.us)
- // Last Update : 08.01.92
- // Header Files: cBASE.HPP
- // Comments : Class is still under construction, so use at your own risk.
- //
- // You are free to copy and distribute this code as long as
- // you do not charge a fee for it, and the Copyright notice
- // above remains intact.
-
- // -- `To Do' list --
- // 1. lock database header area when updating
- // 2. deal with memo fields
- // 3. implement a linked-list quick sort routine (for indexing)
- // 4. create generic area locking routine by locking (record number +
- // 1,000,000 or so). This is how the big boys (Clipper, dBASE, etc.)
- // allow you to view a record even though another user has it locked!
-
- #include <stdio.h>
- #include <iostream.h>
- #include <conio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <io.h>
- #include <alloc.h>
- #include <string.h>
- #include <mem.h>
- #include <dos.h>
-
- #include "cbase.hpp"
-
- #define DB_LOCK 0x00
- #define DB_UNLOCK 0x01
-
- //---------------------------------------------------------------------------
- // constructor...
- //---------------------------------------------------------------------------
- dBASE::dBASE()
- {
- data.db_name[0] = '\0';
- data.database = -1;
-
- data.field_rec = NULL;
- data.record_hold = NULL;
- data.index.index_chain = NULL;
- data.relation_list = NULL;
- data.field_data = NULL;
-
- db_err = NO_PROBLEM;
- net_err = NO_PROBLEM;
- }
-
- //---------------------------------------------------------------------------
- int dBASE::activate(char *db_name,char *alias)
- {
- if(data.database != -1) return(ALREADY_OPEN_ERROR);
-
- data.database = open(db_name,O_RDWR|O_BINARY);
-
- if(data.database != -1)
- {
- strcpy(data.db_name,db_name);
- strcpy(data.alias,alias);
-
- eof_met = FALSE;
- bof_met = FALSE;
- update = FALSE;
- file_locked = FALSE;
- record_locked = FALSE;
- }
- else
- return(DOS_OPEN_ERROR);
-
- return(getStructure());
- }
-
- //---------------------------------------------------------------------------
- int dBASE::deactivate(void)
- {
- INDEX_CHAIN *hold1,*hold2;
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- // flush any changed data contained in the record buffer...
-
- if(update)
- {
- if(record_locked || file_locked)
- {
- f2b(); // return the linked list to a stream
- writeRecord(); // and put the data back in the file
- if(record_locked) rUnLock();
- }
- else
- cout << "ERROR: Record #" << currRecord() << " not locked -- cannot update";
- }
-
- // ...and shut that puppy down!
-
- if(file_locked) fUnLock();
-
- close(data.database);
-
- if(data.field_rec != NULL) free(data.field_rec);
- if(data.record_hold != NULL) free(data.record_hold);
- if(data.index.index_chain != NULL) killIndex();
- if(data.relation_list != NULL) free(data.relation_list);
-
- data.db_name[0] = '\0';
- data.alias[0] = '\0';
- data.database = -1;
- data.field_rec = NULL;
- data.record_hold = NULL;
- data.relation_list = NULL;
-
- eof_met = FALSE;
- bof_met = FALSE;
- update = FALSE;
- file_locked = FALSE;
- record_locked = FALSE;
-
- db_err = NO_PROBLEM;
-
- return(db_err);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::getStructure(void)
- {
- int x,y;
- int num_fields;
- int more_fields;
- long rec_pos;
- FIELD_REC hold_field;
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- lseek(data.database,0L,SEEK_END); // jump to the end..
- dbSize = tell(data.database); // see how long this file is...
-
- lseek(data.database,0L,SEEK_SET); // rewind the file
-
- x = read(data.database,(char *)&data.dbf_head,sizeof(DBF_HEAD));
-
- if(x != sizeof(DBF_HEAD)) return(DOS_READ_ERROR);
-
- rec_pos = tell(data.database); // position of the start of the field list
- data.field_list_offset = rec_pos;
- num_fields = 0;
-
- for(x = 0,y = 0;x < 2;x++) // two passes
- {
- lseek(data.database,rec_pos,SEEK_SET); // move to start of field list
-
- more_fields = TRUE;
- while(more_fields)
- {
- more_fields = (read(data.database,(char *)&hold_field,sizeof(FIELD_REC)) == sizeof(FIELD_REC));
-
- if(more_fields) more_fields = (hold_field.field_name[0] != 0x0D);
- if(more_fields)
- {
- if(x == 1)
- {
- memmove((void *)&data.field_rec[y],(void *)&hold_field,
- sizeof(FIELD_REC));
- ++y;
- }
- else
- ++num_fields;
- }
- }
-
- if(x == 0) // first pass, create an array large enough to hold list
- {
- data.num_fields = num_fields;
- data.field_rec = (FIELD_REC *)calloc(num_fields,sizeof(FIELD_REC));
- }
- }
-
- // the record pointer should be positioned @ the first data record in this
- // database. save it in the area structure
-
- data.data_records_offset = tell(data.database);
- data.current_record = 1L;
-
- data.record_hold = (void *)malloc(data.dbf_head.rec_size);
-
- // position the record pointer @ the first record, and read it into
- // the 'record_hold' area...
-
- gotoRecord(data.current_record);
-
- return(NO_PROBLEM);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::gotoRecord(LONG rec_number,int lockIt)
- {
- int x,y;
- int num_fields;
- int more_fields;
- LONG rec_pos;
-
- // see if there is a database currently open in this area
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- // do we have data sitting in the `data.record_hold' buffer?
-
- if(update)
- {
- if(!record_locked) return(RECORD_NOT_LOCKED_ERROR);
-
- f2b(); // return the linked list to a stream
- writeRecord(); // and put the data back in the file
- }
-
- x = NO_PROBLEM;
-
- if(record_locked && !file_locked) rUnLock(); // unlock the record
-
- // see if the requested record number is greater than those contained
- // in the database file...
-
- if(rec_number > data.dbf_head.last_rec) return(INVALID_RECORD_ERROR);
-
- // position the file pointer at the first record in the database
-
- lseek(data.database,(long)data.dbf_head.data_offset,SEEK_SET);
-
- // calculate the records offset from here...
-
- rec_pos = (rec_number - 1) * data.dbf_head.rec_size;
-
- // now position to that record
-
- lseek(data.database,rec_pos,SEEK_CUR);
-
- // and update the area record pointer
-
- data.current_record = rec_number;
-
- if(lockIt && !file_locked)
- {
- if(!rLock()) x = db_err;
- }
-
- // read the current record into 'record_hold' for this area
-
- read(data.database,data.record_hold,data.dbf_head.rec_size);
-
- // put us back to the start of this record in case we do a writeRecord()
-
- lseek(data.database,-data.dbf_head.rec_size,SEEK_CUR);
-
- // convert the stream of characters into a linked list of fields
-
- b2f(); // gets fields to linked list, and sets `update' to FALSE
-
- // make the new linked list publicly available
-
- field_list = data.field_data;
-
- return(x);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::goTop(void)
- {
- return(gotoRecord(1L));
- }
-
- //---------------------------------------------------------------------------
- int dBASE::goBottom(void)
- {
- return(gotoRecord(data.dbf_head.last_rec));
- }
-
- //---------------------------------------------------------------------------
- void *dBASE::getRecord(void)
- {
- // see if there is a database currently open in this area
-
- if(data.database == -1)
- {
- db_err = NO_DB_OPEN_ERROR;
- return(NULL);
- }
-
- // return a pointer to the data currently being held in `record_hold'
-
- return((void *)data.record_hold);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::getRecordLen(void)
- {
- // see if there is a database currently open in this area
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- // return the record len of the current database
-
- return(data.dbf_head.rec_size);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::writeRecord(void)
- {
- // write the current record in `record_hold' (was converted with `f2b()'
- // in `gotoRecord()' above
-
- write(data.database,data.record_hold,data.dbf_head.rec_size);
-
- // put us back to the start of this record
-
- lseek(data.database,-data.dbf_head.rec_size,SEEK_CUR);
-
- return(NO_PROBLEM);
- }
-
- //---------------------------------------------------------------------------
- LONG dBASE::lastRecord(void)
- {
- if(data.database == -1)
- {
- db_err = NO_DB_OPEN_ERROR;
- return(0L);
- }
-
- // return the record len of the current database
-
- return(data.dbf_head.last_rec);
- }
-
- //---------------------------------------------------------------------------
- LONG dBASE::currRecord(void)
- {
- if(data.database == -1)
- {
- db_err = NO_DB_OPEN_ERROR;
- return(0L);
- }
-
- // return the record len of the current database
-
- return(data.current_record);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::deleteRecord(void)
- {
- char *buff;
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- if(!record_locked) return(RECORD_NOT_LOCKED_ERROR);
-
- buff = (char *)getRecord();
- *buff = '*';
- data.deleted = TRUE;
-
- update = TRUE;
-
- return(NO_PROBLEM);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::recallRecord(void)
- {
- char *buff;
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- buff = (char *)getRecord();
- *buff = ' ';
- data.deleted = FALSE;
-
- update = TRUE;
-
- return(NO_PROBLEM);
- }
-
- //---------------------------------------------------------------------------
- void dBASE::listInfo(void)
- {
- int x;
-
- // see if there is a database currently open in this area
-
- if(data.database == -1) return;
-
- printf("\n*** Structure of database \"%s\"\n\n",data.db_name);
- printf("Last update %2d/%2d/%2d\n",
- data.dbf_head.last_update[1], // month
- data.dbf_head.last_update[2], // day
- data.dbf_head.last_update[0]); // year
- printf("Data offset %d\n",data.dbf_head.data_offset);
- printf("Record size %d\n",data.dbf_head.rec_size);
-
- printf("Number of records %lu\n\n",data.dbf_head.last_rec);
- printf("NAME TYPE LEN DEC\n\n");
-
- x = 0;
- while(x < data.num_fields)
- {
- switch(data.field_rec[x].field_type)
- {
- case 'N': printf("%-11s %-4c %3d %3d\n",
- data.field_rec[x].field_name,
- data.field_rec[x].field_type,
- data.field_rec[x].len_info.num_size.len,
- data.field_rec[x].len_info.num_size.dec);
- break;
-
- default: printf("%-11s %-4c %3d\n",
- data.field_rec[x].field_name,
- data.field_rec[x].field_type,
- data.field_rec[x].len_info.char_len);
- break;
- }
-
- ++x;
- }
- }
-
- //---------------------------------------------------------------------------
- void dBASE::grab(char *from, char *to, char *dest)
- {
- int x;
-
- x = 0;
- while(from <= to)
- {
- dest[x] = *from;
- ++from;
- ++x;
- }
- dest[x] = '\0';
- }
-
- //---------------------------------------------------------------------------
- char *dBASE::alias(void)
- {
- // see if there is a database currently open in this area
-
- if(data.database == -1)
- {
- db_err = NO_DB_OPEN_ERROR;
- return(NULL);
- }
-
- // return the record len of the current database
-
- return(data.alias);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::newRecord(int lockIt)
- {
- int x,y;
- long rec_pos;
- char *holdfield;
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- lseek(data.database,0L,SEEK_END); // go to bottom of file
-
- holdfield = (char *)malloc(data.dbf_head.rec_size);
-
- memset(holdfield,' ',data.dbf_head.rec_size);
-
- x = write(data.database,holdfield,data.dbf_head.rec_size);
- free(holdfield);
-
- if(x != data.dbf_head.rec_size) return(DOS_WRITE_ERROR);
-
- dbSize += x; // update the size pointer...
-
- // dynamically update the database header
-
- lseek(data.database,0L,SEEK_SET); // rewind the file
-
- x = read(data.database,(char *)&data.dbf_head,sizeof(DBF_HEAD));
- if(x != sizeof(DBF_HEAD)) return(DOS_READ_ERROR);
-
- ++data.dbf_head.last_rec; // increment the number of records by one
-
- // update the `last_update' field <<-- needs to be implemented
-
- lseek(data.database,0L,SEEK_SET); // rewind the file
- if(lock(data.database,0L,sizeof(DBF_HEAD),DB_LOCK))
- {
- write(data.database,(char *)&data.dbf_head,sizeof(DBF_HEAD));
- lock(data.database,0L,sizeof(DBF_HEAD),DB_UNLOCK);
- }
- else
- return(RECORD_LOCK_FAILED_ERROR);
-
- // is there a `file_locked' condition?
-
- if(file_locked)
- {
- // yes, expand the current lock to include the new record
-
- dbSize += data.dbf_head.rec_size;
-
- if(!lock(data.database,0L,dbSize,DB_LOCK))
- return(FILE_LOCK_FAILED_ERROR);
-
- lockIt = FALSE; // record is already implicitly locked,
- // so don't be redundant
- }
-
- gotoRecord(data.dbf_head.last_rec); // re-position to the new record
-
- x = NO_PROBLEM;
-
- if(lockIt && !rLock()) x = db_err;
-
- return(x);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::b2f(void)
- {
- int x,y,z;
- int left,right;
- int year,month,day;
- char logical;
- char text[256];
- char format[25];
- char *buff;
- char *hold;
- float number;
- long long_number;
- FIELD_DATA *new_field;
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- buff = (char *)getRecord();
- y = getRecordLen();
-
- data.deleted = (*buff == '*') ? TRUE : FALSE;
-
- ++buff;
-
- clearDBFields(); // release the linked list of field data
-
- x = 0;
- while(x < data.num_fields)
- {
- switch(data.field_rec[x].field_type)
- {
- case 'D': grab(buff,buff+3,text);
- year = atoi(text);
-
- grab(buff+4,buff+5,text);
- month = atoi(text);
-
- grab(buff+6,buff+7,text);
- day = atoi(text);
-
- buff += 8;
-
- if((new_field = newDBField()) == NULL)
- {
- ++x;
- continue;
- }
-
- new_field->field_type = 'D';
- new_field->data.date.month = month;
- new_field->data.date.day = day;
- new_field->data.date.year = year;
-
- break;
-
- case 'C': y = data.field_rec[x].len_info.char_len - 1;
- grab(buff,buff+y,text);
-
- buff += y;
- ++buff;
-
- if((new_field = newDBField()) == NULL)
- {
- ++x;
- continue;
- }
-
- new_field->field_type = 'C';
- strcpy(new_field->data.text,text);
-
- break;
-
- case 'L': logical = *buff;
- ++buff;
-
- if((new_field = newDBField()) == NULL)
- {
- ++x;
- continue;
- }
-
- new_field->field_type = 'L';
- new_field->data.boolean = logical;
-
- break;
-
- case 'M': grab(buff,buff+9,text);
- buff += 10;
- break;
-
- case 'N': y = data.field_rec[x].len_info.num_size.len - 1;
- grab(buff,buff+y,text);
-
- buff += y;
- ++buff;
-
- z = data.field_rec[x].len_info.num_size.dec;
-
- if((new_field = newDBField()) == NULL)
- {
- ++x;
- continue;
- }
-
- if(z > 0)
- {
- sprintf(format,"%%%3d.%03df",y+1,z);
- sscanf(text,"%f",&number);
-
- new_field->field_type = 'F';
- new_field->data.float_number.number = number;
- strcpy(new_field->data.float_number.format,format);
- }
- else
- {
- long_number = atol(text);
-
- new_field->field_type = 'N';
- new_field->data.long_number = long_number;
- }
- break;
- }
-
- ++x;
- }
-
- update = FALSE;
-
- return(NO_PROBLEM);
- }
-
- //---------------------------------------------------------------------------
- FIELD_DATA *dBASE::newDBField(void)
- {
- FIELD_DATA *this_field;
- FIELD_DATA *new_field;
-
- new_field = (FIELD_DATA *) malloc(sizeof(FIELD_DATA));
- if(new_field == NULL) return(NULL);
-
- if(data.field_data == NULL)
- data.field_data = new_field;
- else
- {
- this_field = data.field_data;
- while(this_field->next != NULL) this_field = this_field->next;
- this_field->next = new_field;
- }
-
- new_field->next = NULL;
- return(new_field);
- }
-
- //---------------------------------------------------------------------------
- void dBASE::clearDBFields(void)
- {
- FIELD_DATA *this_field;
- FIELD_DATA *that_field;
-
- // clear out an previous data
- if(data.field_data != NULL)
- {
- this_field = data.field_data;
- while(this_field != NULL)
- {
- that_field = this_field->next;
- free(this_field);
- this_field = that_field;
- }
- data.field_data = NULL;
- }
- }
-
- //---------------------------------------------------------------------------
- int dBASE::f2b(void)
- {
- int x,y,z;
- int left,right;
- int year,month,day;
- int logical;
- char text[256];
- char *buff;
- char *hold;
- float number;
- long long_number;
- FIELD_DATA *this_field;
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- buff = (char *)getRecord();
- ++buff; // skip over the "deleted" marker
-
- y = getRecordLen();
-
- this_field = data.field_data;
-
- while(this_field != NULL)
- {
- switch(this_field->field_type)
- {
- case 'D': *text = 0;
- sprintf(hold,"%04d",this_field->data.date.year);
- strcat(text,hold);
- sprintf(hold,"%02d",this_field->data.date.month);
- strcat(text,hold);
- sprintf(hold,"%02d",this_field->data.date.day);
- strcat(text,hold);
-
- hold = text;
- while(*hold != 0) *buff++ = *hold++;
-
- break;
-
- case 'C': hold = this_field->data.text;
- while(*hold != 0) *buff++ = *hold++;
- break;
-
- case 'L': *buff = this_field->data.boolean;
- ++buff;
- break;
-
- case 'M':
- break;
-
- case 'F': sprintf(text,this_field->data.float_number.format,
- this_field->data.float_number.number);
- hold = text;
- while(*hold != 0) *buff++ = *hold++;
- break;
-
- case 'N': sprintf(text,"%ld",this_field->data.long_number);
- hold = text;
- while(*hold != 0) *buff++ = *hold++;
- break;
- }
-
- this_field = this_field->next;
- }
-
- buff = (char *)getRecord();
- ++buff;
- putchar('(');
- for(z = 0;z < y;z++) putchar(*buff++);
- putchar(')');
- getch();
-
- return(NO_PROBLEM);
- }
-
- //---------------------------------------------------------------------------
- void dBASE::printDBFields(void)
- {
- FIELD_DATA *this_field;
-
- if(data.database == -1) return;
-
- this_field = data.field_data;
-
- while(this_field != NULL)
- {
- switch(this_field->field_type)
- {
- case 'D': printf("\t%02d/%02d/%04d\n",
- this_field->data.date.month,
- this_field->data.date.day,
- this_field->data.date.year);
- break;
-
- case 'C': printf("\t%s\n",this_field->data.text);
- break;
-
- case 'L': printf("\t%c\n",this_field->data.boolean);
- break;
-
- case 'M':
- break;
-
- case 'F': printf("\t");
- printf(this_field->data.float_number.format,
- this_field->data.float_number.number);
- printf("\n");
- break;
-
- case 'N': printf("\t%ld\n",this_field->data.long_number);
- break;
- }
-
- this_field = this_field->next;
- }
- }
-
- //---------------------------------------------------------------------------
- void dBASE::skip(LONG num)
- {
- LONG hold;
-
- if(data.database == -1) return;
-
- eof_met = FALSE;
- bof_met = FALSE;
-
- if(data.index.index_chain != NULL) // we have an index active
- {
- if(num < 0) // we're skipping backward
- {
- hold = num;
- while(hold)
- {
- if(data.index.current_record->prev == NULL) // @ BOF
- {
- hold = data.index.current_record->record;
- bof_met = TRUE;
- break;
- }
-
- --hold;
- data.index.current_record = data.index.current_record->prev;
- }
- if(!bof_met) hold = data.index.current_record->record;
- }
- else // we're skipping forward
- {
- hold = num;
- while(hold)
- {
- if(data.index.current_record->next == NULL) // @ EOF
- {
- hold = data.index.current_record->record;
- eof_met = TRUE;
- break;
- }
-
- --hold;
- data.index.current_record = data.index.current_record->next;
- }
- if(!eof_met) hold = data.index.current_record->record;
- }
- }
- else
- {
- hold = data.current_record + num;
-
- if(hold > data.dbf_head.last_rec)
- {
- eof_met = TRUE;
- hold = data.dbf_head.last_rec;
- }
- else if(hold < 1)
- {
- bof_met = TRUE;
- hold = 1;
- }
- }
-
- data.current_record = hold;
- gotoRecord(data.current_record);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::eof(void)
- {
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- return(eof_met);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::bof(void)
- {
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- return(bof_met);
- }
-
- //---------------------------------------------------------------------------
- // this function is a front-end to indexOn(int) which locates the field
- // indicated by its name, and then forwards that field's # to the real
- // routine.
- //---------------------------------------------------------------------------
- int dBASE::indexOn(char *fieldName)
- {
- int x;
-
- // see if there is a database currently open in this area
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
-
- x = 0;
- while(x < data.num_fields)
- {
- if(stricmp(data.field_rec[x].field_name,fieldName) == 0) break;
- ++x;
- }
-
- // see if we located it...
- if(x == data.num_fields) return(INVALID_FIELD_NAME_ERROR);
-
- return(indexOn(x + 1)); // convert x to 1-based indexing
- }
-
- //---------------------------------------------------------------------------
- int dBASE::indexOn(int fieldNumber) // fieldNumber is 1-based (1234...)
- {
- INDEX_CHAIN *this_link,*new_link;
- FIELD_DATA *this_field;
- FIELD_REC *this_rec;
- int x,first;
-
- // see if there is a database currently open in this area
-
- if(data.database == -1) return(NO_DB_OPEN_ERROR);
- if(fieldNumber < 1 || fieldNumber > data.num_fields)
- return(INVALID_FIELD_NUM_ERROR);
-
- // is there an index currently active?
-
- if(data.index.index_chain != NULL) killIndex(); // keel it... 8^)
-
- // build a linked list of FIELD DATA/RECORD NUMBER pairs that will
- // act as our index.
-
- data.index.index_field = x - 1;
-
- gotoRecord(1L);
-
- while(!eof())
- {
- new_link = (INDEX_CHAIN *)malloc(sizeof(INDEX_CHAIN));
-
- if(data.index.index_chain == NULL)
- data.index.index_chain = new_link;
- else
- {
- this_link->next = new_link;
- new_link->prev = this_link;
- }
-
- this_link = new_link;
- this_link->next = NULL;
-
- // locate the field data
- x = 0;
- this_field = data.field_data;
- while(x < fieldNumber)
- {
- this_field = this_field->next;
- ++x;
- }
-
- switch(this_field->field_type)
- {
- case 'D': sprintf(this_link->key.textKey,"%02d/%02d/%04d",
- this_field->data.date.month,
- this_field->data.date.day,
- this_field->data.date.year);
- break;
-
- case 'C': strcpy(this_link->key.textKey,this_field->data.text);
- break;
-
- case 'L': this_link->key.logicalKey = this_field->data.boolean == 'F' ? FALSE : TRUE;
- break;
-
- case 'M':
- break;
-
- case 'F': this_link->key.floatKey = this_field->data.float_number.number;
- break;
-
- case 'N': this_link->key.longKey = this_field->data.long_number;
- break;
- }
- this_link->record = currRecord();
-
- skip();
- }
-
- // since the other routines check for an active index, all we have left
- // to do is sort it...
- }
-
- //---------------------------------------------------------------------------
- void dBASE::killIndex(void)
- {
- INDEX_CHAIN *this_link;
- INDEX_CHAIN *that_link;
-
- // clear out any previous index
-
- if(data.index.index_chain != NULL)
- {
- this_link = data.index.index_chain;
- while(this_link != NULL)
- {
- that_link = this_link->next;
- free(this_link);
- this_link = that_link;
- }
-
- data.index.index_chain = NULL;
- data.index.current_record = NULL;
- }
- }
-
- //---------------------------------------------------------------------------
- int dBASE::fLock(void)
- {
- // ask the network to lock this file...
-
- file_locked = lock(data.database,0L,dbSize,DB_LOCK);
-
- if(!file_locked)
- db_err = FILE_LOCK_FAILED_ERROR;
- else
- record_locked = TRUE; // locked file means locked records
-
- return(file_locked);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::fUnLock(void)
- {
- // ask the network to unlock this file...
-
- file_locked = !lock(data.database,0L,dbSize,DB_UNLOCK);
-
- if(file_locked)
- db_err = FILE_UNLOCK_FAILED_ERROR;
- else
- record_locked = FALSE; // unlocked file means unlocked records
-
- return(!file_locked);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::rLock(void)
- {
- long pos;
-
- // ask the network to lock this record...
-
- // see ::lock() for an explanation of this mechanism.
-
- pos = tell(data.database);
- record_locked = lock(data.database,pos,data.dbf_head.rec_size,DB_LOCK);
-
- if(!record_locked) db_err = RECORD_LOCK_FAILED_ERROR;
-
- return(record_locked);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::rUnLock(void)
- {
- long pos;
-
- // ask the network to unlock this record...
-
- pos = tell(data.database);
- record_locked = !lock(data.database,pos,data.dbf_head.rec_size,DB_UNLOCK);
-
- if(record_locked) db_err = RECORD_UNLOCK_FAILED_ERROR;
-
- return(!record_locked);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::lock(int file,long offset,long length,int function)
- {
- union REGS xr;
- int result;
-
- net_err = -1;
-
- // if `length' is 0L, what the hell are they trying to lock?!
-
- if(length == 0L) return(FALSE);
-
- // we use the DOS 21h/5Ch function (Lock/Unlock File Access) to
- // allow locking compatibility with networks that support this interrupt
- // (such as Novell NetWare, LANtastic, and Banyan Vines).
-
- // AL = [0 to lock/1 to unlock]
- // BX = File Handle
- // CX = High word of offset
- // DX = Low word of offset
- // SI = High word of length
- // DI = Low word of length
- // If CF = 1, AX = error code
-
- xr.h.ah = 0x5C;
- xr.h.al = function; // lock/unlock request
- xr.x.bx = file; // file handle
-
- // starting offset in `file'
-
- if(offset != 0L)
- {
- xr.x.cx = (INT)((offset & 0x7FFF0000) >> 8);
- xr.x.dx = (INT)(offset & 0x0000FFFF);
- }
- else // skip the contortions for a 0L value
- {
- xr.x.cx = 0x0000;
- xr.x.dx = 0x0000;
- }
-
- // number of bytes in `file' to lock
-
- xr.x.si = (INT)((length & 0x7FFF0000) >> 8);
- xr.x.di = (INT)(length & 0x0000FFFF);
-
- int86(0x21,&xr,&xr);
-
- // we will receive an error code of 0x0001 (Invalid Function) if file/record
- // locking is not appropriate or possible for the current medium (such as
- // a file residing on a local hard drive without SHARE loaded). In such
- // an instance, simply act as though the file/record is locked.
-
- if(xr.x.cflag && xr.x.ax != 0x0001)
- {
- net_err = xr.x.ax;
- return(FALSE);
- }
- else
- return(TRUE);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::getDBErr(void)
- {
- int hold;
-
- hold = db_err;
- db_err = NO_PROBLEM; // reset the error holder on each call
- return(hold);
- }
-
- //---------------------------------------------------------------------------
- int dBASE::getNetErr(void)
- {
- int hold;
-
- hold = net_err;
- net_err = NO_PROBLEM; // reset the error holder on each call
- return(hold);
- }
-
- //---------------------------------------------------------------------------
- // this function is a front-end to getField(int) which locates the field
- // indicated by its name, and then forwards that field's # to the real
- // routine.
- //---------------------------------------------------------------------------
- FIELD_DATA *dBASE::getField(char *fieldName)
- {
- int x;
-
- // see if there is a database currently open in this area
-
- if(data.database == -1)
- {
- db_err = NO_DB_OPEN_ERROR;
- return(NULL);
- }
-
- x = 0;
- while(x < data.num_fields)
- {
- if(stricmp(data.field_rec[x].field_name,fieldName) == 0) break;
- ++x;
- }
-
- // see if we located it...
- if(x == data.num_fields)
- {
- db_err = INVALID_FIELD_NAME_ERROR;
- return(NULL);
- }
-
- return(getField(x + 1)); // convert x to 1-based indexing
- }
-
- //---------------------------------------------------------------------------
- FIELD_DATA *dBASE::getField(int fieldNumber) // fieldNumber is 1-based (1234...)
- {
- FIELD_DATA *this_field;
- int x,first;
-
- // see if there is a database currently open in this area
-
- if(data.database == -1)
- {
- db_err = NO_DB_OPEN_ERROR;
- return(NULL);
- }
-
- if(fieldNumber < 1 || fieldNumber > data.num_fields)
- {
- db_err = INVALID_FIELD_NUM_ERROR;
- return(NULL);
- }
-
- this_field = data.field_data;
- x = fieldNumber - 1;
-
- while(this_field != NULL && x)
- {
- this_field = this_field->next;
- --x;
- }
-
- if(this_field == NULL) // shouldn't occur, but here for robustness
- {
- db_err = INVALID_FIELD_NUM_ERROR;
- return(NULL);
- }
-
- return(this_field);
- }
-
- ---------------------------- end CBASE.CPP ----------------------------
-
-
- --
- Bob Hood thor@arrakis.denver.co.us H: 303-980-8392 W: 303-632-2180
- ---------------------------------------------------------------------------
- When people are free to do as they please, they usually imitate each other.
-