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
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������