home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d9xx
/
d953
/
isam.lha
/
ISAM
/
ISAM.doc
< prev
next >
Wrap
Text File
|
1993-11-28
|
53KB
|
1,106 lines
===========================================
= ISAM - for the Commodore (R) Amiga (R) =
===========================================
----------------------
| Version : 1.03 |
| Released: 11/28/93 |
----------------------
ISAM Copyright (C) 1992, 1993 Scott C. Jacobs / RedShift Software.
All Rights Reserved. GTDR.
===============================================================================
===============================================================================
== ==
== PROGRAM LICENSE AGREEMENT ==
== ==
== REDSHIFT SOFTWARE DISCLAIMS ALL WARRANTIES RELATING TO THIS SOFTWARE, ==
== WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED ==
== WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ==
== AND ALL SUCH WARRANTIES ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. ==
== NEITHER REDSHIFT SOFTWARE NOR ANYONE ELSE WHO HAS BEEN INVOLVED IN ==
== THE CREATION, PRODUCTION OR DELIVERY OF THIS SOFTWARE SHALL BE LIABLE ==
== FOR ANY INDIRECT, CONSEQUENTIAL, OR INCIDENTAL DAMAGES ARISING OUT OF ==
== THE USE OR INABILITY TO USE SUCH SOFTWARE EVEN IF REDSHIFT SOFTWARE ==
== HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES OR CLAIMS. IN NO ==
== EVENT SHALL REDSHIFT SOFTWARE'S LIABILITY FOR ANY DAMAGES EVER EXCEED ==
== THE PRICE PAID FOR THE LICENSE TO USE THE SOFTWARE, REGARDLESS OF THE ==
== FORM OF CLAIM. THE PERSON USING THE SOFTWARE BEARS ALL RISK AS TO THE ==
== QUALITY AND PERFORMANCE OF THE SOFTWARE. ==
== Some states do not allow the exclusion of the limit of liability ==
== for consequential or incidental damages, so the above limitation may ==
== not apply to you. ==
== This agreement shall be governed by the laws of the United States ==
== of America, State of New York and shall inure to the benefit of ==
== RedShift Software and any successors, administrators, heirs and ==
== assigns. Any action or proceeding brought by either party against ==
== the other arising out of or related to this agreement shall be brought ==
== only in a STATE or FEDERAL COURT of competent jurisdiction located in ==
== Monroe County, New York. ==
== The parties hereby consent to in personam jurisdiction of said courts. ==
== ==
== ==
== This software and the disk(s) on which it is contained is licensed ==
== to you, for your own use. This is copyrighted software. You are ==
== not obtaining title to the software or any copyright rights. You ==
== may not sublicense, rent, lease, convey, modify, translate, convert ==
== to another programming language, decompile, or disassemble the ==
== software for any purpose. ==
== ==
== You may make as any copies of this software as you need for back-up ==
== purposes. You may use this software on more than one computer, ==
== provided that there is no chance it will be used simultaneously on ==
== more than one computer. If you need to use the software on more ==
== than one computer simultaneously, please contact us for information ==
== about site licenses. ==
== ==
== ==
== REGISTERED VERSIONS of this software may NOT be copied (except as ==
== described above for backup), and may NOT be distributed. ==
== ==
== Individuals may freely copy any SHAREWARE VERSION of the software and ==
== share it with friends and family. ==
== Nonprofit groups (including user groups and BBSs) may distribute ==
== copies of the SHAREWARE VERSION. A fee of not more than US$ 5.00 ==
== may be charged to cover disk copying costs. If the files in a ==
== SHAREWARE VERSION have dates more than a year old, we request that you ==
== contact us for a free upgrade to the current SHAREWARE VERSION. ==
== Disk distributors and dealers must have written permission before ==
== selling copies of the SHAREWARE VERSION of this software. When you ==
== contact us, you will receive a free copy of the latest SHAREWARE ==
== VERSION and you will be placed on our mailing list to receive updates ==
== as they are released. ==
== Disk distributors may charge no more than US$ 10.00 per disk for ==
== copies of this software. If, as a distributor, you supply copies to ==
== other resellers, the end price to the user may not exceed US$ 10.00. ==
== ==
== Anyone distributing copies of the SHAREWARE VERSION of this software, ==
== whether for profit or as a nonprofit organization, must conform to ==
== the following: ==
== The files [on each disk] may not be modified or adapted in any way. ==
== All of the files provided [on the disk] must be distributed ==
== together. ==
== Individual files or groups of files may not be sold separately. ==
== Additional files may be added and this software may be combined on ==
== a disk with other programs. ==
== This software may not be represented as anything other than share- ==
== ware, and the shareware concept must be explained in any ad or ==
== catalog that includes this software and on any packaging used to ==
== display the disk. ==
== You must immediatly stop selling/distributing copies of this disk ==
== upon notice from the author or RedShift Software. ==
== ==
===============================================================================
===============================================================================
ISAM FEATURES/LIMITS
--------------------
Multiple Keys
Unique/Repeatable Keys
Multi-"user"
Client/Server Design
Fixed-length Records
File/Record Locking (Exclusive/Shared)
Deleted-record-space reclaimed
Minimal code size used per program
Small server size
Resident Library of functions
Max. Users : 4,294,967,296 ( largest unsigned long + 1 )
Max. Open ISAM Files : 2,147,483,648 ( largest unsigned long / 2 )
Max. Number of Keys : 65,536/file ( largest unsigned word + 1 )
Max. Key Length : 499 Bytes ( Keynode Size - 13 )
Min. Key Length : 1 Byte
Max. Number of Records : 4,294,967,296/file ( largest unsigned long + 1 )
Max. Record Length : 4,294,967,296 Bytes ( largest unsigned long + 1 )
Min. Record Length : 4 Bytes ( used in deleted-record-space
reclamation )
The above maximum figures are of course limited by available disk space
and/or available memory (and CPU horsepower).
If there is an upper limit on the size of a file, then the above maximum
Record Count/Length figures may, of course, be smaller.
REQUIREMENTS:
Any Amiga, AmigaDOS (R) V1.2 or higher.
Any Language that can access Resident Libraries (such as the Amiga system
libraries (Exec/Intuition/DOS/etc)).
Closest fit: users of Lattice (R) C or SAS/C (R).
====
ISAM
====
WHAT IT IS:
ISAM - Indexed Sequential Access Method - is a method of storing records,
for retrieval in any pre-selected order. As its name implies, records
are usually stored sequentially in the DATA File, in the order in which they
are received. A separate file, the INDEX File, is used to store the indices
(usually referred to as "keys") that order the records.
Together, the data and index files are referred to as an ISAM FILE.
A RECORD is a group of related information, stored together. Each piece
of information is called a FIELD of the record. For example: an "Employee"
record in a business might have a field for First Name, a field for Last Name,
one for Phone Number, Address, Annual Salary, Social Security Number, etc.
For all records in a file, the same field is in the same position in each
record.
KEYS are special areas of a record that hold information by which the records
will be ordered (kept sorted). A key is often a single field.
For example: in the above "Employee" record, a likely key would be the
employee's Last Name field; another key might be the Social Security Number.
The employee's First Name, while an important piece of information, would
probably not be made a key.
Keys do not have to correspond to single fields. If our "Employee" had
the Last Name stored before the First Name, a key could span both the Last
Name and the First Name fields. All employees would be ordered as before,
but all those with identical Last Names would themselves be ordered by
First Names. Also, to save space, a key might consist of just a part of a
field. If the Last Name field were 30 characters long, a key might be just
10 bytes long, the first 10 characters of the Last Name.
An ITERATION is a sequence of records retrieved in key order. An iteration
may consist of all of the records in the file, or it may be limited to
records having keys of one key value; it may consist of a RANGE of records
from one key value to another, or all records whose keys begin with a certain
PREFIX.
As implemented, this version of ISAM consists of two main parts: a SERVER and
a RESIDENT (SHARED) LIBRARY. The server is a background program that does the
actual work of storing/retrieving records. All programs that need to store/
retrieve records are separate from the server, and contain only references to
the functions called in the library. The library is small and only contains
enough code to allow communication with the server.
This means that programs using ISAM are no larger than the program object
code itself (not counting, of course, code linked from other libraries).
The ISAM library is only about 7.5K.
The server occupies 54K, plus a 4K stack, plus dynamically-allocated memory
for each task, file, key, iteration, etc.
Multiple programs or tasks (hereafter referred to as "users") may use ISAM
concurrently, and more than one user may have the same ISAM file open at the
same time.
Of course, only one user will have ISAM's attention at any one instant.
Requests that arrive while ISAM is busy will be serviced one at a time,
in the order that they arrive. Most functions return almost instantan-
eously.
Except for record size, and the location and size of each key, ISAM does not
know or care what your record looks like. All non-key areas of a record
are ignored, and the records themselves are stored/retrieved unaltered.
KEYS
----
This implementation of ISAM allows multiple indices (keys). Each of these
may be unique or repeatable. A UNIQUE key only allows each possible key value
to appear once in the file. A REPEATABLE key allows a key value to appear
more than once. Each key may be ASCENDING (... ,57, 59, 67, 67, 108, ...) or
DESCENDING ( ..., Zebra, Talon, Talon, Mussel, Cadillac, Abacus, ...).
A Key may have one of 5 types: integer, floating point, single character, and
two types of text: normal alphbetical order, where case is not significant
("Abacus" is equivilent to "abacus","aBaCuS","ABAcus", and so forth),
and straight ascii, where case is significant. Ascii is useful for non-text
keys as well.
Each key has a location and a size. The location is the byte offset from the
beginning of the record. A key beginning at the start of the record would
have an offset of zero.
Keys are referred to by number. The first key listed in the Specs File (see
below) is key 0, the next is key 1, and so on, up to key N-1 (if there are
N keys).
Keys may overlap each other, partially or completely, and do not have to
correspond to single fields in the record. For instance, a key could span
a date field and a name field for absent students. If the key is ascending,
all students absent on a particular day would be grouped together, and for
that day would be grouped alphabetically (A-Z). A second key could be just
the date, in descending order, so as to order the students from the most
recently absent back to those absent on the first day of school.
NOTE: a key may have only ONE type. A key that spans several fields of
differing types will NOT act as if each part of the key is handled separately.
An ascii type key that spans a floating point number will not order that part
of the key in floating point order.
Spanning multiple fields is generally only workable for text types (including
single character), and unsigned integers or other groups of bytes which
happen to be ordered left-to-right with the most significant byte on the left
(like unsigned integers, if the above description confuses).
Keys cannot contain "holes", cannot contain non-consecutive pieces of a record.
Ex. if a record has the following fields in the order given:
ID SocialSecurityNumber LastName FirstName
there CAN be a key that spans ID and SocialSecurityNumber, but there CANNOT
be a key that contains ID and LastName, without SocialSecurityNumber.
To get around this, one can either rearrange the record to place the fields
necessary for the key next to each other, or if that is impossible because
there is already a key involving one of the fields and a different field,
then one can repeat a field in the record.
Ex. if there is a key on ID/SocialSecurityNumber and a key is needed on
ID/LastName, then add another ID field to the record:
ID SocialSecurityNumber ID LastName FirstName
SPECS FILE
----------
In order for ISAM to be able to manipulate records in an ISAM file correctly,
it must know certain information about the file, records and keys. This
information is stored in a separate specifications file (or SPECS FILE).
One specs file must exist for each ISAM file, and contains the information for
one type of record.
The specs file is an ascii file (use your favorite text editor) with 4 or
more lines in it:
Line #1 : the data file path/name, Ex: "work:finances/checks.data"
2 : the index file path/name, Ex: "FINANCES:checks.index"
3 : the record size, Ex: "126"
4 : one or more key specification lines (one line per key)
FILE PATH/NAME
--------------
No particular file extension is required for either file. ".data" and
".index" are intuitive, but ".harry" and ".sally" would work just the same.
In fact, no extension at all is required. The above files could be
"work:finances/checks0" and FINANCES:checks1" if you like.
It is permissible to have the data and index files (and Specs file) on
different devices. Say: data file on one floppy, and the index on another;
data file on floppy, the index in RAM: (temporarily,
of course...), etc.
It is suggested that logical devices be used for paths. (In the above
examples, we assume that "FINANCES:" has been assigned "work:finances" if
the user wished to keep both the data and index file in the same directory).
If a logical device is used in the Specs file to designate the files' paths,
then should it become desirable to move the file to another location (say,
RAM:, to speed up a lengthy report), all you need to do is re-"Assign" the
logical device, and no editing of the Specs file is needed.
More importantly, if a logical device is used to specify the location of
the Specs file itself in the program code, should it become necessary to
move the Specs file, the program need not be re-compiled and re-linked.
RECORD SIZE
-----------
The record size must be at least 4 bytes. The first four bytes of a deleted
record are used to allow ISAM to locate it so its space may be reclaimed
when a subsequent record is stored.
When figuring record sizes and key offsets (see below), remember that
the system aligns certain data types on even byte boundaries, and thus
record fields may be offset further in the record than expected, and
the record itself may be larger as a result.
C programmers should use the "sizeof()" function to be sure of the record
size (see example below for Key Offset).
KEY SPECIFICATION LINE
----------------------
Each key specification line consists of 5 items, each separated by one or
more spaces:
1 : the key offset
2 : the key length
3 : the key type
4 : whether the key is ascending or descending
5 : whether the key is unique or repeatable
Key Offset
----------
When figuring offsets, remember that integers, floats, doubles and pointers
are aligned on even addresses, so if, for example, an integer appears to
start at offset 3 (after a 3 character string, for example), it doesn't - it
starts at offset 4.
For C programmers, Lattice/SAS C 5.02 and later revisions contain the
macro "offsetof()" in the header "stddef.h". This produces record field
offsets. A small program contining this, along with sizeof() (for figuring
record sizes) and your struct definition, should fairly painlessly determine
the necessary information.
(for those not possessing the above-mentioned file, it contains the following
lines:
-------------------------------------------------------------
typedef unsigned int size_t;
#define offsetof(type,memb) (size_t)&(((type *)0L)->memb)
-------------------------------------------------------------
(where 'type' is the struct type name and 'memb' the struct field the offset
of which you're trying to find).
Example: struct Employee {
int EmpNo;
char Name[31];
float Salary;
char SSNo [11]; /* incl. '-' */
};
...
printf ( "The offset of Salary in the Employee struct is %u.\n",
offsetof ( struct Employee, Salary ) );
printf ( "The size of Employee struct is: %d.\n",
sizeof ( struct Employee ) );
...
See the file "offsetof.c", and try it with one of your records.
Non-C programmers may have to figure record sizes and key offsets "by hand".
Key Length
----------
An integer key can have three lengths: 1, 2, 4.
A floating point key can have two lengths: 4, 8.
A character key can have only one length: 1.
A text/ascii key can be any length (greater than zero)
NOTE: ISAM will know from what is specified here how long the key is;
and will only store/retrieve that length: therefore, text keys
do NOT need an extra byte on the end to store a '\0' (you may,
of course, wish to have one there for other purposes), and there
is no point in including the '\0' byte in the key length, as this
would only result in wasted file space.
Key Type
--------
There are 5 types, each specified by a single letter:
I - integer
F - floating point (float or double) (standard IEEE floating point)
A - ascii (text is case sensitive - "B" is not the same as "b" ).
T - text (text is case insensitive - "B" is the same as "b" )
C - single character (equivilent to type A with length 1 )
Type I should be prefixed by "U" if the integer is unsigned. Do NOT insert
any space between the U and the I.
Keys that are record fields of type: should be designated as:
WORD SHORT LONG int I
UWORD USHORT ULONG unsigned int UI
float double F
char C or A
char[<N>] BYTE[<N>] UBYTE[<N>] T or A
Keys that are record fields of type: may be designated: or: or: or:
BYTE I C A T
UBYTE UI C A T
depending on how they are to be used.
NOTE: any T or A key is considered to consist of individual UNsigned bytes
(UBYTE).
Ascending/Descending
--------------------
There are two possible specification characters:
A - ascending
D - descending
Unique/Repeatable
-----------------
There are two possible specification characters:
U - unique
R - repeatable
Example: If date is a key to a Bank Account Transaction File, it would need
to be repeatable, as otherwise there could be only one transaction
per day.
The account number in the Bank Account File, however, would have
to be a unique key, or several accounts could have the same
account number.
Example Specs File (don't include the dashed lines in your specs files):
----------------------------------------------------------------
FINANCES:checks.data
FINANCES:checks.index
126
0 8 T A R
0 10 T A U
34 4 UI D R
----------------------------------------------------------------
The data file is checks.data, and is on a disk (or logical device) named
FINANCES.
The index file is checks.index, and is on the same disk/device as the data
file.
The record length is 126 bytes.
Key #0 starts at record offset 0, is 8 bytes long, type T, is ascending,
and key values may repeat.
Key #1 also starts at record offset 0, is of length 10, also is type T,
also is ascending, but is unique.
Key #2 starts at record offset 34, is of length 4, is of unsigned integer
type, is descending, and its key values may repeat.
In the above example, the first key line should be your model. The second
and third key lines are included to show that the spacing may vary.
The second key line doesn't start at the first character position of the line
(fine) and the third key line has multiple and varied spacing (great). Note,
however that, as stated above, the U (unsigned) qualifier for the I (integer)
type CANNOT be separated from the type by any spaces.
Note that keys number 0 and 1 (the first and second key lines) overlap.
PAD BYTES: (Note well!)
----------
(ARexx users may probably skip this section, unless the records they use are
also used from C programs, where it most definitely applies. Users of other
languages will have to check their references to see if it applies or not.)
If a key spans several fields in a record, there may be PAD BYTES in the
record between one or more of the fields (due to data alignment, as
described above).
The presence of pad bytes may be determined by finding the offset of each
field included in the key (using offsetof(), as shown above), and comparing
each with the offset/length of the previous field.
If there are pad bytes in the key, be sure to include them when specifying
the key length.
It is possible that, by rearranging the order of the fields in the record,
that pad bytes may be eliminated. This will also reduce the size of the
record, which is always a good idea.
For example, the struct below, which has pad bytes where indicated, could
be rearranged as shown on the right:
struct Employee { struct Employee{
char Name [31]; char Name [31];
<-----pad byte char SSN [9];
float Salary; char Phone [7];
char SSN [9]; char NickName[11];
<-----pad byte float Salary;
int Age; int Age;
char Phone[7]; WORD DaysLate;
<-----pad byte }
WORD DaysLate;
char NickName[11];
}
The pad bytes could also be eliminated by adding or subtracting 1 to the
length of each character array (making each an even number of bytes long).
If re-arrangement is not possible, then along with specifying a longer
key size, the following must also be done:
Each pad byte must be EXPLICITLY SET to a specific value (zero, probably)
each time the key value is set or changed in the record, as otherwise
is is uncertain just WHAT value will be stored there, and if that value
varies from record to record, it will wreck the ordering.
Ex. An ascending key composed of the following fields of a record:
...
char[5] firstname;
int age;
char[4] lastname;
...
would have a pad byte between the first two fields listed.
If two key values have the same first two fields, and a differing
third, their values could look like this:
char[5] int char[4]
------- --- -------
"Henry" 24 27 "Ford"
"Henry" 9 27 "Fork"
Ignoring the pad byte, one would expect the first
key value to be ordered BEFORE the second ("Henry/27/Ford" coming
before "Henry/27/Fork"), but because of the pad byte values,
it will actually be stored AFTER it ("24" coming after "9").
If the struct were changed to:
...
char[5] firstname;
byte pad;
int age;
char[4] lastname;
...
and 'pad' set to zero each time, the ordering would then be as
expected.
Once a specs file is created, the corresponding ISAM file (data and index
files) can then be created. An ISAM file MUST be created before it can be
used. Once the record structure has been decided upon, keys selected, and
specs file edited and saved, invoke the command "CreateISAMFile", with the
specs file as the only parameter (see ISAM.AutoDocs for details).
For an example run-through of the process of creating a record, deciding
what to use as keys, and how to specify the keys in the specs file, see
the last section of the ARexx/ISAM documentation file.
RUNNING THE ISAM SERVER
-----------------------
First of all, make a backup copy of the ISAM distribution disk (or the disk
onto which you copied the shareware file(s), and work with that, putting the
original disk away in a safe place.
NEVER use the original disk of ANY software you purchase as your working
copy!
Since ISAM is a server for the entire computer, it is run only once during
each time the computer has been booted, unless it is intentionally removed.
As the program occupies little memory, it will probably not need to be
removed for that reason.
Also, since it is designed to be run only once, storing it in RAM: prior to
use, or trying to make it resident would only waste memory.
FROM THE CLI / SHELL:
---------------------
The server is the file named simply "ISAM".
From any directory, type: "<path>ISAM" (where <path> is wherever you've got
the server stored - even from a copy of the original floppy disk).
If you put it in the sys:c directory, or if the directory where you have
stored it has been added to the search path (with the AmigaDOS "Path" command),
then specifying a path is unnecessary.
It is also unnecessary if you have changed directories (AmigaDOS "CD" command)
to the directory containing the ISAM file(s).
Ex. "ISAM"
"work:servers/ISAM"
"COMMANDS:ISAM" where COMMANDS: is an assigned logical device (see
the AmigaDOS "Assign" command).
"df0:ISAM" where the backup copy of the original disk is in df0:.
It has been designed to run in the background, so prefacing the command
with "run " is unnecessary.
A large requester will appear describing ISAM, and unless there's a problem,
"ISAM Installed." will appear in the message area. The single button
centered below the message area will contain the word "Continue", unless
there's a problem, when the word "Abort" will appear instead. Press the
button. That's all there is to it.
The CLI/Shell prompt will re-appear (you may need to press <return>, though),
and other commands may then be entered.
(The requester will reappear when the server is being shut down, with the
phrase "ISAM Shutting Down." in the message area.)
If you wish to eliminate the requester that appears when ISAM is being
installed or shut down, simply add a parameter to the "ISAM" command. The
composition of this parameter is ignored. The requester will STILL appear
if an error occurs when installing ISAM.
If the default stack of 4K (4096) should prove insufficient, see "FROM
THE WORKBENCH" below for directions on how to increase it (it CANNOT be
changed from the CLI/Shell). The stack size, and the largest stack amount
used so far are some of the things output from the ISAM Status Report
command/function (see ISAM.AutoDocs).
To remove ISAM, type: "<path>ISAMShutDown", where, as above, <path> is
wherever the program is stored. A small requester will appear, giving
you a chance to abort the shutdown. Click on "NO" to abort, "YES" to
shut down ISAM. To eliminate the "Are you sure..." requester, add a
parameter to the above command (the composition of the parameter is ignored).
FROM THE WORKBENCH
------------------
Open whatever drawer in which you have the ISAM server stored (or the
disk icon of a copy of the original disk). Several icons will appear.
Open the "ISAM" icon. The same requester described in "FROM THE CLI" will
appear, and the same action is required.
To remove ISAM, open the ISAM icon that has "ISAM" with a "no smoking"-type
slash across it. The same requesters described in "FROM THE CLI" will
appear, and the same actions are required.
To change the stack size, it is necessary to first select the ISAM icon, and
then choose the "Information" Workbench menu item. This must be done before
installing ISAM in memory.
If you wish to eliminate the requester that appears when ISAM is being
installed or shut down, add "QUIET" to the tooltypes box (click on "New",
type the word "QUIET", press <return>, and click on "Save"). The requester
will STILL appear if an error occurs when installing ISAM.
To change the stack size, find the box next to the word "Stack", change it
to the desired size, press return, and then click on the "Save" gadget.
If you find (through using the ReportISAMStatus command/function) that the
stack used figure is close to the stack size, then you know that you need
to increase the stack size.
Setting it too low can cause the machine to crash, either immediately upon
installation, or later during a complicated operation. This is true of
any program, not just ISAM.
USING THE ISAM FUNCTIONS
------------------------
In general, the programmer need only:
1.* #include the prototype header file for the ISAM functions (this
also pulls in the error #define file for the error names, and the
file of function #pragmas);
2. Copy the Resident Library ("isam.library") to the system LIBS:
directory; ARexx users need to do the same with the
"rexxisam.library" file.
3. Open the ISAM Resident Library prior to using any ISAM functions;
ARexx users: follow the instructions in RexxISAM.doc.
4. use whatever ISAM functions are necessary in the program;
5. Close the ISAM library when finished using the ISAM functions.
ARexx users: follow the instructions in RexxISAM.doc.
Any C dialect that cannot handle prototypes with variable names should use the
prototype file ending in "nn.c" (NoNames). If it cannot handle prototypes at
all, just use the error-define file, and add to it the #defines for OK and
ALLFILES from the prototype file.
If your language cannot handle #pragma statements, or cannot handle #pragmas
for functions with more than 4 parameters, then comment out the line in the
prototype header file #include'ing the #pragma file, and add the file
"ISAMStub.Lib" to the list of libraries your linker scans.
The prototype file uses the Logical Device "MYLIB:" in pulling in #include
files for errors and #pragmas. Either "Assign" it where you want, or replace
it with your accustomed assign.
* Non-C programmers will need to adapt these guidelines, and the instructions
that follow, to the way their language handles defined names, and Resident
Libraries. Assembler programmers should put the similar .i files wherever
they usually store include files. ARexx users may ignore #1.
FUNCTION COMMENTS
-----------------
(See ISAM.AutoDocs for a description of the functions and their parameters.)
- Most functions return values of type "long". The value 0L (#define
name "OK") is returned to indicate a successful completion, and a non-
zero result for failure. These non-zero Error Codes are sometimes
merely Condition Codes. For example, ReadNextISAMRecord returns
ERROR_NO_MORE_RECORDS when there are no more records in an iteration,
a condition expected to occur eventually.
The error codes returned are usually ISAM error codes (see the file
ISAMErrors.doc, and the function/command ISAMWhy), but not always.
If the error code returned is not an ISAM error, then it is probably
a DOS error. Use the AmigaDOS "fault" command to get a handle on why
the function failed. For example: if you specify the name of a specs
file to OpenISAMFile, and the file does not exist, you will receive
the error 205, which is DOS's ERROR_OBJECT_NOT_FOUND.
For most Non-Read functions, the following is a good template to use:
if ( (ErrorCode = <function_name> ( <parm1>, <parm2, ...)) != OK )
{
...error handling code...
}
For read/store/modify/etc., where there are multiple likely condition
codes, a switch makes more sense:
ErrorCode = <function_name> ( <parm1>, <parm2, ...);
switch ( ErrorCode )
{
case ERROR_NO_SUCH_RECORD : ...for ReadUnique...
case ERROR_DELETED_RECORD : ...for Modify/Delete/ReadISAMRecord
...etc...
case OK : break;
default : ...handle unexpected errors here...
}
See FileConvert.c, test.c, and Books.c in the example directory
for sample code.
- The ISAM Resident Library must be opened prior to any call to an
ISAM function. Failure to do this will cause AT LEAST the program
to crash.
The Library must be closed prior to your program's termination.
Use the following code fragments (in C):
struct Library *ISAMBase;
...
if ( (ISAMBase = OpenLibrary ( "isam.library", 0 )) == NULL )
{
...handle error - library didn't open - CAN'T CALL FUNCTIONS...
}
...
CloseLibrary ( ISAMBase ); /* ONLY if the earlier Open succeeded */
NB: "ISAMBase" and "isam.library" are CASE-SENSITIVE, and MUST be
used as shown.
- OpenISAMFile / CloseISAMFile. OpenISAMFile must be called prior to
use of any other ISAM function that needs to access a particular file.
Open creates certain user-specific file memory structures that Close
later releases. If a file being opened is not already in use (by
another user), other (non-user-specific) memory structures are created,
and if no other user has this file open when Close is called, those
structures are released as well.
- Every function that is ISAM-file-specific (that is, operates on one
specific ISAM file), must supply an ID that distinguishes that file
from other files.
This ID is known as an ISAM Handle, and is returned to you as a
parameter of OpenISAMFile. The actual contents of this handle are
unimportant. Just create a variable to hold the handle, and provide
a pointer to it when calling Open.
The ISAM Handle returned will never be zero (0L).
- Every function that deals with a specific record refers to a record ID
known as the Record Number. StoreISAMRecord returns this number in
a parameter (as does ReadNextISAM(Record|Key)), and the other record-
specific functions (including ReadISAMRecord) require this number to
be supplied as a parameter.
Zero (0L) is a valid record number.
- Records may be read in several ways. Single records may be read by
ReadISAMRecord or ReadUniqueISAMRecord. Groups of records are read by
first calling one of three functions used to set up an ISAM ITERATION
(multiple-record retrieval). This is then followed by repeatedly
calling the function ReadNextISAMRecord until no more records match
the desired criteria.
- The "Record" parameter, in all Read functions, points to memory
belonging to the calling program. It is NOT a pointer to memory that
ISAM owns. The calling program must set aside the memory itself, either
as a simple variable declaration, or as memory the program has asked
DOS to allocate for it. In effect, the program calling Read is saying
"HERE is where I want ISAM to put the record."
- The function CountISAMRecords will return the number of records that
meet the criteria defined when an iteration is set up. The iteration
remains set up ("SetUp..." does not need to be called again.).
- The function ReadNextISAMKey will return ONLY the KEY VALUE of the
next record - not the record itself. This is useful for those cases
when the key information alone is sufficient, and the rest of the
record is not currently needed. Like ReadNextISAMRecord, the KeyValue
parameter is a pointer to memory belonging to the calling program.
- Setting up an iteration for the same key where one is already set up
is NOT considered an error. The old iteration is merely cancelled,
and the new one set up in its place.
- Several iterations on the same file may be going on at the same time,
so long as each is iterating on a different key.
- When an iteration is underway, (in the middle of repeatedly calling
ReadNext...), do NOT Store/Modify/Delete any records, and do not
ReadUnique with the same key that the iteration is using. This
will destroy the sequence you have set up.
Creating/ReIndexing/Deleting/Closing the same file are obviously
bad ideas if you want to keep the iteration intact.
Calling GetFirstLastISAMKeyValues is also out.
Other operations should be safe, including ReadISAMRecord.
- The ISAM Server does the actual opening and closing of the data
and index files when a request to Open/CloseISAMFile is made.
Therefore, Opening an ISAM file does NOT add to any "maximum files
open" limitation of the program calling ISAM.
- A record is always stored/modified/deleted in the data file BEFORE
its keys are added/removed to/from the index file. This is done
because, there being more operations necessary to store keys, (and thus
more time needed as well), it is more likely that if a problem occurs,
it will happen during the key-storing phase. Since the record is
already stored (or deleted), ReIndex'ing the file should be all that
is necessary to restore things to normal.
- When a program ends, explicitly UnLock'ing locked records, and
UnLock'ing/Close'ing open files is NOT necessary.
Any records locked by the program will be UnLock'ed when their file is
Close'd, and any open files will be UnLock'ed/Close'd when the program
calls CloseLibrary. If a program may end without traversing the
section of code where CloseLibrary is situated, it is suggested that
an exit trap be set up (if one isn't already) and the CloseLibrary
call inserted there.
- When ISAM is shut down, all Open files will be UnLock'ed and Close'd
(so if any program bombs without calling CloseLibrary, all will be
taken care of when ISAM shuts down).
Any user functions still waiting in line to be served will return with
ERROR_ISAM_SHUTTING_DOWN.
- CountISAMRecords, DeleteISAMRecords, and ReIndexISAMFile, unlike most
other ISAM functions, do not return "instantaneously."
It is therefore STRONGLY recommended that they be forbidden where there
are simultaneous users, as all other users will appear to "hang" while
the function executes. Count... may be rendered safer by using
CountMax, but even for a reasonably small file, some delay is
inevitable.
- ReIndexISAMFile CANNOT be used to effect a change of record size or
structure (fields moved, added, or removed). To do that, a new ISAM
file must be Created with the new specifications (make SURE the data
and index file names are DIFFERENT in the new specs file!). Then, a
file conversion program must be written to transfer the old ISAM file's
records to the new file. This can be easily done by the following
technique:
Open the old ISAM file and the new ISAM file;
ReadISAMRecord the old file's records sequentially; copy
the old record information to the new record, make any
changes needed to the new record, and StoreISAMRecord the
new record to the new file; Close both ISAM files; Once ASSURED of
a successful conversion, the old file may be Deleted.
FileConvert.c is a template file showing in more detail how
the above technique may be done.
ISAM COMMANDS
-------------
The following commands, except where noted, require the SpecsFileName to be
entered on the command line, just as a string containing the SpecsFileName
is required as a parameter for the function.
Except where noted, where FUNCTIONS of the same name exist, the commands
accomplish the same thing, and require the same input.
The commands may be found in the "c" directory of the distribution disk/file.
If using a version of AmigaDOS prior to 2.0x, the commands MUST be entered
from the CLI/Shell. If 2.0x (or later) is used, the commands may also be
run from the Workbench: when you Open the tool icon bearing the name of
the desired command, a window will open allowing you to enter the command
and parameters just as if you were entering them from a CLI/Shell. Anything
that would ordinarily be printed in the CLI/Shell, will be re-directed to
an "Output Window." If there is a lot of information to print, it may scroll
off the window. If that is the case, it is recommended that the output be
redirected to a file (or printer), so that the file may be later viewed in
its entirety with a text editor or wordprocessor.
(To be able to view the tool icons of the c directory with Workbench 2.0x
(or higher), the menu option "View By: Icon"/"Show: All Files" must be
selected for the open "c" directory (drawer).)
These commands are not "sacred." Except for ISAMFileReport, they merely
call the associated ISAM function from the library, perhaps after doing some
preliminary setup, and print messages regarding the status of the function
return. If you don't like one or more of the commands, just write your own
(even using ARexx, with version 1.03), replacing the commands provided.
Add your own (new) commands, as well... A command could be written that
would prompt the user for information needed for the Specs File, and would
then create the Specs File from that information.
DeleteISAMFile -
CreateISAMFile -
ReIndexISAMFile
- The presence or absence of a second parameter (one
following the SpecsFileName) determines whether a Counter
window will be displayed or not. The actual composition
of this second parameter is ignored.
ISAMFileReport -
This program looks at the Specs and Index file and reports
on the vital statistics of the ISAM file in question: names
of data and index files, the record size, record count
keycount, and the key offset/size/type/etc. for each key.
It also reports on whether there are currently deleted
records in the file.
This command does not require ISAM to be installed to work.
ISAMWhy - ALL | ErrNo [,ErrNo [,ErrNo [,ErrNo...]]]
If 'ALL' is entered on the command line, a list of all ISAM
error numbers, along with #define strings, is typed to
the console. Re-direct this command to a file or printer
for a permanent list.
The command also accepts multiple error numbers on the
command line, printing a descriptive line for each.
This command does not require ISAM to be installed to work.
SeqToISAM - <Sequential File Name> <record size>
a record-sequential file (a file in which fixed-size records
are stored one after the other, with nothing in between)
is modified to the ISAM data file format (a single byte is
added prior to each record).
Any record whose first four bytes are "FREE" will be marked
as deleted. (ISAM will later reclaim their space as records
are subsequently Store'd).
The modified file will be stored under the given name with
".NEWFILE" appended. The record-sequential file will be left
unchanged.
This command does not require ISAM to be installed to work.
ISAMPresent - <suppress message>
This program is designed to be used in a script file.
Since ISAM is a background process (and would be unlikly
to be shut down in any case), it does not have a return code.
However, it is still necessary to know if ISAM is "out there"
in order to run programs that require its presence.
Therefore, the program ISAMPresent may be used to determine
ISAM's presence/absence.
The message: "ISAM is present" (or "not present") will be
printed. Return Code '5' will be returned if it couldn't
find ISAM, and return code '0' if it does.
Ex: ISAMPresent q
if WARN
echo "Uh-oh! ISAM is not installed."
quit
else
prog1
prog2
...
endif
The message will be suppressed if there is a parameter
present on the command line. The actual composition of the
parameter is ignored.
This command does not require ISAM to be installed to work.
Obviously.
ReportISAMStatus
-
NOTES ON FILE/RECORD LOCKING
----------------------------
ISAM files and individual records may be locked to limit or deny access to
other users; a file may be locked at the time it is opened, and a record at
the time it is read or stored, and either may be done at any other time as
well.
Locks come in two "flavors": exclusive and shared. If a file is locked with
an exclusive lock, neither it nor any of its records may be read, changed,
or locked by another user. Likewise, an individual record locked with an
exclusive lock may not be accessed by another user.
A file that is locked with a shared lock may be read by another user, but not
changed or locked. Records that are locked with a shared lock (and records
in a file that is shared locked) likewise may only be read, not changed.
For our purposes, "change" includes attempting to modify or delete an exist-
ing record, or store a new one.
DEADLOCK
--------
Since files and records may be locked, the situation may occur that two differ-
ent users having different files/records locked may each request something
that the other has locked. If each keeps trying until it gets what it wants,
they will each wait forever. This is known as deadlock. There are three
strategies that will help avoid deadlock.
First, instead of continuously looping until the request is (or in this case,
isn't) granted, back off. Inform the user that the record/file desired is
locked and to please try again later. The user then may wait, do something
else, end the program, etc. He isn't dead in the water. Secondly, if several
programs each use two or more of the same ISAM files, make sure that they all
attempt to open them in the same order: A then B then C. This way it is im-
possible to deadlock: Program 1 opens/locks A and B; Program 2 then tries to
get A and fails. True, he is locked out of A, BUT he doesn't have anything
locked himself - so deadlock cannot occur. Even if he has a try-until-succeed
loop, it's not deadly. Program 1 will eventually quit and he will then succeed.
Thirdly, any time you get a lock error, unlock EVERYTHING you've got locked
and begin over. This avoids deadlock, but is often difficult (not to mention
time-consuming) to code.
Strategy 2 is often not practical for Record locking (different programs may
use different keys to get at the same records - hence different orders).
Remedy 1 or 3 would then be better bets for record-locking.
EXAMPLES
--------
TEST
----
The file "test", in the examples subdirectory, is a test program showing
the use of most of the ISAM functions in manipulating the ISAM file
"Employee". (Employee is found in the data subdirectory).
Test may be run from the Workbench only with AmigaDos 2.0x or higher
("show all files" and open the tool icon "test". You'll need to enlarge
the Output Window). Otherwise the CLI/shell must be used. There
are no parameters.
The source code for test (test.c) is included for C-language programmers,
to show sample function calls and error/condition code handling.
Feel free to change it and/or snip bits of it for your own use.
Non-C-programmers should find it useful as well, although obviously any
code appropriated will need to be modified to fit the constraints of their
language.
Prior to running test, the Logical Device "DATA:" will need to be assigned
to wherever the specs/data/index files for Employee have been stored.
The locking/unlocking features can only be tested if test is run from more
than one CLI/shell simultaneously (since obviously the user locking the file/
records may access the files/records he/she locked).
BOOKS
-----
The file "Books", in the examples subdirectory, is a working application that
allows the user to keep an inventory of his books, and to list those books
in many different orders (8 actually; applications would not ordinarily have
8 keys on the same file, but Books does!).
Books operates on the ISAM file "Books", located in the data subdirectory.
Like test, Books needs to have the logical device "DATA:" assigned.
The source code for Books is included as well, and may be appropriated for
your own use, just like "test".
-------------------------------------------------------------------------
Amiga is a registered trademark of Commodore-Amiga, Incorporated.
AmigaDOS is a trademark of Commodore-Amiga, Incorporated.
Commodore is a trademark of Commodore Electronics Limited.
ARexx is a trademark of Wishful Thinking Development Corp.
Lattice is a registered trademark of Lattice, Inc.
SAS/C is a registered trademark of SAS Institute Inc.