---------------------------------------------------------
Brosco's Liberty Basic Newsletter - Issue #9 - June 98
---------------------------------------------------------
In this issue:
       1) Using Random files - Part 1

Ok - lets first understand what a RANDOM file is.

Basically all files (including text files) are RANDOM files!  Its
just a stream of data that you can start reading anywhere - rather
than at the first position - and you retrieve records of data rather
than text strings.

Within LB, life has been simplified for us.   We can tell LB that we
have a record or structure for the data, and it gets it for us.  If
you were accessing a file as random in some other Windows programming
languages you would need to keep track of the record length and
request a specific number of bytes and the byte starting position
within the file - with LB we simply tell it the record number that
we want to read or write.

Here's a very simple example of using a Random file in LB.  Suppose
that we wanted to create a catalogue of our collection of Video
Cassettes.  Each cassette has a number on its label, starting with
0001 and incrementing as we add to our collection - it will be OK
if some numbers are missing.  We will keep track of the Movie name
and the main star in the movie.  The first program will record a
couple of cassettes that are already in our collection.

    nomainwin
    open "video.txt" for random as #f len=52    '*** note 1
    field #f, _
        4 as cNum, _
        24 as name$, _
        24 as mainActor$
    cNum = 1
    name$="Golden Eye"
    mainActor$ = "Pierce Brosnan"
    put #f, 1

    cNum = 3
    name$ = "Ransom"
    mainActor$ = "Mel Gibson"
    put #f, 3

    close #f

    notice "Initial database has been created"
    end

***** Note 1
First of all - read the second statement of the program very
carefully!  On the end of the OPEN statement there is "len=49".
This is the length of the record.  This must EXACTLY match the
total length of all FIELDs specified in the next statement.

The file has been given a name of "video.txt" - you could choose any
name you liked - plus the extension could be any name you wanted.  I
used the extension of .TXT so that you could run the program and
then, using Windows Explorer - simply double click on the file and
Notepad would display the contents of our database.  Please do this
now - 'cut' the program above - 'paste' it into LB and then run it.
Then use Notepad to examine the contents of  "video.txt".

When you view the file, click on EDIT and then WORDWRAP so that you
can see all the data.  Notice that we added record #1 and then
record #3.  LB inserted a blank record #2 for us.

Also note that the cassette number (cNum) is displayed as text,
even though its a number within our program - LB does that for us.
All data in our database is stored as  text - and converted to
the correct format for use in the program.



Next, we will have a very simple program to list the contents of our
database:


    open "video.txt" for random as #f len=52
    field #f, _
        4 as cNum, _
        24 as name$, _
        24 as mainActor$ 

    for i = 1 to 3
        get #f,i
        print cNum;" ";name$;mainActor$
        next i


    notice "Initial database has been displayed"
    close #f
    end

Cut and Paste this program to LB and run it.  You will see the
contents listed.


Now that we have seen how easy it is to read and write to random
files - lets build a slightly more realistic program to add,
update, delete and browse our database.

' Sample program to update a database
' Brosco - June 98 (Newsletter #9)
'
    open "video2.txt" for random as #f len=49
    field #f, _
        1 as active$, _
        24 as name$, _
        24 as mainActor$

    nomainwin
    WindowWidth = 320
    WindowHeight = 230

    statictext #w.1, "Cassette Number:", 10, 40, 130, 20
    statictext #w.2, "Movie Name:", 10, 70, 130, 20
    statictext #w.3, "Main Star:", 10, 100, 130, 20
    statictext #w.4, "Status:", 10, 175, 65, 20
    statictext #w.status, "", 80, 175, 240, 20

    textbox #w.cn, 150, 40, 30, 25
    textbox #w.movie, 150, 70, 150, 25
    textbox #w.star, 150, 100, 150, 25

    button #w.add, "Add", [add.movie], UL, 70, 140, 50, 25
    button #w.upd, "Update", [update.movie], UL, 130, 140, 50, 25
    button #w.del, "Delete", [delete.movie], UL, 190, 140, 50, 25
    button #w.exit, "Quit", [close.w], UL, 250, 140, 50, 25

    button #w.prev, "<--Prev", [previous], UL, 70, 5, 60, 25
    button #w.next, "Next -->", [next], UL, 160, 5, 60, 25

    button #w.default, "Get", [get.movie], UL, 10, 140, 50, 25

    open "Movie Database" for dialog as #w
    print #w, "trapclose [close.w]"
    print #w.cn, "!setfocus"

[loop]
    input var$
    goto [loop]

[previous]
    cNum = cNum - 1
    if cNum < 1 then
        cNum = 1
        print #w.status, "You are at the start of the database"
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [previous]
    gosub [display.movie]
    goto [loop]

[next]
    cNum = cNum + 1
    if cNum > lof(#f) / 49 then
        cNum = lof(#f) / 49
        print #w.status, "You are at the end of the database"
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [next]
    gosub [display.movie]
    goto [loop]

[display.movie]
    print #w.cn, cNum
    print #w.movie, name$
    print #w.star, mainActor$ 
    print #w.status, ""
    print #w.cn, "!setfocus"
    return

[get.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if cNum < 1 then
        notice "Get error!" + chr$(13) + _
            "Cassette number must be greater than 0"
        goto [loop]
        end if
    if cNum > lof(#f) / 49 then    'check if the record exists
[get.error]
        notice "Get Error!" + chr$(13) + _
            "This record doesnt exist"
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [get.error]
    gosub [display.movie]
    goto [loop]

[add.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if cNum < 1 then
        notice "Add error!" + chr$(13) + _
            "Cassette number must be greater than 0"
        goto [loop]
        end if
    if cNum <= lof(#f) / 49 then    'check if the record exists
        get #f, cNum    'check if the record is active
        if active$ = "1" then
            notice "Add error!" + chr$(13) + _
                "This Cassette exists in the database." + chr$(13) + _
                "Select GET - then Update"
                goto [loop]
                end if
        end if
    gosub [write.record]
    print #w.status, "Movie has been added."
    goto [loop]

[update.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if (cNum < 1) or (cNum > lof(#f)/49) then
[update.error]
        notice "Add error!" + chr$(13) + _
            "Cannot update non-existant record."
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [update.error]
    gosub [write.record]
    print #w.status, "Movie has been updated."
    goto [loop]

[delete.movie]
    print #w.cn, "!contents?"
    input #w.cn, cNum
    if (cNum < 1) or (cNum > lof(#f)/49) then
[delete.error]
        notice "Delete error!" + chr$(13) + _
            "Cannot delete non-existant record"
        goto [loop]
        end if
    get #f, cNum
    if active$ <> "1" then [delete.error]
    active$ = ""
    name$ = ""
    mainActor$ = ""
    put #f, cNum
    gosub [display.movie]
    print #w.status, "Movie has been deleted."
    goto [loop]

[write.record]
    print #w.movie, "!contents?"
    input #w.movie, name$
    print #w.star, "!contents?"
    input #w.star, mainActor$
    active$ = "1"               ' show the entry is valid
    put #f, cNum
    return

[close.w]
    close #w
    close #f
    end


Cut and Paste the above program to the LB editor and then run the
program.

A very good way to see how a program works is to use LB's Debug mode
and Step through the program.



Some notes about this program.

Instead of storing the CassetteNumber in the database, we used that
as the physical record number in that database.  That is, if you add
Cassette 0010, we will write the record in position 10 of the database.
____

You will notice a new field has been added to FIELD - called
"active$".  When we write a valid record to the database, we set
it to "1".  When LB writes blank records, or when we delete a
record, it is set to " ".  This way we know which records are valid.
____

You will see several refences in the code like:
    if cNum > lof(#f) / 49 then

lof(#f) returns us the length of the file (in bytes).  By dividing by
49 - the length of the FIELD structure, we know how many records exist
on the database.  We need to know this so that we dont try to GET
non-existant records - that would cause an error and crash the program.

                        ***********

OK - so what's wrong with this program?

1)  First the KEY to the database must be a number, and unless we
want to create a very large file, the keys should start at 1 and
have very few 'gaps'.

2)  To re-use deleted space - we must know the available record
numbers.

3)  If we wanted to find all the movies that starred our favourite
actor, we would have to scan the entire database.

Next issue I will address these issues and, hopefully I will also
have the problems in my DBDLL sorted out so that we can add a very
fast indexing access method.

If you would like to discuss any of the code or techniques used
here, please use my message board at:

http://users.orac.net.au/~brosco

and ideally, include "NL0009" is the Subject of the posting.

--------------------------------------------------------------
 Newsletter written by: Brosco.
 Comments, requests or corrections mailto:brosco@orac.net.au

 Translated from Australian to English by an American:
 Alyce Watson -  Chief Editor.  Thanks Alyce.
