home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_C
/
KFS.ZIP
/
KFS.DOC
< prev
next >
Wrap
Text File
|
1994-02-15
|
69KB
|
2,646 lines
KEYED FILE SYSTEM - User's Guide
Version 2.0 (DOS and OS/2 1.x)
(c) 1993 APT Computer Solutions, Inc.
Table of Contents
Introduction 1
System Components and Requirements 2
System Requirements 2
Keyed File System Components 2
Keyed File System Restrictions 2
Including KFS Routines in Your Program 4
What Are Keyed Files 5
Keyed File System Functions 7
The File Information Structure 8
Parameters to Keyed File System Functions 10
Keyed File System Functions 11
KFS_Add 11
KFS_Close 13
KFS_Create 14
KFS_Delete 16
KFS_Open 18
KFS_Read 19
KFS_ReadFirst 20
KFS_ReadGen 21
KFS_ReadGenNumeric 23
KFS_ReadNext 25
KFS_Replace 27
Interdependencies of the KFS operations 29
Special Processing 30
KFS_Small_PTR 30
KFS_Numeric_Key 30
KFS_Ignore_Case 31
Programming Hints and Tips 32
Data Recovery 34
Appendix A - Keyed File System Return Codes 35
Appendix B - File Recovery Example 37
3
Introduction
The Keyed File System is a set of routines that allow you to
write programs in C to build and maintain databases on a PC that
are logically organized by a user defined key. Records can be
read or written directly using an alphabetic or numeric key. An
alphabetic key can be a string consisting of any combination of
ASCII characters up to 32,767 characters in length. You may also
have 4 byte signed numeric keys contained in the normal Intel
80x86 long integer format. Note that a database may have alpha-
betic keys or numeric keys but not both (however, see
"Programming Hints & Tips" for hints about combining keys).
The Keyed File System uses normal DOS and OS/2 functions to
create and maintain its databases. Therefore, records may be of
any length supported by the DOS or OS/2 operating systems and
can be created using the FAT or HPFS (OS/2 only) file systems.
Files may be created on floppy or hard disks, although, as might
be expected, hard disk files will provide better performance.
KFS databases may be moved or copied using normal DOS or OS/2
commands (such as COPY) as long as both file components are
moved together (see "Copying Files"). Additionally, databases
built using the KFS functions on one operating system are com-
patible with databases built using the KFS functions on the
other operating system. Thus, databases built by programs run-
ning under DOS may be subsequently used by programs running
under OS/2.
The Keyed File System supports most operations normally associ-
ated with keyed files:
* Direct reading and writing of records by key.
* Sequential reading of records in key sequence.
* Deleting of records by key.
* Reading records using a partial key.
4
System Components and Requirements
System Requirements
The minimum system required to run programs that use the
Keyed File System are:
* OS/2 1.2 or higher, or DOS 3.3 or higher.
* Approx. 180K of disk space including sample programs and
utilities.
* Microsoft C compiler and libraries, version 6.0 (OS/2 and
DOS) or 7.0 (DOS only).
Keyed File System Components
KFS.H - The header file for use in C programs that
want to use KFS functions.
KFSMSC6O.LIB - A lib used at linkedit time to include the
KFS functions when building OS/2 programs
written in Microsoft C Version 6.0.
KFSMSC6D.LIB - A lib used at linkedit time to include the
KFS functions when building DOS programs
written in Microsoft C Version 6.0.
KFSMSC7.LIB - A lib used at linkedit time to include the
KFS functions when building DOS programs
written in Microsoft C Version 7.0.
KFSSAMP.C - A sample program that builds a KFS database
from a sequential file and then uses most of
the functions available in KFS.
KFSSAMP.DAT - The sequential input file to the KFSSAMP
program.
KFSSAMP.MAK - A sample make file for KFSSAMP.C.
Keyed File System Restrictions
The following restrictions apply to KFS databases:
* Databases must contain fixed length records.
* Each record must be at least 5 bytes in length.
* Numeric keys must be 4 bytes in length but alphabetic keys
may be up to 32767 characters in length.
* Duplicate keys are not allowed (see "Programming Tips and
Techniques").
* The path and file name specified during KFS_Create or
KFS_Open for a KFS database cannot be longer than 63 bytes.
5
* Files cannot be created using KFS_Open, you must use
KFS_Create to create a new file and KFS_Open after a file
exists.
* Two databases with the same "base" name cannot exist in the
same directory even if the file extensions are different.
That is KFS databases with the base names of MYFILE.001 and
MYFILE.002 cannot exist in the same directory, but the
names MYFILE1.XXX and MYFILE2.XXX are OK. This is explained
further in the section "What Are Keyed Files".
* You cannot name a KFS database using the extension of .PTR.
Thus MYFILE.PTR is invalid. This is also explained in the
"What Are Keyed Files" section.
6
Including KFS Routines in Your Program
To include the KFS routines in your C program requires three
steps:
1. Include the KFS.H header file at the beginning of your
program source. For example:
#include <KFS.H>
2. Define any keyed files using the KFS_FILEINFO typedef. For
example:
KFS_FILEINFO keyedfile;
3. Include the appropriate KFS---.LIB file when linking your
program. For example, to link a DOS program compiled with
MS/C version 6.0 would be:
LINK myprog,,,KFSMSC6D;
For a complete example of a program using some KFS functions,
look at the KFSSAMP.C file included with this package.
7
What Are Keyed Files
Keyed File System databases are actually composed of two files,
an index file and a data file. These two files work together to
provide you with direct access of a record by key while keeping
the records in a logical keyed sequence. The name of the data
file is the same as the name of the database and is specified by
the programmer when the KFS database is created (using the
KFS_Create function). This may be any valid DOS or OS/2 file
name. The index file is automatically given the same base name
you specified for the database but with an extension of .PTR.
For example, specifying a name of CUSTOMER.DAT for a database
automatically causes the creation of an index file with the name
of CUSTOMER.PTR. This leads to two restrictions in the Keyed
File System:
1) You cannot name a database using an extension of .PTR.
2) You cannot have two databases in the same directory with
the same base name since this would result in an attempt by
KFS to create duplicate .PTR files. For example, MYFILE.001
and MYFILE.002 would both result in KFS attempting to cre-
ate an index file named MYFILE.PTR.
Because these two files work together they must remain physi-
cally in the same directory. Therefore, if the Keyed File System
database is moved, both the data and index files must be moved
together.
The format and content of the index file is determined by the
Keyed File System, while the format and content of the data file
is determined by you when the database is created. When you
create a Keyed File System database you must tell the Keyed File
System how large each record in the database will be
(KFS_recsize), where the key begins in the record (KFS_keypos),
and how long the key is (KFS_keylen). Note that the Keyed File
System only supports fixed length records (ie. each record in
the database is the same length).
The Keyed File System requires that databases are either created
or opened before they are used, and that they are closed before
the program terminates. With any file system, if a program ter-
minates abnormally without closing files (such as a system crash
because of a power failure) and file buffering is being used
(such as is available with HPFS or DOS lazy writing), data that
has been "written" by the program but waiting in an output
buffer to be physically written to disk may be lost. The Keyed
File System makes every attempt to minimize the impact of such a
system failure, but since it does utilize two files working
together, there are rare times this loss of data may result in
the database becoming unusable. Thus special care should be
taken by your application user to properly back up the data and
index files making up each KFS database. Also, see the section
on "Data Recovery" for an example of how to recover a damaged
KFS database.
8
Keyed File System Functions
The Keyed File System is a set of 11 routines that provide you
with the basic functions required for keyed record access on the
PC. These functions are:
KFS_Add
Adds a new record to a KFS database. The key of the record
being added must not already exist in the database.
KFS_Close
Close an open KFS database.
KFS_Create
Create and open a new KFS database. The database must not
already exist.
KFS_Delete
Deletes the record from a KFS database that has the key
specified.
KFS_Open
Open an existing KFS database.
KFS_Read
Read a record from an open KFS database by key.
KFS_ReadFirst
Reads the first logical record in a KFS database.
KFS_ReadGen
For databases with alphabetic keys only. Read a record from
an open KFS database using a partial key. If no records
match the partial key, the next record in sequence after
the key requested is returned in the user area and a code
of KFS_Key_Not_Found is returned in KFS_rc.
KFS_ReadGenNumeric
For databases with numeric keys only. Read a record from an
open KFS database. If the requested key is not found, the
next record in sequence after the key requested is returned
in the user area and a return code of KFS_Key_Not_Found is
returned in KFS_rc.
KFS_ReadNext
Reads the record in a KFS database that is the next record
after the key specified.
KFS_Replace
Replaces the record in a KFS database that has the same key
as the one specified. A record with this key must exist in
the database.
9
The File Information Structure
In order to use the Keyed File System routines, you must provide
the KFS functions with a File Information Structure for each
database you are going to use in your program. This is a control
structure (similar to the C "FILE" typedef) that includes such
information about the database as the database name, key length,
location of the key within the record, and a return code field
for checking the result of KFS operations, as well as control
fields used by the KFS functions themselves. Once the database
is opened, this structure should not be modified by the appli-
cation since this may damage the control information used by the
KFS functions and the integrity of the database may be compro-
mised. There is a C typedef named KFS_FILEINFO for this
structure defined in the KFS.H header file provided with the
system. Also present in this header file are the C prototypes
for the KFS functions and the definitions of the KFS return
codes.
To create a KFS database (using the KFS_Create operation), you
must provide several important pieces of information about the
database. This is done by placing the appropriate values in the
following fields in the File Information Structure defined for
the file:
KFS_filename
Required for KFS_Create or KFS_Open, this field must
contain the name of the database being created or
opened. This is a DOS or OS/2 file specification that
includes drive, path, and database name. As mentioned
before the Keyed File System actually creates (or
opens) two files for any KFS database and if these
files are moved, both must be move to the same loca-
tion (ie. subdirectory or floppy disk). The first file
will have the name you specify here, while the second
file will have the same base name as the database you
specified but a qualifier of .PTR.
KFS_keypos
KFS_Create only. This is the position of the key
within the record. This position is relative to 0.
That is, if the key begins in the first position of
the record, 0 is placed here by the programmer. If the
key begins in the 5th position of the record, 4 is put
here.
KFS_keylen
KFS_Create only. This is the length of the key in the
record. For example, if the key went from position 5
through position 10 (ie. 6 characters long) in the
data record, 6 would be placed here. For numeric keys,
this field is ignored.
10
KFS_recsize
KFS_Create only. Place the total size of each data
record, including the key in this field.
KFS_flags
KFS_Create only. These flags specify any special pro-
cessing required for the database. The options
available to you are normal pointer file, small
pointer file, numeric keys, and ignore case. These
options are discussed further in the section "Special
Processing".
Once a KFS database is created, it may be subsequently used by
simply specifying the name of the database in the KFS_filename
field of the File Information structure and using KFS_Open to
open the database. The remaining information about the database
(ie. KFS_keypos, KFS_keylen, KFS_recsize, and KFS_flags) is
stored with the database when it is created.
Upon the completion of a KFS operation, the success or failure
of the operation is determined by checking the return code pro-
vided in the database's KFS_FILEINFO field KFS_rc. The valid
return codes are defined in the KFS.H header file and are docu-
mented in Appendix A of this User's Guide.
11
Parameters to Keyed File System Functions
The are 11 application interfaces that can be called to perform
operations on databases with the Keyed File System. These
operations require 1, 2, or 3 parameters depending on the func-
tion desired.
The first parameter to all of the KFS functions is always the
address of the KFS File Information structure (KFS_FILEINFO) for
the desired database. As mentioned before, once a database is
created or opened this structure should not be changed by the
programmer since it is used by the database system to keep track
of current information about the database. It is also used to
provide feedback to the programmer about the requested opera-
tion.
The second parameter is necessary for the functions that will be
reading data from or writing data to a KFS database. This
parameter is the address of an area large enough to contain a
record from the database (that is, at least KFS_recsize in
length). When a key is required by a specific KFS operation, the
system expects the key to be in this area at the same relative
position, and with the same length, as the key in a record in
the database. For example, to read a record with the key "ABCDE"
for a database whose KFS_keypos = 3, KFS_keylen = 5, and
KFS_recsize = 80 means that the second parameter would be the
address of an area at least 80 bytes in length that contains
"ABCDE" in the 4th, 5th, 6th, 7th, and 8th bytes (ie.
...ABCDE..).
The third parameter is only required on the KFS_ReadGen function
and is the length of the portion of the key provided. This
parameter is discussed further in the discussion of KFS_ReadGen.
The following program segment illustrates how the above param-
eters would be specified for a typical KFS function call:
#include <kfs.h>
KFS_FILEINFO file1;
char recarea[100];
strcpy(file1.KFS_filename, "C:\\MYDIR\\MYFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
strcpy(&recarea[file1.KFS_keypos], "A k");
KFS_ReadGen(&file1, (void *)recarea, 3);
For further examples, see the description of the individual KFS
functions and the KFSSAMP.C program provided as part of this
package.
12
Keyed File System Functions
In the description of the following functions the KFS_File_Error
is a general error caused by an "unknown error" returned from
the operating system and is possible for all functions.
KFS_Add(fs, area)
Add a data record to a database.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area containing the record to be
added. The key to be added must be at KFS_keypos of
this area before the operation is issued.
Description
Add a record to the database. Another record with this key
must not already exist in the database.
Required Fields
KFS_filename
Contains the name of an open database where the record
is to be added.
13
Example
/* Add a record to a KFS file */
#include <kfs.h>
KFS_FILEINFO file1;
typedef struct m {
int f1;
int f2;
char mykey[7];
char filler[89];
} MYSTRUCT;
MYSTRUCT inarea;
strcpy(file1.KFS_filename, "C:\\MYDIR\\NUMFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
strcpy(&inarea.mykey, "Newkey");
inarea.f1 = 0; /* Just some data in record */
inarea.f2 = 15; /* Just some data in record */
KFS_Add(&file1, (void *)&inarea);
switch (file1.KFS_rc) {
case KFS_Key_Already_Exists :
printf("Key already in file");
case KFS_OK:
break;
default:
printf("Error adding record");
}
Possible KFS_rc Values
KFS_OK
The record was added successfully.
KFS_Key_Already_Exists
A record with the same key as the record being added
already exists in the database. The operation is
ignored.
KFS_File_Error
An unknown error occurred when attempting to add a
record to a KFS database.
KFS_No_Space_On_Disk
There was not enough space on the disk containing the
KFS file to contain another data and pointer record.
14
KFS_Close(fs)
Close a database.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
Description
Close a database. The database must then be opened before
further processing can occur.
Required Fields
KFS_filename
Contains the name of an opened database.
Example
/* Close a KFS file */
#include <kfs.h>
KFS_FILEINFO file1;
.
.
KFS_Close(&file1);
Possible KFS_rc Values
KFS_OK
The database was closed successfully.
15
KFS_Create(fs)
Create a new, empty database and open it.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
Description
Create an empty database from the information supplied in
the KFS_FILEINFO structure. At the conclusion of a suc-
cessful operation the database is opened and may be used
without the need to call the KFS_Open function. If a data-
base already exists with this name, an error is returned.
Required Fields
KFS_keypos
Contains the position of the key in the records of the
new database. This position is relative to 0.
KFS_keylen
Contains the length of the key.
KFS_recsize
Contains the size of each of the keyed records to be
built.
KFS_filename
Contains the name of the database to be created. If
the name has a qualifier, it cannot be PTR. Also, the
base portion of the name cannot be the same as any
other database even if the qualifiers are unique.
KFS_flags
Specifies some additional information about the data-
base (See the "Special Processing" section for more
discussion of these options). The valid settings for
this field are:
KFS_Normal_PTR
The normal pointer file organization is
used. This results in the initial allocation
of the .PTR file of about 8K but results in
good performance for large databases.
KFS_Small_PTR
The organization of the pointer file will be
changed to save space on the initial allo-
cation of the database. This option should
be specified only when the database will be
a small one since larger databases having
this option are slower than for databases
created with KFS_Normal_PTR.
KFS_Numeric_Keys
The keys in the database will be numeric
keys stored in the Intel long integer for-
mat. This option also implies a small
pointer file.
16
KFS_Ignore_Case
The case of the keys in the database is
ignored. That is, a key of "ABCDE" and "ab-
cde" will be treated as the same key.
Example
/* Create and open a KFS file with alphabetic keys starting */
/* in the 5th position of the record and 7 bytes long */
#include <kfs.h>
KFS_FILEINFO file1;
char recarea[100];
file1.KFS_flags = KFS_Normal_PTR;
file1.KFS_keypos = 4;
file1.KFS_keylen = 7;
file1.KFS_recsize = 100;
strcpy(file1.KFS_filename, "C:\\MYDIR\\MYFILE.DAT");
KFS_Create(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error creating file1\n");
Possible KFS_rc Values
KFS_OK
The database was created successfully.
KFS_Keyed_File_Already_Exists
A database with this name already exists.
KFS_Invalid_File_Name
The file name and associated path name is longer than
63 characters.
KFS_PTR_File_Open_Error
An unknown error occurred while attempting to open the
PTR file associated with the database. This error can
occur if there is not enough space on the disk to
allocate the pointer file or if a .PTR file by this
name already exists.
KFS_Data_File_Open_Error
An unknown error occurred while attempting to open the
data file associated with the database.
17
KFS_Delete(fs, area)
Delete a record from the database.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area containing the key of the
record to be deleted. This key must be placed at
KFS_keypos of this area before the operation is
issued.
Description
Delete a record from the database.
Required Fields
KFS_filename
Contains the name of an opened database.
area
The data area pointed to must contain the key of the
record being deleted beginning in KFS_keypos of the
area.
Example
/* Add a record to a KFS file */
#include <kfs.h>
KFS_FILEINFO file1;
typedef struct m {
int f1;
int f2;
char mykey[7];
char filler[89];
} MYSTRUCT;
MYSTRUCT inarea;
strcpy(file1.KFS_filename, "C:\\MYDIR\\NUMFILE.DAT");
KFS_Open(&file1);
memset(&inarea.mykey, ' ', sizeof(inarea.mykey));
strcpy(&inarea.mykey, "Dkey");
KFS_Delete(&file1, (char *)&inarea);
switch (file1.KFS_rc) {
case KFS_OK:
break;
case KFS_No_Space_On_Disk:
printf("Not enough space on disk to add record\n");
break;
default:
printf("Error adding record\n");
}
Possible KFS_rc Values -
KFS_OK
The record was deleted successfully.
18
KFS_Key_Not_Found
A record with the key specified was not found. The
operation is ignored.
KFS_No_Space_On_Disk
There is not enough space on the disk containing the
KFS database to add a record.
19
KFS_Open(fs)
Open an existing database.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
Description
Open an existing database for processing. All databases
must be opened before any processing may be done on those
databases.
Required Fields
KFS_filename
Contains the name of an existing database to be
opened.
Example
/* Open a KFS file */
#include <kfs.h>
KFS_FILEINFO file1;
char recarea[100];
strcpy(file1.KFS_filename, "C:\\MYDIR\\MYFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
Possible KFS_rc Values
KFS_OK
The database was opened successfully.
KFS_Keyed_File_Does_Not_Exist
The database does not exist.
KFS_Invalid_File_Name
The database name and associated path name is longer
than 63 characters.
KFS_PTR_File_Open_Error
An unknown error occurred while attempting to open the
PTR file associated with the database.
KFS_Data_File_Open_Error
An unknown error occurred while attempting to open the
data file associated with the database.
20
KFS_Read(fs, area)
Read a record by key from the database.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area where the requested record
will be read. The key to be read must be placed at
KFS_keypos of this area before the operation is
issued.
Description
Read a record by key from a database.
Required Fields
KFS_filename
Contains the name of an open database.
area
The data area pointed to must contain the key of the
record being read beginning at position KFS_keypos.
Example
/* Read a KFS file by key (keypos=4, keylen=7) */
#include <kfs.h>
KFS_FILEINFO file1;
char recarea[100];
strcpy(file1.KFS_filename, "C:\\MYDIR\\MYFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
memset(recarea, ' ', sizeof(recarea));
/* Note - we kept the terminating NULL as part of the key */
strcpy(&recarea[file1.KFS_keypos], "A key");
KFS_Read(&file1, (void *)recarea);
if (file1.KFS_rc != KFS_OK)
printf("Error reading keyed record from file1\n");
Possible KFS_rc Values
KFS_OK
The record was read successfully.
KFS_Key_Not_Found
A record with the key specified was not found. The
operation is ignored.
21
KFS_ReadFirst(fs, area)
Read the first record in keyed sequence in the database.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area where the first record in the
KFS database will be read.
Description
Read the first record from a database. The record with the
lowest key will be read and placed in the data area.
Required Fields
KFS_filename
Contains the name of an open database.
Example
/* Read the all of the records sequentially from a file */
#include <kfs.h>
KFS_FILEINFO file1;
char recarea[100];
strcpy(file1.KFS_filename, "C:\\MYDIR\\NUMFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
KFS_ReadFirst(&file1, recarea);
if (file1.KFS_rc != KFS_OK) printf("Error");
Possible KFS_rc Values -
KFS_OK
The record was read successfully.
KFS_Keyed_File_Empty
No records were found in the database. The operation
is ignored.
22
KFS_ReadGen(fs, area, length)
Read a record using a partial key.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area where the requested record
will be read. The partial key to be used must be
placed at KFS_keypos of this area before the operation
is issued.
int length
The length of the partial key at KFS_keypos. If the
length specified is 0, the first record in the data-
base is read.This length must be less than or equal to
KFS_keylen.
Description
Read the first record in the database whose first portion
matches that of the partial key supplied. If no record
matches the partial key, the next logical record in the
database is returned.
Required Fields
KFS_filename
Must contain the name of an open database.
area
The data area pointed to must contain the key of the
record being read.
Example
/* Read a KFS file by partial key (keypos=4, keylen=7) */
#include <kfs.h>
KFS_FILEINFO file1;
char recarea[100];
strcpy(file1.KFS_filename, "C:\\MYDIR\\MYFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
strcpy(&recarea[file1.KFS_keypos], "A k");
KFS_ReadGen(&file1, (void *)recarea, 3);
if (file1.KFS_rc == KFS_Key_Not_Found)
printf("We had no key match but got the next key\n");
else
if (file1.KFS_rc == KFS_OK)
printf("We got a record with a key starting with 'A
k'");
Possible KFS_rc Values -
KFS_OK
The partial key matched an existing record and this
record was read successfully.
KFS_Key_Not_Found
23
No record with a key that matched the partial key
specified was found. The next logical record in the
database is returned.
KFS_EOF
The partial key requested could not be found and the
next position in the database was end of file.
KFS_Key_Length_Invalid
A length greater than KFS_keylen was supplied in the
parameter list.
KFS_Invalid_Request
A KFS_ReadGen operation was attempted on a database
with numeric keys.
24
KFS_ReadGenNumeric(fs, area)
Read a numeric record, return the next record if not found.
Parameters -
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area where the requested record
will be read. A numeric key must be placed in
KFS_keypos of this area prior to performing the
operation.
Description
If a record in the database matches the key specified it is
read and placed in the data area. KFS_OK is then returned.
If no record matches the numeric key, then the next record
in the database is returned with a return code of
KFS_Key_Not_Found.
Required Fields
KFS_filename
Contains the name of an open database.
area
The data area pointed to must contain a numeric key at
KFS_keypos.
Example
/* Read a KFS file by numeric key (keypos=4) */
#include <kfs.h>
KFS_FILEINFO file1;
typedef struct m {
int f1;
int f2;
long mykey;
char filler[92];
} MYSTRUCT;
MYSTRUCT inarea;
strcpy(file1.KFS_filename, "C:\\MYDIR\\NUMFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
inarea.mykey = 1000;
KFS_ReadGenNumeric(&file1, (void *)inarea);
if (file1.KFS_rc == KFS_Key_Not_Found)
printf("There was no key 1000 but got the next key\n");
else
if (file1.KFS_rc == KFS_OK)
printf("We got the record with key 1000");
Possible KFS_rc Values
KFS_OK
The record was read successfully.
25
KFS_Key_Not_Found
No record with a key that matched the key specified
was found. The next logical record in the database is
returned.
KFS_EOF
The partial key requested could not be found and the
next position in the database was at end of file.
26
KFS_ReadNext(fs, area)
Read the next record in keyed sequence in the database.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area where the requested record
will be read. The key placed at KFS_keypos of this
area must be the key of the record before the record
desired.
Description
Read the next logical record from a database. The record
with the next highest key after the key specified in the
data area will be read. The user must provide the key of
the previous record in KFS_keypos of area. This allows the
user to read all records in a database with a succession of
KFS_ReadNext functions.
Required Fields
KFS_filename
Contains the name of an open database.
area
Contains the key of the record previous to the one to
be read.
Example
/* Read the all of the records sequentially from a file */
#include <kfs.h>
KFS_FILEINFO file1;
typedef struct m {
int f1;
int f2;
char mykey[7];
char filler[89];
} MYSTRUCT;
MYSTRUCT inarea;
strcpy(file1.KFS_filename, "C:\\MYDIR\\NUMFILE.DAT");
KFS_Open(&file1);
if (file1.KFS_rc != KFS_OK)
printf("Error opening file1\n");
KFS_ReadFirst(&file1, (void *)&inarea);
while (file1.KFS_rc != KFS_EOF) {
KFS_ReadNext(&file1, (void *)&inarea);
if (file1.KFS_rc != KFS_OK) printf("Error");
}
KFS_Close(&file1);
Possible KFS_rc Values
KFS_OK
The record was read successfully.
27
KFS_EOF
There are no more records in the dataset.
KFS_Key_Not_Found
A record with the specified key did not exist in the
database and no record is returned. (i.e. the previous
record must be found before the "next" record can be
returned)
28
KFS_Replace(fs, area)
Replace the record with the specified key.
Parameters
KFS_FILEINFO *fs
A pointer to a KFS file structure.
void *area
A pointer to a data area containing the record that
will replace the record with the specified key in the
database.
Description
Replace the record with the corresponding key in the data-
base with the record in area. If the record does not exist
in the database, the operation is ignored and a
KFS_Key_Not_found is returned. No prior read of the record
being replaced must be done.
Required Fields
KFS_filename
Contains the name of an open database.
area
Contains the record that will replace the one in the
database.
Example
/* Replace a record in a KFS file */
#include <kfs.h>
KFS_FILEINFO file1;
typedef struct m {
int f1;
int f2;
char mykey[7];
char filler[89];
} MYSTRUCT;
MYSTRUCT inarea;
strcpy(file1.KFS_filename, "C:\\MYDIR\\NUMFILE.DAT");
KFS_Open(&file1);
strcpy(&inarea.mykey, "Oldkey");
/* Note - we would not have to read to replace */
KFS_Read(&file1, (void *)&inarea);
inarea.f2 = 77;
KFS_Replace(&file1, (void *)&inarea);
switch (file1.KFS_rc) {
case KFS_Key_Not_Found :
printf("Record was not in file");
case KFS_OK:
break;
default:
printf("Error replacing record");
}
29
Possible KFS_rc Values -
KFS_OK
The record was read successfully.
KFS_Key_Not_Found
A record with the key specified was not found. The
operation is ignored.
KFS_File_Error
An unknown error occurred when attempting to replace
the requested record.
30
Interdependencies of the KFS operations
Except for the requirements for opening databases first and
closing databases last, there is no specific dependencies
between KFS operations. That is, there is no requirement to call
a specific function before another function can be called. For
example, it is not necessary to read a specific record before
replacing it with KFS_Replace. The same is true if you want to
delete a record, it is not necessary to read it first. Simi-
larly, you can issue a KFS_ReadNext after any other operation,
as long as the key of an existing record is present in the data
area so that KFS_ReadNext can read the record with the next
highest key.
31
Special Processing
There are a few special options that may be chosen when creating
a database with the Keyed File System that allow for special
uses of databases. These options are enabled by setting certain
bits in the KFS_flags field of the File Information Structure.
If none of the options are desired, the flags field should be
set to KFS_Normal_PTR. Normally, databases are relatively large
databases (such as customer record databases) with keys that
contain primarily letters (people's names, for example) and the
Keyed File System was designed to handle these databases most
efficiently. Some assumptions are made about the number and type
of keys that will exist in the database when it is created and
results in creating an initial .PTR file of about 8K bytes.
Because of this initial allocation, the .PTR file is normally
slow to grow. However, for some applications, the assumptions
made by the Keyed File System may not be correct. Three options
are provided to enable the programmer to select a more efficient
initial .PTR allocation or to utilize various types of keys.
KFS_Small_PTR
For applications that need relatively small databases (up to a
few hundred records), the KFS_Small_PTR option provides a way to
greatly reduce the initial size of the .PTR file from 8K to a
few hundred bytes. However, using this option will result in
slower execution speed if the database does grow large. Note
that this does not prohibit the database from becoming large,
just that performance is slower should it do so.
The option is enabled by setting the KFS_flags field to
KFS_Small_PTR. In C this could be done by the following code :
#include <kfs.h>
KFS_FILEINFO file1;
file1.KFS_flags = KFS_Small_PTR;
KFS_Numeric_Key
For applications whose keys are all numbers, it would be more
efficient of these numbers could be stored in the normal way
that the Intel 80x86 stores numbers. That is, in byte reversed
binary form (ie. short, int, or long in C terminology). The
Keyed File System provides the KFS_Numeric_Key option that
allows the key to be stored in the 4 byte Intel integer format
(ie. C's "long int"). Using this option will cause the system to
assume that KFS_keypos indicates the beginning of a 4 byte key
that is a number stored in integer form. KFS_keylen is ignored
when this option is specified.
The option is enabled by setting the KFS_flags field to
KFS_Numeric_Key. In C this could be done by the following code :
#include <kfs.h>
KFS_FILEINFO file1;
file1.KFS_flags = KFS_Numeric_Key;
32
KFS_Ignore_Case
Normally, databases created with alphabetic keys are sensitive
to the case of the keys. That is, keys "ABCDE" and "abcde"
indicate the keys of two different records. However, setting
this option allows case to be ignored for databases that have
alphabetic keys. Then a database created with this option would
treat the keys "ABCDE" and "abcde" as the key to the same
record.
The option can be combined with the KFS_Normal_PTR or
KFS_Small_PTR options and is enabled by setting the KFS_flags
field to KFS_Ignore_Case. In C this could be done by the fol-
lowing code :
#include <kfs.h>
KFS_FILEINFO file1;
file1.KFS_flags = KFS_Normal_PTR | KFS_Ignore_Case;
33
Programming Hints and Tips
In this section we will try to provide some hints, examples,
and, hopefully, the answers to some questions to help an appli-
cation developer in using the Keyed File System. As part of the
KFS package we have included the source to the sample and util-
ity programs we have provided. These programs will provide some
concrete coding examples of how to use the functions we have
described. Use them to reinforce some of the examples we use in
this section.
* Ensure that when creating a database that the KFS_flags
field is properly set to one of the valid options.
* When specifying a key in the data area for an operation
that requires a key, make sure that all bytes in the key
field are set to a known value. Remember, the Keyed File
System always assumes the key is KFS_keylen bytes long,
irrespective of any NULLS in the key field. A common mis-
take is not to "clear" the key field before moving in a key
that may be shorter than keylen. For example, STRCPY only
moves data until a '00'X is detected in the source. Thus,
if what is being moved in is shorter than KFS_keylen, the
remaining bytes of the key field will remain unchanged (ie.
may contain garbage). Additionally, consider that STRCPY
also moves the terminating NULL character and that will
become part of the key. This may be OK, just realize that
the NULL is there. A good habit to get into when using KFS
functions is illustrated by the following code:
#include <kfs.h>
KFS_FILEINFO file1;
char area[80];
memset(&area[file1.KFS_keypos], ' ', file1.KFS_keylen);
strcpy(&area[file1.KFS_keypos, newkey);
This code sequence initially sets the key field of "area"
to blanks and then copies in the desired key from the
"newkey" variable.
* You will notice that the Keyed File System does not allow
for duplicate keys. However, with a little thought, the
KFS_ReadGen and KFS_ReadNext functions can be used to pro-
vide a similar capability. For example, if you wanted to
have a database whose key was a name field, duplicate names
could be avoided by making the key field the name AND
account number. You could still issue a KFS_ReadGen for
only the name and then use KFS_ReadNext to read the rest of
the records having the same name.
* If KFS_ReadNext tries to read the next record after the
last logical record in the database (ie. the record with
the highest key) a KFS_EOF is returned. If another
KFS_ReadNext is issued, KFS_EOF will again be returned.
However, other operations (such as KFS_Read) are still
allowed on the database and will result in KFS_rc to be set
to another value (such as KFS_OK if the read is success-
ful). Further KFS_ReadNext operations may be performed from
that spot in the database.
34
* We mentioned earlier that numeric and alphabetic keys can-
not be combined. However, if you keep in mind that shorts
and longs are stored in byte reversed format, you can form
keys that mix data types. The following code segment com-
bines an alphabetic customer name and a numeric (i.e. long)
customer number into a single key. The customers names
would be in the database in alphabetic sequence, but cus-
tomers with the same name would not necessarily be in
sequence by customer number (customer number 256, stored as
'00010000'x, would be before customer number 255, stored as
'FF000000'x, for example).
#include <kfs.h>
struct DA {
char custname[40];
long custnum;
char morestuff[40];
} myarea;
KFS_FILEINFO myfile;
:
myfile.KFS_keypos = 0;
myfile.KFS_keylen = 44;
:
KFS_Create(&myfile);
35
Data Recovery
Most programmers are familiar with damaged data files caused by
unusual system problems (power failures or system crashes) while
a file is being written to disk. While these problems are rare,
they do occur. The Keyed File System contains code that attempts
to minimize the impact of such a system failure, but this impact
cannot be eliminated completely. Since the Keyed File System
uses two related DOS files (an index file and a data file) to
manage a database, damage to one of these files can cause the
database to become unusable. With a little planning, however, a
programmer can frequently recover a damaged KFS database with
little or no loss of data. To do this requires a little knowl-
edge of the internals of KFS.
The data file that makes up a KFS database is a normal DOS
binary file. That is, each "logical" record is KFS_recsize bytes
long and does not contain a CR/LF at the end of each record.
Thus, these records can be read using operating system or C
language functions just like any other binary file. Addition-
ally, when KFS deletes a record, it is not physically removed
from the data file but only from the .PTR file. However, it is
marked for reuse and a hex 'FF' is placed in the last byte of
the data record when a record is deleted. This hex 'FF' has no
consequence to KFS since deleted records are tracked another way
internally, but can be useful for a programmer wanting to
recover a damaged KFS database by using only the data file. If,
when writing an application, a programmer using the Keyed File
System ensures that the last byte of each data record cannot
normally be hex 'FF', then recovering a KFS database can be
relatively simple. A database recovery program can be written
that simply reads the data portion of the damaged KFS database
as fixed length binary records, checks to ensure the last byte
of each record is not hex 'FF' (remember, hex 'FF' means the
record has been deleted), and uses the KFS_Add operation to add
the record to a new KFS database. At the conclusion of such a
recovery program, the new KFS database would contain all of the
undamaged records that existed in the original KFS database. A
simple example of this technique appears in Appendix B.
36
Appendix A - Keyed File System Return Codes
The following is a list of return codes generated by the Keyed
File System. These definitions are found in the supplied header
file (KFS.H).
KFS_OK (0)
The operation completed successfully.
KFS_Data_File_Open_Error (3)
A bad return code was return from the system when trying to
open the data file of the database.
KFS_EOF (-1)
End of file was reached on the data database during a
KFS_ReadNext. The database remains open and subsequent
keyed operations are allowed.
KFS_File_Error (8)
An unknown error was returned by the operating system.
KFS_File_Already_Exists (9)
You are trying to create a database that already exists in
this directory.
KFS_Invalid_File_Name (1)
The database name requested in KFS_filename is longer than
the 63 characters allowed by the Keyed File System.
KFS_Invalid_Request (11)
You are attempting to do a KFS_ReadGen on a database with
numeric keys. Use a KFS_ReadGenNumeric function instead.
KFS_Key_Already_Exists (4)
A record with the key specified already exists in the
database.
KFS_Key_Length_Invalid (12)
The length of the partial key specified for a KFS_ReadGen
was either 0 or greater than the key length for this data-
base.
KFS_Key_Not_Found (5)
A record with the key specified does not exist in the
database.
KFS_Keyed_File_Empty (7)
When attempting to execute a KFS_ReadFirst operation it was
discovered that the database had no records.
KFS_No_Space_On_Disk (13)
There is no space on the disk containing the KFS database
to add a new record.
KFS_Prior_Key_Not_Found (6)
The key specified as the prior key in a KFS_ReadNext was
not found in the database.
37
KFS_PTR_File_Open_Error (2)
A bad return code was return from the system when trying to
open the pointer file of the database.
KFS_Recordsize_Too_Short (10)
The amount specified in KFS_recsize is smaller than
KFS_keypos + KFS_keylen.
38
Appendix B - File Recovery Example
The following is an example of a C program that could be used to
recover a KFS database. Assume the damaged database had the
following characteristics:
KFS_filename = C:\DATA\MYFILE.DAT
KFS_recsize = 100
KFS_keypos = 0
KFS_keylen = 15
The C program to recover this database could look like this:
main()
{
/* Example of how to recover a KFS file if .PTR is damaged */
FILE *old;
KFS_FILEINFO new;
char dataarea[100];
old = fopen("C:\\DATA\\MYFILE.DAT", "rb");
new.KFS_recsize = 100;
new.KFS_keylen = 15;
new.KFS_keypos = 0;
new.KFS_flags = KFS_Normal_PTR;
strcpy(new.KFS_filename, "C:\\WORK\\MYFILE.DAT");
KFS_Create(&new);
fread(&dataarea, sizeof(dataarea), 1, old);
while(!feof(old))
{
if (dataarea[new.KFS_recsize - 1] != 0xff)
KFS_Add(&new, &dataarea);
fread(&dataarea, sizeof(dataarea), 1, old);
}
fclose(old);
KFS_Close(&new);
}
39