============================================================================
       $VER: CNet Amiga ARexx Examples2, v1.0 (10-Dec-94) by Dotoran!
============================================================================

    The following tutorial was sent to a user who requested information on
using relative (or packed character) types of data files. I've slightly
updated this tutorial, since it's first release.

Packed Character Files
~~~~~~~~~~~~~~~~~~~~~~
OK, well, this is going to get a bit involved, but I'll try to present it in
an understandable way.

In normal, sequential type files(like most TEXT files), there is a lot of
wasted space at the ENDS of each line.

In packed, relative type files(like CNet's "bbs.udata" file), ALL SPACE is
accounted for in the file. We know EXACTLY where EACH separate piece of data
is stored WITHIN the file. Because we know this, we can go RIGHT TO the piece
of data we wish to use, whenever we wish to use it.

In order for us to be able to know EXACTLY where each piece of data is found,
we can't simply SAVE the data in it's "raw" format. For instance, let's say
we wish to save the following data to a file:

            Real Name           Handle
            ===============================
            David Weeks         Dotoran
            Jay Weber           Lifeform
            Patrick Grieshop    Hooter
            Jeffrey Waris       Lord Zeus

If saved as a "sequential" type of file, it really wouldn't look much more
different than is shown above:

            David Weeks         Dotoran
            Jay Weber           Lifeform
            Patrick Grieshop    Hooter
            Jeffrey Waris       Lord Zeus

Now, we could use a non-alphabetic character to make determining where the
REAL NAME ends and the HANDLE starts, so we'd then have this:

            David Weeks|Dotoran
            Jay Weber|Lifeform
            Patrick Grieshop|Hooter
            Jeffrey Waris|Lord Zeus

But what happens when we want to grab, say Patricks HANDLE only? We already
know his REAL NAME, so we really don't want to know THAT info again, just
his HANDLE. The only way we could do this would be to read through the file,
line by line, until we found "Patrick Grieshop", upon which we'd then know
the NEXT piece of data was his HANDLE.

Not very efficient, nor is it very fast if Patrick's name happened to be, oh
say the 230th entry in the file... Also, what happens when we decide to SAVE
the data? The only way to SAVE data in a sequential file, while maintaining
data integrity would be to READ ALL the data INTO the computer, CHANGE the
ONE or TWO pieces of data in question, then SAVE ALL the data BACK onto the
disk. This is VERY inefficient, and could take literally FOREVER, depending
on how large the database in question happened to be.

To make "relative" (packed) files work, we have to follow TWO basic rules:

1: Every data field MUST be of a FIXED length.

2: Every data item MUST be padded out with an Ascii 0 character, d2c(0)

By FIXED length, we mean the LENGTH of any specific value will NEVER CHANGE.

Let's look at our data table again:

            Real Name           Handle
            ===============================
            David Weeks         Dotoran
            Jay Weber           Lifeform
            Patrick Grieshop    Hooter
            Jeffrey Waris       Lord Zeus

OK, we have two pieces of data to work with. The REAL NAME and the HANDLE.

Before continueing, we need to find the MAXIMUM LENGTH either of these could
EVER be. The easiest way to do this would be to check in the EU command.

Doing so gives us the following information:

            Handle: 20 characters long.
        First Name: 14 characters long.
         Last Name: 19 characters long.
         Separator:  1 space character.

This, followed by some simple math gives us the info we're interested in:

        MAX Length of a HANDLE: 20 characters long.
     MAX Length of a REAL NAME: 34 characters long. (14+19+1)

Alright, now we know all the info we need. When constructing the format for
the "relative" file, all we have to remember is to KEEP ALL our data padded
out to these lengths. Here's one way we could look at the file's format:

---------------------------------------------------------------------------

Data LENGTH's (Real Name is 34 Characters, Handle is 20 characters)
         1         2         3   3         1         2         1      1
12345678901234567890123456789012341234567890123456789012345678901234567
                                 |                   |
DAVID WEEKS                      |DOTORAN            |JAY WEBER
                                 |                   |
01234567890123456789012345678901234567890123456789012345678901234567890
0         1         2         3         4         5         6         7
Characters INTO the file-------> (the first 70 characters of the file)

---------------------------------------------------------------------------

Data LENGTH's (Real Name is 34 Characters, Handle is 20 characters)
1 2         3   3         1         2         1         2         3  3
8901234567890123412345678901234567890123456789012345678901234567890123
                |                   |
                |LIFEFORM           |PATRICK GRIESHOP
                |                   |
1234567890123456789012345678901234567890123456789012345678901234567890
         8         9         0         1         2         3         4
                             1         1         1         1         1
Characters INTO the file-------> (characters 71 thru 140 in the file)

---------------------------------------------------------------------------

Data LENGTH's (Real Name is 34 Characters, Handle is 20 characters)
3         1         2         1         2         3   3         1    1
4123456789012345678901234567890123456789012345678901234123456789012345
|                   |                                 |
|HOOTER             |JEFFREY WARIS                    |LORD ZEUS
|                   |                                 |
1234567890123456789012345678901234567890123456789012345678901234567890
5        5         6         7         8         9         0         1
1        1         1         1         1         1         2         2
Characters INTO the file-------> (characters 141 thru 210 in the file)

---------------------------------------------------------------------------

Data LENGTH's (Real Name is 34 Characters, Handle is 20 characters)
1   2
67890
    |
    |
    |
12345
1   1
2   2
Characters INTO the file-------> (characters 211 thru 215 in the file)

---------------------------------------------------------------------------

Well, I'll bet BIG BUCKS I just thoroughly lost you on the above....

What I'm trying to convey is that a "relative" file is nothing more than
ALL the DATA strung out one piece after another, so long as each item stays
the same LENGTH. Note that the "D" of DOTORAN follows RIGHT AFTER the 34th
character of the REAL NAME "David Weeks". Then note the "J" of Jay Weber
only appears AFTER the 20th character of the HANDLE "Dotoran".

I guess you could think of "relative" files as BLOCKS of data. In our example
above, we start with a 34 character block, then a 20 character block, then a
34 character, 20 character, 34, 20, 34, and finish off with a 20 character
block.

The vertical bars shown | help you to see where one data block ENDS and the
NEXT data block BEGINS. Also note that at the END of the file, in the LAST
block of data, we STILL made sure to pad it out to the FULL 20 characters.

Why? Well, for one reason, it makes ADDING additional data to the file a bit
easier, because we're all ready to accept another 34 character REAL NAME.

The other reason is because we have to READ a WHOLE block of data from the
file, and not just the "textual" part of the data.

All right, so we have this "relative" file on the disk, but how do we get at
the data INSIDE the file? Well, we have three commands just for "relative"
type files:
                SEEK(), READCH(), and WRITECH()

The SEEK() command is used to set a "pointer" to POINT to the START of a
piece of data, while the READCH() and WRITECH() commands are used to READ
CHARACTERS and WRITE CHARACTERS starting at the "pointed to" position.

For instance, let's take a look at the beginning of our example file again:

DAVID WEEKS                      |DOTORAN            |JAY WEBER
                                 |                   |
01234567890123456789012345678901234567890123456789012345678901234567890
0         1         2         3         4         5         6         7
Characters INTO the file-------> (the first 70 characters of the file)

Lets say we wish to read the HANDLE of "David Weeks". We know that it is the
SECOND piece of data in the file. We also know that it is 20 characters long,
and follows a 34 character block of data. Here's how we'd read the HANDLE of
"David Weeks", given the name of our example file is "beta:example.data":

call OPEN(f1,"beta:example.data","r")

    call SEEK(f1,34,"b")

    handle=READCH(f1,20)

call CLOSE(f1)

Alright, the initial OPEN and CLOSE commands should look familiar, as they
are used in the exact same way as when working with "sequential" type files.

The SEEK() command tells the computer to "point to" the 34th character of
data within the file, which you can see from the example above is the START
of the first HANDLE in the file. The "b" used inside the SEEK() command tells
the computer to start at the BEGINNING of the file, before counting off the
34 characters.

NOTE: I should also tell you that the START of a "relative" file is referred
      to as point "0", NOT point 1. SEEK(f1,1) means MOVE IN ONE character,
      which would actually be the SECOND character of data.

Next, the READCH() command tells the computer to READ 20 CHARACTERS out of
the "relative" file STARTING at the current position of the "pointer".

The last thing we need to do is STRIP AWAY any pad characters that may
have been used to make the HANDLE equal to 20 characters in length. Earlier
I mentioned that Ascii 0 d2c(0) is usually used for this purpose, so the
following command would be used to "clean up" or STRIP any excess pad
characters from the END of our "handle" variable:

handle=STRIP(handle,'t',d2c(0))

The "t" in the STRIP() command means we wish to STRIP the Ascii 0's that
TRAIL the handle. We MUST remember to STRIP these Ascii 0's, or else we'll
get odd results when printing, or errors if we wish to perform MATH on any
NUMBERS we might be storing in a "relative" file.

Alright, that's essentially how we READ data from a "relative" file, but
how would you SAVE data into an existing "rel" file? Let's say after we
read in the handle for "David Weeks", we wished to CHANGE his handle to be
"The Marshal". Here's how it would look:

handle="The Marshal"

handle=left(handle,20,d2c(0))

call OPEN(f1,"beta:example.data","w")

    call SEEK(f1,34,"b")

    call WRITECH(f1,handle)

call CLOSE(f1)

Again, the OPEN and CLOSE commands are the same. The second "handle=" is
used to pad the LENGTH of the handle so it will be 20 characters long.
Notice how the LEFT() command is used to do this, simply by tossing in the
third parameter allows us to pad the contents using something OTHER than
a SPACE(which is the DEFAULT pad character).

The SEEK() command is used to position the "pointer" to the start of the 34th
character, just like before. We also specify "b", just to make sure we START
from the BEGINNING of the file, then we WRITECH() the contents of the HANDLE
variable.

Essentially, that's all there is to "relative" files. I know this file is a
bit on the lengthy side, but hopefully it is of some use to you in the future.

                                                                  - Dotoran
============================================================================
                       Frontiers BBS (716)/823-9892!
============================================================================
