Liberty Basic is develeopped by Carl Gundel Original Newsletter compiled by Alyce Watson and Brosco Translation to HTML: Raymond Roumeas
In this issue:
Last issue we developed a program to maintain our collection of movie cassettes - but we still had a couple of problems with the solution:
1) The KEY was also used as a record number. This gave us little flexibility in what we could use as a Key for the database.
2) We had to know where the 'deleted' records were to be able to re-use the space.
3) Direct access was only based on Record number.
We will address the first two problems in this issue. The 3rd problem will be in Issue #11.
OK - on to the solution!
open "video3.txt" for random as #f len=55field #f, _ 1 as active$, _ 6 as casNum$, _ ' The KEY to the DB 24 as name$, _ 24 as mainActor$
We will also reserve record #1 of the database to hold some 'control' information - it will NOT contain info about our movies! It will be used to keep track of our 'deleted' records so that we can reclaim the space. Now I know that this sounds impossible - but even if you have thousands of 'deleted' records - we will be able to keep track of all of them with just one 55 byte record and re-use them when we add new records!!!!! How do we do this?
OK - after we OPEN our database - if its the first time - we create a control record at Position #1:
if lof(#f)/55 = 0 then ' Empty DB - create CONTROL Rec casNum$ = "0" put #f, 1 end if
In the control record we only use the 'casNum$' field. This will be used to "point" to the last record deleted. If no deleted' records exist - it will have a value of "0".
When we delete a record - we update the Control rec:
[delete.movie]
if cNum < 2 or cNum > lof(#f) / 55 then ' Check if valid to delete this
notice "Delete Error!" + chr$(13) + _ "No record to delete!" goto [loop] end if get #f, 1 ' Get the Control record put #f, cNum ' Write it to the Deleted space casNum$ = str$(cNum) put #f, 1 ' Write a new control record active$ = "" name$ = "" mainActor$ = "" gosub [display.movie] print #w.status, "Movie: " + casNum$ + " has been deleted." goto [loop]
First we check that this record is 'allowed' to be deleted.
Now this is where you have to concentrate - and if its the first time you have done something like this - you will probably have to read it a few times - and if the eyes start to glaze over, dont worry - you will have plenty of company!
We get the ControlRec (remember, casNum$ in this record points to the previous deleted record - or "0" if none) and we write it to the position of the record we are deleting. We then write a new ControlRec with casNum$ now pointing to the deleted record.
Now for the second part of the equation - this is how we re-use the space when we add new records:
[add.movie] gosub [GetEmptyRec] ' Find somewhere to write the new record. print #w.cn, "!contents?" input #w.cn, casNum$ gosub [write.record] print #w.status, "Movie: " + casNum$ + " has been added." goto [loop] [GetEmptyRec] ' Returns cNum set to position for new rec get #f, 1 ' Get the Control rec cNum = val(casNum$) if cNum = 0 then ' No deleted space available - get from end cNum = lof(#f) / 55 + 1 return end if get #f, cNum ' Get the deleted rec put #f, 1 ' write the Deleted rec as the new Control return
The 'magic' is all in [GetEmptyRec]. It Gets the ControlRec and checks if there is any deleted records. If not - it just sets the output position to the End of File position - that's the place we normally add new records.
But - if there is deleted space available - we set the output position to the record pointed to by the ControlRec. Then we get that record (remember casNum$ in that record points to the 'previous' deleted record) and we write that as our new ControlRec.
If you are having a problem understanding this - get a piece of paper and create a list of added records. Dont forget to put the ControlRec in position 1. Then go through an exercise of deleting and adding records - VERY carefully updating the value of casNum$ - you will soon get the hang of it.
Here's the full sample program:
' Sample program to update a database ' plus automatically re-use deleted space. ' Brosco - June 98 (Newsletter #10) ' open "video3.txt" for random as #f len=55 field #f, _ 1 as active$, _ 6 as casNum$, _ ' The KEY to the DB 24 as name$, _ 24 as mainActor$ if lof(#f)/55 = 0 then ' Empty DB - create CONTROL Rec casNum$ = "0" mainActor$ = "(Control Record)" put #f, 1 end if cNum = 1 ' initialise for browsing ' 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, 50, 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" print "DB at start of program" gosub [print.db] [loop] print #w.cn, "!setfocus" input var$ goto [loop] [previous] cNum = cNum - 1 if cNum < 2 then ' Note - Record #1 is Control info cNum = 2 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) / 55 then cNum = lof(#f) / 55 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, casNum$ print #w.movie, name$ print #w.star, mainActor$ print #w.status, "" print #w.cn, "!setfocus" return [print.db] print " R# Active casNum Name " for i = 1 to lof(#f) / 55 get #f,i rn$ = right$("000" + str$(i),3) + " " print rn$;active$;" ";casNum$;" ";name$;mainActor$ next i print return [get.movie] print #w.cn, "!contents?" input #w.cn, cNum if cNum < 2 then notice "Get error!" + chr$(13) + _ "Cassette number must be greater than 1" goto [loop] end if if cNum > lof(#f) / 55 then 'check if the record exists [get.error] notice "Get Error!" + chr$(13) + _ "This record doesn't exist" goto [loop] end if get #f, cNum if active$ <> "1" then [get.error] gosub [display.movie] goto [loop] [add.movie] gosub [GetEmptyRec] ' Find somewhere to write the new record. print #w.cn, "!contents?" input #w.cn, casNum$ gosub [write.record] print #w.status, "Movie: " + casNum$ + " has been added." print "DB After Add new Record:" gosub [print.db] goto [loop] [GetEmptyRec] get #f, 1 ' Get the Control rec cNum = val(casNum$) if cNum = 0 then ' No deleted space available cNum = lof(#f) / 55 + 1 return end if get #f, cNum ' Get the deleted rec mainActor$ = "(Control Record)" put #f, 1 ' write the Deleted rec as the new Control return [update.movie] if cNum < 2 or cNum > lof(#f) / 55 then notice "Update Error!" + chr$(13) + _ "No record to Update!" goto [loop] end if print #w.cn, "!contents?" input #w.cn, casNum$ gosub [write.record] print #w.status, "Movie: " + casNum$ + " has been updated." goto [loop] [delete.movie] if cNum < 2 or cNum > lof(#f) / 55 then notice "Delete Error!" + chr$(13) + _ "No record to delete!" goto [loop] end if get #f, 1 ' Get the Control record mainActor$ = "(deleted)" put #f, cNum ' Write it to the Deleted space casNum$ = str$(cNum) mainActor$ = "(Control Record)" put #f, 1 ' Write a new control record active$ = "" name$ = "" mainActor$ = "" print #w.cn, "!contents?" input #w.cn , casNum$ gosub [display.movie] print #w.status, "Movie: " + casNum$ + " has been deleted." print "DB After DELETE Record:" gosub [print.db] 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
Also see - Using Random files - Part 1
Also see - Using Random files - Part 3
Newsletter written by: Brosco. Comments, requests or corrections to: brosco@orac.net.au Translated from Australian to English by an American: Alyce Watson. Thanks Alyce.