📄 Random.doc for Euphoria 3.1.1


                 Version 1.00, March/23/2017, by Shian Lee.



 Introduction
 ============

 This library provides random access file routines for any platform. Random
 access, also known as direct access, provides efficient and very fast access
 to each record in a file, by using the record's serial number directly.

 Random access files can be used for almost anything: configuration files,
 help systems, dictionaries, account managing, databases, etc. These are
 binary files (not text files), which you *must* open, copy or transfer in
 binary mode, otherwise the file might be modified by the operating system.

 All records in a random access file have fixed length and a fixed number of
 fields. The length of a field depends on its data type. String field stores
 a fixed length of characters. Numeric field stores a number in binary format,
 which uses a fixed length of bytes.

 You can always append new records to a random access file (up to 2 Gb in
 file size), but for deleting records, inserting records, or modifying the
 structure of records, you must rewrite the entire file. To avoid it, it is
 neccessary to design the structure of a random access file carefully,
 according to your needs. You can also use few random access files as "tables"
 in a database.

 This library supports 15 simple data types, for string and numeric fields:

 Data type  Field size in bytes  Values range             Euphoria  QBasic
 ---------  -------------------  ------------             --------  ------
 1..32767   String (text)        1 to 32767 characters    sequence  STRING

 RA_S1      1 Signed byte        -128..127                integer   -
 RA_U1      1 Unsigned byte      0..255                   integer   -

 RA_S2      2 Signed bytes       -32768..32767            integer   INTEGER
 RA_U2      2 Unsigned bytes     0..65535                 integer   -

 RA_S3      3 Signed bytes       -8388608..8388607        integer   -
 RA_U3      3 Unsigned bytes     0..16777215              integer   -

 RA_S4      4 Signed bytes       -2147483648..2147483647  atom      LONG
 RA_U4      4 Unsigned bytes     0..4294967295            atom      -

 RA_S5      5 Signed bytes       -549755813888..
                                  549755813887            atom      -
 RA_U5      5 Unsigned bytes     0..1099511627775         atom      -

 RA_S6      6 Signed bytes       -140737488355328..
                                  140737488355327         atom      -
 RA_U6      6 Unsigned bytes     0..281474976710655       atom      -

 RA_R4      4 Real number bytes  7 significant digits     atom      SINGLE
 RA_R8      8 Real number bytes  16 significant digits    atom      DOUBLE

 * The column 'Euphoria' lists the compatible data types in Euphoria 3.1.1.
 * The column 'QBasic' lists the compatible data types in Microsoft (R)
   QBasic for MS-DOS (R).


 Note: for a simple, extremely flexible, database system, see also the
       Euphoria Database System (EDS), Euphoria 3.1.1, DATABASE.DOC.


 Disclaimer
 ==========

 Use this library at your own risk. The author will not be responsible for
 any damage or data loss. (Remember to backup your files frequently).

 This library is tested on FreeDOS 1.1 operating system. The code or the
 documentation might still contain errors or mistakes.


 Random Access Routines
 ======================

 In the descriptions below, to indicate what kind of object may be passed in
 and returned, the following prefixes are used:

 x     - a general object (atom or sequence)

 s     - a sequence

 a     - an atom

 i     - an integer

 fn    - an integer used as a file number

 st    - a string sequence, or single-character atom


 ra_open         - open a file for random access

 ra_length       - return the length of record in a random access file

 ra_put          - put a record in a random access file

 ra_get          - get a record from a random access file

 ra_close        - close a random access file



 --------------------------------<ra_open>-----------------------------------

 Syntax:      include random.e
              fn = ra_open(st, s)

 Description: Open a file for random access, to get the file number. -1 is
              returned if the open fails. st is the path name of the file. The
              file will be created if necessary. s is a list of data types
              that defines the structure and length of the file records.

              The following data type constants are defined in random.e:

                global constant      -- ( Values range )
                 -- 1 to 32767       -- bytes (characters) for a string field

                    RA_S1 =  0,      -- -128..127
                    RA_U1 = -1,      -- 0..255

                    RA_S2 = -2,      -- -32768..32767
                    RA_U2 = -3,      -- 0..65535

                    RA_S3 = -4,      -- -8388608..8388607
                    RA_U3 = -5,      -- 0..16777215

                    RA_S4 = -6,      -- -2147483648..2147483647
                    RA_U4 = -7,      -- 0..4294967295

                    RA_S5 = -8,      -- -549755813888..549755813887
                    RA_U5 = -9,      -- 0..1099511627775

                    RA_S6 = -10,     -- -140737488355328..140737488355327
                    RA_U6 = -11,     -- 0..281474976710655

                    RA_R4 = -12,     -- 7 significant digits real number
                    RA_R8 = -13      -- 16 significant digits real number

              * For each data type x is its fixed length in bytes:
                String is x
                Signed integer is RA_Sx
                Unsigned integer is RA_Ux
                Real number is RA_Rx

 Comments:    The file number returned by ra_open() can be used with any other
              Euphoria routine, such as lock_file(), flush(), etc.

              For speed and efficiency, you should choose the smallest data
              types which are neccessary to store your data.

              Use ra_close() to close the file.

 Example:

              -- this sequence defines the fields and their order in each
              -- record. the record length is the sum of the fields length,
              -- i.e. 4+15+15+30+1+1+4=70. the file size is the sum of the
              -- records length, e.g. 20 records = 20*70 = 1400 bytes.

              fields = {
                RA_U4,      -- [1] worker ID
                15,         -- [2] First Name; string of 15 characters
                15,         -- [3] Last Name;  string of 15 characters
                30,         -- [4] Telephone;  string of 30 characters
                RA_U1,      -- [5] Age
                RA_S1,      -- [6] Motivation and care (-10 to 10)
                RA_R4       -- [7] $ per hour
              }

              -- open file for random access
              fn = ra_open("workers.dat", fields)

              -- create a record sequence according to the fields above
              record = {
                201345498,          -- [1]
                "Pink",             -- [2]
                "Floyd",            -- [3]
                "273-3533-838",     -- [4]
                60,                 -- [5]
                10,                 -- [6]
                8.73                -- [7]
              }

              -- update record number 2
              ra_put(fn, 2, record)

              -- retrieve record number 2 and print it
              record = ra_get(fn, 2)
              printf(1, "[%d] %s %s\nTel: %s Age: %d *%d*\n%5.3f$\n", record)

              -- close the random access file
              ra_close(fn)


 See Also:    ra_put, ra_get, ra_length, ra_close
              Euphoria 3.1.1: lock_file, open, close


 --------------------------------<ra_length>----------------------------------

 Syntax:      include random.e
              i = ra_length(fn)

 Description: Return the length of record in random access file fn.

 Comments:    The length of a record is the sum of the fields length. It is
              calculated when you open a file using ra_open(). You can tell
              how many records are in a random access file by dividing the
              file-size by its record-length.

 Example:

              -- open 3 files for random access
              fn1 = ra_open("test1.dat", {10})
              fn2 = ra_open("test2.dat", {10, RA_U2})
              fn3 = ra_open("test3.dat", {10, RA_U2, RA_R8})

              len1 = ra_length(fn1)  -- len1 is 10 -- i.e. string of 10 bytes
              len2 = ra_length(fn2)  -- len2 is 12 -- i.e. 10+2=12
              len3 = ra_length(fn3)  -- len3 is 20 -- i.e. 10+2+8=20

              -- put record number 10 in each file
              ra_put(fn1, 10, {"this is a text field"})
              ra_put(fn2, 10, {"this is a text field", 45})
              ra_put(fn3, 10, {"this is a text field", 45, 123.78})

              -- close the random access files (also updates directory list)
              ra_close(fn1)
              ra_close(fn2)
              ra_close(fn3)

              -- calculate how many records are in each file
              s = dir("test1.dat")
              records = s[1][D_SIZE] / len1  -- records is 10 -- i.e. 100/10
              s = dir("test2.dat")
              records = s[1][D_SIZE] / len2  -- records is 10 -- i.e. 120/12
              s = dir("test3.dat")
              records = s[1][D_SIZE] / len3  -- records is 10 -- i.e. 200/20


 See Also:    ra_open


 --------------------------------<ra_put>-----------------------------------

 Syntax:      include random.e
              ra_put(fn, i, s)

 Description: In random access file fn, update record number i, with s. s is a
              sequence of values for updating each field in the record. You
              must have previously defined the structure of s using ra_open().

 Comments:    If you put a record past the end of the file, undefined bytes
              will be inserted into the gap between the original end of file
              and your new record.

              Out of range values (string or number) will be truncated to the
              correct number of low-order bytes. Trailing spaces (ASCII 32)
              are used to fill up a string field.

 Example:

              -- define the fields in record -- see also ra_open()
              fields = {
                RA_U1,      -- [1] year (since 2000)
                RA_U1,      -- [2] month
                RA_U1,      -- [3] day
                RA_U1,      -- [4] important (0/1)
                50,         -- [5] title
                250         -- [6] note
              }

              -- open file for random access
              fn = ra_open("notes.dat", fields)

              -- update record number 1
              ra_put(fn, 1, {17, 3, 21, 0, "First note", "It works!"})

              -- update record number 9
              ra_put(fn, 9, {17, 3, 27, 1, "Bug fix", "n is not a 32-bit..."})

              -- retrieve record number 1 and print it
              record = ra_get(fn, 1)
              printf(1, "%d/%d/%d [%d] %s\n%s\n", record)

              -- retrieve record number 9 and print it
              record = ra_get(fn, 9)
              printf(1, "%d/%d/%d [%d] %s\n%s\n", record)

              -- close the random access file
              ra_close(fn)


 See Also:    ra_get, ra_open, ra_close
              Euphoria 3.1.1: flush


 --------------------------------<ra_get>-----------------------------------

 Syntax:      include random.e
              x = ra_get(fn, i)

 Description: From random access file fn, retrieve record number i. x will be
              a sequence of values of all fields in the record. You must have
              previously defined the structure of the records using ra_open().
              The atom -1 is returned on end of file.

 Comments:    Because either a sequence or an atom (-1) might be returned, you
              should probably assign the result to a variable declared as
              object.

 Example:

              -- define the fields in record -- see also ra_open()
              fields = {
                RA_U1,      -- [1] month
                RA_U1,      -- [2] day
                30,         -- [3] description
                RA_R4,      -- [4] plus (+) $
                RA_R4       -- [5] minus (-) $
              }

              -- open file for random access
              fn = ra_open("balance.dat", fields)

              -- append record number 7
              ra_put(fn, 7, {5, 12, "New shirt", 0, 10.99})

              -- append record number 8
              ra_put(fn, 8, {5, 12, "Food", 0, 128.34})

              -- append record number 9
              ra_put(fn, 9, {5, 15, "Salary", 1400.92, 0})

              -- retrieve records number 7, 8, 9 and print them
              for i = 7 to 9 do
                  record = ra_get(fn, i)
                  printf(1, "%d/%d - %s +[%8.3f]  -[%8.3f]\n", record)
              end for

              -- close the random access file
              ra_close(fn)


 See Also:    ra_put, ra_open, ra_close
              Euphoria 3.1.1: flush, getc


 --------------------------------<ra_close>----------------------------------

 Syntax:      include random.e
              ra_close(fn)

 Description: Close a random access file, flush out any still-buffered
              records, and remove its entry from the list of open-files.

 Comments:    Any still-open files will be closed automatically when your
              program terminates.

              If you close a random access file directly using close(), it
              may lead to unexpected results, or crash your program, the next
              time you call any routine in this library.


 See Also:    ra_open
              Euphoria 3.1.1: close, flush