Dec 132017
 
Turbo-C ISAM rtns. What more could you want ?.
File TCISAM.ZIP from The Programmer’s Corner in
Category C Source Code
Turbo-C ISAM rtns. What more could you want ?.
File Name File Size Zip Size Zip Type
ADR.C 6681 1830 deflated
ADR.MAK 168 112 deflated
ADR.PRJ 29 26 deflated
ARCIT.BAT 128 72 deflated
IDELETE.C 6400 1505 deflated
INAMES 128 52 deflated
INDEX.DOC 22400 6172 deflated
INDEX.H 1478 589 deflated
INDEX.LIB 8907 3556 deflated
INDEX.MAK 522 201 deflated
INXDEFS.H 3153 975 deflated
INXRTNS.C 10828 2090 deflated
IOPEN.C 3911 1207 deflated
IREADN.C 1674 732 deflated
IREADP.C 1653 730 deflated
IREADR.C 1002 532 deflated
IREWRITE.C 1378 635 deflated
ISTART.C 3041 928 deflated
IWRITE.C 4836 1430 deflated

Download File TCISAM.ZIP Here

Contents of the INDEX.DOC file


.PL
A2



INDEX.DOC Version 1.01 August 21, 1987
Page 1

This documentation and the software it describes are Copyright 1987, Jim
Mischel. You are free to use this software providing that the following
conditions are met:

1) Any distributed versions contain the my copyright notice and are
accompanied by documentation and source code. The package doesn't do
anybody any good if they don't know how to use it.
2) You notify me before using it in any commercial application. I won't
ask for any money, I'd just like to know about it. Also, if you
notify me I may be able to get you a current version and/or notify
you of any bug fixes.

This package was developed using Turbo C version 1.0. It should port to other
compilers and operating systems with very little modification.

Questions, comments, problems should be addressed to Jim Mischel, CIS id
number 73717,1355. I regularly visit BORPRO, CLMFORUM, and DDJFORUM. I'd be
more than happy to reply to inquiries.


INDEX.DOC Version 1.01 August 21, 1987
Page 2
DESCRIPTION

INDEX is a collection of routines designed to provide single-key indexed file
access to C programs. They are modeled after the ISAM features supplied in
standard COBOL implementations, with some additions. Keys can be of any type,
including float, double, and user-defined key types.

This version of the package uses a threaded binary tree to maintain the index.
This may change in future versions. I chose the threaded tree because it is
relatively simple to implement, uses little memory, and is acceptable for
small and medium-sized data sets. It is not the fastest method available, and
I make no claims as to the speed of record access, though it should be
acceptable. Currently, no balancing is performed when adding or deleting
records from the file. In many cases, this can result in a severely un-
balanced tree and horribly slow access times. I am currently working on
adding the tree balancing routines.

Following are descriptions of the user-accessable routines. These are the
only routines that should be called by applications programs. Calling other
routines in the package will produce unpredictable results and could very
possibly destroy the database.

The examples provided build on previous examples. For example, the example
used with iclose() uses data types defined in the example provided with
iopen().


INDEX.DOC Version 1.01 August 21, 1987
Page 3
IOPEN - open a file for indexed I/O

void *iopen(char *fname, unsigned recsiz, char keytyp, unsigned offset,
char dupflag, int (*cmp_rtn)());

iopen opens an indexed file for reading/writing. If the file to be opened
does not exist, iopen attempts to create it. Upon successful completion,
iopen will return a pointer to an index control record. This pointer should
not be modified by the application program, nor should the fields in the index
control record be changed by the application. The data in the record is used
by the index routines and is at best marginally useful to the application.
Modifying either the returned pointer or the data pointed to will produce
unpredictable results and could very likely make the database unuseable. If
iopen can not open the file, NULL is returned and the global variable ierrno
is set to identify the cause of the error.

Arguments passed to iopen()

fname A string containing the name of the file to be opened. This
name should be without an extension. iopen will append the
extension '.DAT' for the data file and the extension '.INX' for
the index file.

recsiz Size of the data record in characters.

keytyp The type of key. Standard key types supplied in the header
file, INDEX.H are:

UCHAR unsigned character key
SCHAR signed character key
UINT unsigned int key
SINT signed int key
ULONG unsigned long key
SLONG signed long key
STRING string key (ASCIIZ)
FLOAT float key
DOUBLE double key

The last two key types (FLOAT and DOUBLE) are available only if
INDEX.C was compiled with the FLOAT_KEY option. This prevents
the floating point libraries from being included unless they
are needed.

If the key for this file is not one of the above types, use 0
for keytyp and pass the name of the key comparison routine in
the cmp_rtn field.

offset The offset (in characters) from the beginning of the record to
the first byte of the key.

dupflag Controls whether duplicate keys are allowed. If dupflag is 0,
duplicate keys are not allowed, and an attempt to add a
duplicate key will return an error (see error codes below). If
dupflag is 1, duplicate keys will be allowed.


INDEX.DOC Version 1.01 August 21, 1987
Page 4
IOPEN - open a file for indexed I/O

cmp_rtn Is a pointer to a user-defined key comparison routine. If the
key is one of the standard key types, this field should be
NULL. If this field is not NULL, iopen will use this as a
pointer to a user-defined key comparison routine. The
declaration of the routine should be:

int routine_name(void *arg1, void *arg2);

This routine accepts pointers to the operands and returns
-1 if arg1 < arg2
0 if arg1 == arg2
1 if arg1 > arg2

Example:

#include
#include "index.h"

main (int argc, char *argv[]) {

struct {
char first_name[25],
last_name[25];
} name_rec;

char *name_file; /* pointer to control record */
unsigned offset;

offset = &name_rec.last_name - &name_rec; /* compute key offset */
if ((name_file = iopen(argv[1],sizeof(name_rec),STRING,offset,1,NULL) == NULL)
{
printf("Error opening file %s\n",argv[1]);
printf("Error code is %X\n",ierrno);
return;
}


INDEX.DOC Version 1.01 August 21, 1987
Page 5
ICLOSE - close files and free memory

void iclose(void *db_control);

iclose closes the index and data files assigned to the index control record,
and frees the memory used. iclose does not return status.

IMPORTANT NOTE:
All files opened with iopen that have had records added or deleted MUST be
closed with iclose. Failure to do so may result in losing data or destroying
the integrity of the index file.

Arguments passed to iclose()

db_control The pointer returned when the file was opened by iopen.


Example: (building on the one above)

iclose(name_file);


INDEX.DOC Version 1.01 August 21, 1987
Page 6
IREAD - read a record from the file

int iread(void *db_control, void *destin);

iread reads a record and places it in memory at destin. iread assumes there
is sufficient space at destin to hold the entire data record. Place the key
value to be searched for at the key position in the record at destin and call
iread. iread returns 0 if the record was found, I_NOREC if not, and error
status if there was an I/O error. On error conditions, the data at destin is
not changed. Using iread does not change the pointer used by the sequential
read functions iread_next and iread_prev.

Arguments passed to iread()

db_control The pointer returned when the file was opened by iopen.

destin A pointer to the structure that will receive the data record.

Example:

name_rec.last_name = "Mischel";
if (iread(name_file,&name_rec)) {
printf("\007Record key %s not found in file %s\n",
name_rec.last_name,argv[1]);
printf("Error code is %X\n",ierrno);
}
else
printf("Record found\n");


INDEX.DOC Version 1.01 August 21, 1987
Page 7
ISTART - position file for sequential access

int istart(void *db_control, char cond, void *source);

istart positions the file pointer for sequential file access. This function
must be called before attempting to sequentially access the file through
iread_next or iread_prev. Place the key value to be searched for at the key
position in source and call istart. No data is transferred by this function.
istart will return 0 if the file pointer was positioned successfully, EOF if
no record meeting key and cond could be found, and one of the standard error
codes on error.

Arguments passed to istart()

db_control The pointer returned when the file was opened by iopen.

cond One of the conditions defined in INDEX.H:

START_FILE Start at beginning of file, source is ignored
LT Start at the key less than the key in source
LE Start at key less then or equal to key in
source. If a record exists with key, it will
start there.
EQ Start at key equal to the key in source.
GE Start at key greater than or equal to key in
source. If a record exists with key, it will
start there.
GT Start at key greater than key in source.
END_FILE Start at end of file. This is useful for
reading the entire file backwards.

Example:

/*
* to position the file at the first record with a key greater than or equal
* to Sm.
*/
name_rec.last_name = "Sm";
if (istart(db_control,GE,&name_rec)) {
printf("Couldn't position file\n");
printf("Error code is %X\n",ierrno);
}
else {
/*
* read the file sequentially forward or backward. See examples for
* iread_next and iread_prev.
*/
}


INDEX.DOC Version 1.01 August 21, 1987
Page 8
IREAD_NEXT - Sequentially read the next record

int iread_next(void *db_control, void *destin);

Read the next record in sequence into destin. iread_next assumes there is
room in destin for the entire record. Returns 0 if successful, EOF at end of
file, standard error code on error. On error conditions, the data at destin
is not changed.

Arguments passed to iread_next()

db_control The pointer returned when the file was opened by iopen.

destin A pointer to the structure to receive the data record.

Example:

/*
* read the file sequentially forward (assuming it was started as above)
*/
while (!iread_next(db_control,&name_rec))
printf("%s %s\n",name_rec.first_name,name_rec.last_name);


INDEX.DOC Version 1.01 August 21, 1987
Page 9
IREAD_PREV - sequentially read the previous record

int iread_prev(void *db_control, void *destin);

read the previous record in sequence into destin. Assumes there is room in
destin for the entire record. Returns 0 if successful, EOF at top of file,
standard error code on error. On error conditions, the data at destin is not
changed.

Arguments passed to iread_prev()

db_control The pointer returned when the file was opened by iopen.

destin A pointer to the structure to receive the data record.

Example:

/*
* read the file sequentially backward (assuming it was started as above)
*/
while (!iread_prev(db_control,&name_rec))
printf("%s %s\n",name_rec.first_name,name_rec.last_name);


INDEX.DOC Version 1.01 August 21, 1987
Page 10
IWRITE - add a new record

int iwrite(void *db_control, void *source);

Write the record from source to the data file. Data records are always added
to the end of the file. Returns 0 if successful, I_INVKEY if duplicates are
not permitted and an attempt was made to add a duplicate record, standard
error code otherwise.

Arguments passed to iwrite()

db_control The pointer returned when the file was opened by iopen.

source A pointer to the structure to be written.

Example:

name_rec.first_name = "Jim";
name_rec.last_name = "Mischel";
switch (iwrite(db_control,&name_rec)) {
case 0 :
printf("Record written\n");
break;
case I_INVKEY :
printf("Duplicate key %s\n",name_rec.last_name);
break;
default :
printf("Write error. Error code is %X\n",ierrno);
}


INDEX.DOC Version 1.01 August 21, 1987
Page 11
IREWRITE - update an existing record

int irewrite(void *db_control, void *source);

Update the current record in the file. The record must have been read using
one of the read routines, or written using iwrite, and must still be in the
buffer. It is not possible to change the key using irewrite. Use idelete to
remove the record and iwrite to add the record after the key has been changed.
Returns 0 on success, I_INVKEY if attempt to rewrite a record that isn't in
the buffer, standard error code otherwise.

Arguments passed to irewrite()

db_control The pointer returned when the file was opened by iopen.

source A pointer to the structure to be written.

Example:

/* first we have to read the record */
name_rec.last_name = "Smith";
if (iread(name_file,&name_rec)) {
printf("\007Record key %s not found in file %s\n",
name_rec.last_name,argv[1]);
printf("Error code is %X\n",ierrno);
}
else {
name_rec.first_name = "John";
switch (irewrite(db_control,&name_rec)) {
case 0 :
printf("Success\n");
break;
case I_INVKEY :
printf("Invalid rewrite attempted\n");
break;
default :
printf("Rewrite error. Error code is %X\n",ierrno);
}


INDEX.DOC Version 1.01 August 21, 1987
Page 12
IDELETE - delete a record

int idelete(void *d, void *source);

Delete the record currently in the buffer. Record must have been read using
one of the read routines, or written using iwrite, and still be in the buffer.
Returns 0 on success, I_INVKEY if attempt to delete a record that isn't in the
buffer, standard error code otherwise.

When a record is deleted, it is not removed from the data file and its index
pointer is not removed from the index file. What happens is that the index
pointers are re-arranged to point past the deleted record. This has at least
two major side affects:
1) If the data file is scanned by a program that doesn't use the index
routines, deleted records will be picked up along with current records.
2) In a file that has a large turnover rate, there will be a considerable
amount of wasted space taken up by the deleted records.
The next version of the package will include a rebuild() function that will,
among other things, remove deleted records from a data file. This program
will fix the second problem. The first problem can be solved in one of two
ways:
1) Add a flag to the data record to indicate it is deleted. Your program
will have to manipulate this flag, setting it before the record is
deleted.
2) Wait for the next version of the package. By using the rebuild()
function before scanning the file, you're guaranteed not to have any
deleted records.

Arguments passed to idelete()

db_control The pointer returned when the file was opened by iopen.

source A pointer to the structure containing the key name to be
deleted.


INDEX.DOC Version 1.01 August 21, 1987
Page 13
IDELETE - delete a record

Example:

/* first read the record */
name_rec.last_name = "Smith";
if (iread(name_file,&name_rec)) {
printf("\007Record key %s not found in file %s\n",
name_rec.last_name,argv[1]);
printf("Error code is %X\n",ierrno);
}
else {
switch (idelete(db_control,&name_rec)) {
case 0 :
printf("Record deleted\n");
break;
case I_INVKEY :
printf("Invalid delete attempted\n");
break;
default :
printf("Delete error. Error code is %X\n",ierrno);
}


INDEX.DOC Version 1.01 August 21, 1987
Page 14
ERROR CODES

The global variable ierrno will contain the results of the last I/O operation.
Possible values are:

Code Value Description
---- ----- -----------
I_NODAT 0x10 - couldn't open data file (iopen)
I_DATRD 0x11 - I/O error attempting to read data file (any)
I_DATWT 0x12 - I/O error attempting to write to data file (any)
I_NOINX 0x20 - couldn't open index file (iopen)
I_INXRD 0x21 - I/O error attempting to read index file (any)
I_INXWT 0x22 - I/O error attempting to write to index file (any)
I_INVKEY 0x80 - Attempt to add duplicate key (iwrite)
Attempt to rewrite deleted record, or record not in buffer
(irewrite)
Attempt to delete deleted record, or record not in buffer
(idelete)
I_NOMEM 0x81 - out of memory (iopen)
I_NOREC 0x82 - record not found (iread)


INDEX.DOC Version 1.01 August 21, 1987
Page 15
NOTES

I have included a sample program that illustrates the use of several of the
routines in this package. The program, ADR.C, is a simple address/phone book
that is marginally useful as a real application, but does show how to use the
routines.

MAKE FILE
I have included a make file that can be used to re-compile the package. This
file uses the QLIB program to create the library INDEX.LIB. The QLIB program
is available on BORPRO DL 11. The library supplied with the package is a
TLINK compatible library and is not compatible with Microsoft's LINK.

KNOWN BUGS

There are some possible conflicts when using sequential and random I/O at the
same time. These will only occur when adding or deleting records while
sequentially scanning the file. In general, the only problems involve
deleting a record that is to be the next one read, or adding a record between
the current and next records. In the delete case, the deleted record will
still be read, and in the add case, the new record will not be read. The next
release should fix these problems.

REVISION HISTORY

This package started as a "I wonder how that's done" type of project. The
original program used a primitive hashing algorithm to store and retrieve the
keys. The program (written in Pascal) did work, but was a terrible kludge and
I threw it away. The current version was written for two reasons: 1) I
wanted to learn C, and 2) I needed something like this for a project I was
planning.

Version 1.00 August 13, 1987
Original release version.

Version 1.01 August 21, 1987
1) Fixed bugs in iwrite() and irewrite() that prevented the data buffer
from being updated when the record was written. This bug caused
irewrite() and idelete() to erroneously return I_INVKEY.
2) Updated documentation. Added examples and cleaned things up quite a
bit.
3) Split the package into multiple source files and added a make file
that creates a Turbo C compatible library.
4) Add calls to fflush() in the write routines. This slows things down a
bit (a lot?), but does help keep data file integrity.


INDEX.DOC Version 1.01 August 21, 1987
Page 16
NOTES

Files that make up the index package

ADR.C - demonstration program for index package
ADR.MAK - make file for ADR
ADR.PRJ - project file for ADR
ARCIT.BAT - batch file to build the archive
IDELETE.C - delete record routine
INAMES - name file for QLIB program
INXRTNS.C - support functions for index package
INDEX.DOC - index documentation, rough but useable
INDEX.H - header file included by application programs
INDEX.LIB - index routines library (useable only by TLINK, not by MS LINK)
INDEX.MAK - make file for index routines
INXDEFS.H - header file for index routines
IOPEN.C - open and close functions
IREADN.C - readnext function
IREADP.C - readprevious function
IREADR.C - read random function
IREWRITE.C- rewrite (update) record function
ISTART.C - start function
IWRITE.C - write record function
A2


 December 13, 2017  Add comments

Leave a Reply