home *** CD-ROM | disk | FTP | other *** search
- .PL
- Aå
-
-
- 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 <stdio.h>
- #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
- Aî