RDM-F77 Interface Manual by Walt Shpuntoff & Warren Lamb Institute for Resource Management, Inc P.O. Box 869 Arnold, MD 21012 (301) 757 - 6503 RDM is a trademark of Interactive Technology, Inc. TSX-Plus is a trademark of S & H Computer Systems, Inc. This document describes how to use the F77 interface subroutines that make it possible to read and write RDM database file records from an F77 application. It is assumed that if you attempt to use these routines, that you already have an understanding of both RDM and Fortran. o The routines allow you to retrieve and write back out active records. o Records can be Added to a file does not contain Indexes. o Records can NOT be deleted. o Records up to 512 Bytes are supported o The retrieval routines will NOT Perform Any Data Type Conversions The F77 subroutines that start with the letters, RD, deal with the RDM database file (and map files, if need be). The subroutine names starting with MP handle the map files associated with the RDM file. Note: the map routines have not been used in a production environment Any program (subprogram, etc) that is going to use the interface must contain the following statement: Include 'dev:Rdmbuf.For' where dev: is the device containing Rdmbuf.for This will insert the following into your program: C--------------------------- C RDMBUF.FOR- Common area for application program to use to pass C field contents to and receive record contents from RDGET,RDNXT C BYTE value(256) !contents to search for in RDM file C ! left justified (strings, numbers, whatever) BYTE rec(512) ! contains record from RDM file C Integer*4 Nrec, ! Number of Active Records in file last used 1 Recnum ! record number just retreived C COMMON/ rdmbuf/ value,rec,Nrec,Recnum Steps for building an application: 1 - Using RDM, Generate a fieldlist. I recommend directing the fieldlist to an output file and including in your Fortran source code. Keep a copy handy. 2 - Declare the Fortran variables necessary for a search key & for the retreival of a record. 3 - Equivalence each exchange variables to Rec(Disp + 1) where Disp is taken from the RDM fieldlist 4 - Equivalence your key to value(1) Note: Boolean and Bit keys will be rejected by RDGET Example: From the RDM Fieldlist: # Field Name Field Type Size Disp Format Options Order 1 Balkey Record 4 0 0 1 2 Project # Integer 2 0 6 3 Account # Integer 2 2 6 4 Balkey End 5 Open Balance Dollar 8 4 16: 2 I < $ 6 Current Dollar 8 12 16: 2 I < $ C.. for the retreival Integer*2 Project, Account Real*8 Open, Current Equivalence (Rec( 1), Project) Equivalence (Rec( 3), Account) Equivalence (Rec( 5), Open) Equivalence (Rec(13), Current) C.. for the Key (using the record Balkey) Integer*2 TProj, Tacct Equivalence (value( 1), Tproj) Equivalence (value( 3), Tacct) -- Or -- c.. for searching just by account (sequential search) Equivalence (value( 1), Tacct) 1. CALL RDOPEN( funit, fil, access ,stat ) RDOPEN opens a RDM file for reading and writing of data records. a. fil = name of RDM file (14 characters). b. funit = unit number to associate fil with in open. c. access = 0 Read Only access 1 Shared (allow update) 2 Exclusive (required for Adding Records) d. stat = 0 if open succeeds 1 (Tsx) Attempt to file Lock non-existent channel 2 (Tsx) Shared file, channel problems (sysgen material) 3 " 4 (Tsx) Protection conflict between users. NOTE: If the RDM file was opened read only and a RDPUT was performed, a write error may occur. A map file cannot be opened before the RDM file because MPOPEN compares the RDM file name (fil), which would be null or blanks, against what is in the header of the map file. 2. CALL MPOPEN( munit, rdunit, mfil ) Open a map file for the opened RDM file. This call can be made at any place in the program. Before opening another map file for the current RDM file, close the currently opened map file. In determining if this mfil is for the RDM file, MPOPEN compares the RDM file name from the RDOPEN against what is in the header of the map file. MPOPEN assumes that there is a 3 letter and colon preface to the RDM file name proper, such as 'RD1:', or the subroutine will stop with an error message. a. munit = unit number to associate mfil (map file) in open. b. rdunit = unit number of RDM file c. mfil = map file name( 14 characters). 3. CALL RDCLOS( funit ) Closes an opened RDM file. The map file can be closed before or after this statement. Closing a file will compress the field table to reclaim space. a. funit = unit number associated with RDM file to close. 4. CALL MPCLOS( munit ) Close an opened map file. First close a map file before opening another one. Close all map files to RDM file that was or is soon to be closed before opening another RDM file. a. munit = unit number associated with opened map file. NOTE: if the munit number is not the same as the opened one, a warning message is printed and nothing happens (just returns). 5. CALL RDGET( funit, munit, fieldno, aindx, Option, stats ) Retrieve a record from RDM file (funit) using map file (munit) if mapped. a. funit = unit number associated with opened RDM file. b. munit = unit number associated with an opened map file; ignored if munit was not MPOPENed before call to RDGET or munit is 0. The RDGET is still performed on physical file (not through a map). c. fieldno = field number to search on (see FIELDLIST in RDM). A binary search is done if fieldno is major sort key(1) in RDM file or in the map file( if used ). Otherwise, a sequential search through RDM file (using map file) is performed. d. aindx = index in array for comparison if field is an array type. If your primary sort is an array, RDGET will only perform a binary search when using the first element (aindx=1) Note: Arrays of RECORD or arrays within a RECORD not supported as search keys. e. Options (Additive) 1 Lock this block 2 Release all other (previously locked) blocks 4 Key is unique - return with first matching record 8 Display Trace information (When compiled with Debug) 64 Retreive Next matching record (will start sequential search in sorted portion of file and switch to unsorted portion when necessary - only to be used with the primary sort key) f. stats = status of RDGET operation: (Additive) 1 = record not retreived 2 = bad fieldno or illegal key type 4 = bad unit number/file 8 = block locking failure 16 = Binary search performed 32 = unsorted records at end of file 64 = Unsorted section was searched g. value = in common area, RDMBUF. It has contents of field key for comparisons during search. The contents must be exactly the same as in the RDM record. RDGET does not perform any RDM data type conversions. h. rec = in common area, RDMBUF. If record is found, rec will have contents of the RDM record. NOTE: if key is not found, rec will be undefined Special Cases: RDGET supports data type Record as a primary sort key. It also supports non-unique keys by returning the first record that matches the search value. (Yes, it will even correctly handle non-unique record keys.) If your primary sort field is of data type RECORD, then the first field within your record is also considered to be a primary sort. If your search key is a primary (or Map) sort for the file a binary search will be performed. If you have a file with unsorted records appended to the end, you must be aware of the following: When performing a binary search, if RDGET finds a record in the sorted section of the file, it will NOT look at the unsorted portion of the file unless you specify the "Next" option. Note: Rdget does not support RDM Indexes 6. CALL RDNXT( funit, munit, option, stats ) Retrieve next sequential record from RDM file, based on current position in file. If this is first call to retrieve a record from a RDM file (no previous RDGET, or RDGREC), the first record is returned. Of course, if using a map file, the first and next sequential record are determined by the map. a. funit = unit number associated with opened RDM file. b. munit = unit number associated with an opened map file; ignored if munit not MPOPENed or munit is 0 (see RDGET). c. options (Additive) 1 Lock this block 2 Release all other blocks d. stats = status of RDNXT operation: 0 = record found and retrieved. 1 = record not found or end of file (EOF). 3 = bad munit number- munit not been opened by MPOPEN. e. rec = in common area, RDMBUF- contains contents of retrieved RDM record. NOTE: if key is not found, rec will be undefined 7. CALL RDPUT( funit, option, stats) After a record has been retrieved by RDGET or RDNXT and modified by calling application program, RDPUT will write the record out at the same record number (location). The file record pointers are not changed so other routines are unaffected. If you do a RDPUT without having done a successful retreival, you may get some bizarre results. a. funit = unit number associated with opened RDM file. b. stats = status of RDPUT operation: 0 = record written to file successfully. 1 = error in write. c. options 0 = Unlock the block 1 = Leave it locked d. rec = in common area, RDMBUF, rec has contents of record in RDM format (no RDM data type conversions done) to write out. 8. CALL RDGREC( funit, JRecord, Option, Stats) Retrieve a record by the physical record number a. funit = unit number associated with opened RDM File. b. JRecord = Integer*4 Record Number to Retrieve. c. Option 1 Lock this block 2 Release all other blocks d. Stats = status of RDGREC operation: 0 = record retrieved successfully 1 = record not retrieved Notes about Block locking: 1 - Right now, the routines are oriented towards only having one block locked at a time. 2 - Read Only files will not perform block locking regardless of the value of lock. 3 - In order to avoid collisions, right now you are required to have exclusive access to a file in order to add records (see below) 9. Rdadd(funit,Stats) This routine will add whatever is in the exchange buffer to the end of the RDM File opened on Funit. It will also update the Number of active records in the file Header. This routine assumes that you are putting in valid data and will not check your input data for validity or for the proper record length. ie.. you can really trash your file with this routine. a. funit = unit number associated with opened RDM File. b. Stats = status of RDADD operation: 0 = record saved successfully 1 = error in write, record not saved Note: Rdadd requires that the file has been opened with EXCLUSIVE Access. Rdadd WILL NOT ADD records TO AN INDEXED FILE. Also: Rdadd does NOT update any maps that may be attached to the file. Miscellaneous RDM vs F77 quirks: All "Integer*4" values within RDM have the words reversed. The Integer*4 Function RDSWAP can be used to reverse them. Note: The rdm routines will not do any conversions,ie.. convert your search keys to RDM format BEFORE performing a search. Dates: To Unpack Dates after 1972: Integer*2 Day,Month,Year,Date Day = Date.And.31 Month = (Date/32).And.15 Year = (Date/1024) + 72 Dates Before 1972: Day = Date.And.31 Month = (Date.And.480)/32 - 3 Year= Date/512 + 71 Note: Dates before 1972 are Negative RDM Bit Arrays RDM Bits are numbered left to right 1...n as opposed to 15...0 within each word Example using array of 16 bits Integer*2 Word Equivalence (Rec(xx), Word) F77bit = 16 - Imod(RDMbit-1,16) Ival = IIshft(Word,F77bit) If (Ival.Lt.0) Then ! Bit is set . . Endif Boolean Values RDM uses byte value of 0 for .False. and 1 for .True. To Set a Fortran Boolean from a RDM boolean: FortranBoolean = Rec(nnn).Eq.1 RDM Data Type FORTRAN Data Type Integer, Date Integer*2 Real, Longdate, Time Real*4 Real4, Dollar Real*8 Long, Money 2 Word Integers (Integer*4 with the words reversed) Additional User Notes: There is only one buffer for the exchange of data. The recom- mended procedure for using these routines is to capture any data needed immediately after the record is retreived. Compiling & Linking All modules need to be compiled with the same values in RDMCom. Ie. if you make any changes, you must recompile all modules. In order to use Tracing, you must compile RDget with the debug option (/D, or /Ondebug) Note: I keep all modules on one logical unit assigned to DK: Due to the use of the TSX-Plus block locking, you must link your program with TSXLIB (Not Supplied) Overlays Since none of the Rdm routines call each other, they can all be placed on the same overlay level, if need be. The largest routine is RDGET, which, depending on Maxfile and Maxfld, is in the neighborhood of 7 Kb. Maxfile Maximum number of files to be used simultaneously. Due to the presence of Byte Arrays in the Common Areas, Always set Maxfile to an Even number to make sure that all of the variables in common are word aligned. Maxfld Maximum Number of Fields for ALL files open at the same time. This is the parameter you are most likely to exceed. Again, make sure you set Maxfld to an even number. RDCLOS compresses the field table, so closing a file when you are done with it will help conserve table space. Changes to File Structure The interface will automatically compensate for any changes in record size, so that if a file being used by the interface is restructured, the interface will still function correctly. If your fields within the record have been rearranged the results will be unpredictable (remember that your record structure is defined by the equivalences) Good Habits Include a field listing of your file in your Fortran code for quick reference in case something should change. Use Parameters for the Rdm unit numbers. ex: Integer*2 Rdmfile Parameter (Rdmfile=9) . . Call Rdopen(Rdmfile,....) Good Luck ... ws