Users also felt that images, and diagrams would be helpful. Due to a limited time-scale, it was not plausible to implement a graphics engine into the program. Users also felt that other multi-media features would be useful, like verbal explanations of concepts, and animations, visibly showing, say, the path of a datagram between two computers, leaping across routers and hubs. Again, due to limited time-scale, the inclusion of such multi-media abilities did not seem sensible. Some users felt that the use of a mouse as a navigation tool was appropriate, however, due to the fact that I wanted the application to run as a wimp task, for debugging and development ease, mouse control was made ever so much harder, requiring a slightly different approach to the structure of the program. This would have made the program platform-specific, that is, tied to the Acorn range of computers. Since another requirement of the users is platform independence, the use of Acorn-specific Soft Ware Interface calls is not acceptable.
Next the application needs to be running, so you must double-click the !!DB icon.
After double-clicking this icon, the main application starts up, presenting a simple help screen.
As the screen suggests, pressing the [ENTER] key causes the program
to proceed into the main section of the program, which allows the viewing
and searching of the data.
The data viewing screen looks like this:
As the hint line suggests, browsing through the data file can be done
by pressing [Q] to browse to the next page, and [A] to browse to the previous
page. Pressing [F] takes you to the search page, where specific words can
be searched for, in any of the available pages.
When you have picked a field to search in, or pressed [F] for the all
field option, which is recommended for the greatest chance of finding the
required information, the program will display a new prompt.
As this prompt directs, not you enter the word you are looking for,
however, this is a simple search, as such it does not recognise any Boolean
search strings. For instance, searching for "html OR page", will not find
anything, unless the database contains the string "html or page", as such
the better searches are those that consist of just one word, like "html".
Once a search has been made, as the new hint-line suggests, pressing
[C] will re-start the search, from the current page, looking for the same
word. Browsing to another page, or pressing [F], to start another search
will result in this search-again feature being cleared. The final key you
may press is [X] for exit. This will, not surprisingly return you to whatever
you were running before you started the program, however, the RISC-OS incarnation
requires that you close the Task Window, by clicking the [X] in the top-left
corner.
When creating the data file, the program will ask for the dimensions,
except number of pages.
In this screen, the program is requesting the number of lines per page.
This value, once set, cannot be changed by editing the file. This screen
also shows the process of creating a new file, by specifying a file name
that does not exist yet.
This screen shot shows the process of creating a file, defining the lengths of lines in the file, and the number of lines per page. This screen shot was taken just after the one above, showing the steps involved in creating the file.
After the dimensions of the file are input, the program creates the initial, empty, file. This initial file contains only one record, record 0. This record should be used to describe the future contents of the fields, as this record it that that is both displayed on startup, and as the template for the search-screen, for the users, and also as the sort-screen template.
Initially, this mode looks similar to the normal viewing mode. However, there are extra keys that are available, for example, [E] to start editing a record. When starting a new file, there in only one record, or page. The suggested first step here is to edit page 0, describing the contents of each field. The next step will be to add another page. To add a page to the end of the file, press [U]. Then, navigate to this new, blank, page by pressing [A], and fill the field as needed. You can keep sticking another record to the end of the file, and editing it as needed. However, you must remember, there is a maximum limit of 200 pages. Remembering that page 0 also counts, the highest page number of 199.
Then, an array describing, for each field in a record, the size of the field. Thus, we now have a complete description of how the header of the file is laid out.
In sumary: [Number of fields],[Number of records],[Length of field 1],[Length of field 2]...[End of header]
Directly after the header, the data is stored, this time in direct-access mode, in the format of [Record 1, field 1], [Record 1, field 2]...[Record 2, field 1],[Record 2, field 2] etc. The direct-access nature of this section of the file means that any field of any record can be directly accessed, both read from and written to, which can improve the speed at which a total data-write can take, since only those records that need updating get written to, meaning less data which must be written to disk, however, in this program, this feature has not been implemented, since it provides little gain for the amount of work required to achieve it.
20 : ON ERROR OSCLI "close":REPORT:PRINT " on line ";ERL:END
30 : Changefilename=FALSE
40 : Searched_Record=FALSE
50 : REM DEBUG = TRUE
60 : DEBUG=FALSE
70 : REM Bad programming practice to do this... OSCLI "close"
80 : OSCLI "dir <idb$dir>.data"
90 : REM An Internet Jargon-Buster. By Iain Thomas. Computing Coursework. Very Important!
100 : CLS
110 :
120 : REM We don't define a main() procedure, not in basic anyway.
130 : REM Start of Program
140 : REM Draw a screen. To say Hello, and wait for a keypress.
150 : PROC_Screen(1)
160 : PROC_Screen(2)
170 :
180 : REM Load the data to data$()
190 : PROC_Initialise
200 :
210 : IF DEBUG THEN CLS
220 : REM Just to tidy up the DEBUGGING sessions!!
230 : REM This is for when the user has selected Edit Mode.
240 : CASE EMODE OF
250 : WHEN TRUE: PROC_Screen(3) : PROC_Edit : PROC_Screen(2)
260 :
270 : WHEN FALSE: PROC_Screen(4) : PROC_View
280 : ENDCASE
290 : PROC_CloseFile
300 : CLS
310 :
320 : PRINT "End of Program"
330 : REM
340 :
350 : REM THE PROGRAM ENDS HERE, EXCEPT FOR PROCs AND FNs
360 :
370 :
380 : REM All below THIS line, PROCs and FNs OnLy!!!
390 : END
400 : REM PROC_Initialise To initialise the arrays, and load the data.
410 : DEFPROC_Initialise
420 : Curpage=0
430 : Array_Set_Up=FALSE
440 : REM open da file.
450 : PROC_File_open
460 : REM Load da data.
470 : PROC_File_read
480 : REM That *ShOuLd* be all.
490 : ENDPROC
500 :
510 : REM PROC_Screen : To draw screens, menus etc. Screens listed below.
520 : REM Screen 1 is a welcome screen.
530 : REM Screen 2 clears the screen, and invites the user to wait.
540 : REM Screen 3 informs the user if they pressed E for Edit Mode. Will also provide instructions of how to use the edit mode.
550 : REM Screen 4 is to Display the first page of data, and provide for scrolling between records.
560 : REM Screen 5 is to Display the page of data for editing.
570 : REM Screen 6 is to intro the edit system.
580 : DEFPROC_Screen(screen)
590 : CASE screen OF
600 :
610 : WHEN 1
620 : CLS
630 : PRINT "Welcome to my Internet Learning System!"
640 : PRINT "By Iain Thomas (A-Level Computer science project)"
650 : PRINTTAB(0,10);"Press [ENTER] key to continue..."
660 : PRINTTAB(0,11);"Press [E] key to enter edit mode!"
670 : PRINTTAB(0,12);"Press [F] key to toggle file name prompting (change active file)."
680 : REM Provide a way of changing the active filename: mostly for testing purposes...
690 : REPEAT
700 : A=GET
710 : CASE A OF
720 : WHEN 70,102
730 : Changefilename=NOT Changefilename
740 : WHEN 68,100
750 : DEBUG=NOT DEBUG
760 : WHEN ASC("X"),ASC("x")
770 : END
780 : OTHERWISE
790 : ENDCASE
800 : IF Changefilename THEN PRINTTAB(5,6);"File name WILL be asked for." ELSE PRINTTAB(5,6);SPC(28)
810 : IF DEBUG THEN PRINTTAB(5,5);"Running in DEBUG mode (Press [D] to cancel)!" ELSE PRINTTAB(5,5);SPC(44)
820 : UNTIL A<>70 AND A<>102 AND A<>100 AND A<>68
830 : CASE A OF
840 : WHEN69,101: EMODE=TRUE
850 : OTHERWISE:
860 : EMODE=FALSE
870 : ENDCASE
880 : WHEN 2
890 : CLS
900 : PRINTTAB(5,1);"Please Wait: File operations in progress"
910 : WHEN 3
920 : CLS
930 : PRINT "Editing Mode; Press a key!"
940 : PRINT"Press [U] to append a record to the end of the file."
950 : PRINT"Use [Q] and [A] to page through the data."
960 : PRINT"Use [F] to Search for data, and [C] to find again."
970 : PRINT"Use [I] to insert a record, and move current record (and all after) towards end of file."
980 : PRINT"Use [E] to switch to field editor, and use [Q] and [A] to select field."
990 : PRINT"Once selected, press [E] to edit the field."
1000 : PRINT"Then [Enter] to return to record-display."
1010 : PRINT"Use [S] to sort the data."
1020 : PRINT"Then [X] to save the datafile, and exit."
1030 : A=GET
1040 : CLS
1050 : WHEN 4
1060 : PRINTTAB(1,1);"The Internet"
1070 : PRINTTAB(2,2);"Page: ";Curpage;" of ";Numpages;". " :REM Spaces to get rid of unwelcome full-stops.....
1080 : PRINTTAB(2,15);"Use [Q] and [A] to navigate, [F] to find data, or [X] to exit. "
1090 : WHEN 5
1100 : PRINTTAB(40,1);"Selected field is ";eField
1110 : PRINTTAB(0,2);"Data is ";data$(Selected_Record,eField);STRING$(80," ")
1120 : PROC_DataScreen(Selected_Record)
1130 : PROC_EScreenMarkeField(eField)
1140 : WHEN 6
1150 : PRINTTAB(0,0);"Editing record ";Selected_Record;SPC(1)
1160 : PRINTTAB(0,1);"Select Field with [Q] and [A] Edit with [E]!"
1170 : WHEN 7
1180 : PRINTTAB(0,0);"Sort Records by field Press [Enter] to sort..."
1190 : WHEN 8
1200 : PRINTTAB(0,0);"Search Records; Please select the field to search in, and press [Enter]."
1210 : PRINTTAB(0,1);"Press [F] to search all fields."
1220 : WHEN 9
1230 : PRINTTAB(0,0);"Please enter the text you are looking for."
1240 : WHEN 10
1250 : CLS
1260 : PRINTTAB(0,17);"Your text was found in record ";Curpage
1270 : REM PRINTTAB(0,1);"Here is the record. Please press a key to return to Viewing mode."
1280 : PROC_DataScreen(Curpage)
1290 : REM A=GET : CLS
1300 : PROC_Screen(4)
1310 : WHEN 11
1320 : CLS
1330 : PRINTTAB(0,17);"Your text was not found. Sorry about that!"
1340 : PRINTTAB(0,18);"Please press a key!":SOUND 1,-10,200,2
1350 : A=GET : CLS
1360 : PROC_Screen(4)
1370 : WHEN 12
1380 : CLS
1390 : PRINTTAB(0,17);"Sorry, there is no more room for another record!"
1400 : PRINTTAB(0,18);"Please press a key!":SOUND 1,-10,200,2
1410 : A=GET : CLS
1420 : PROC_Screen(4)
1440 : ENDCASE
1450 :
1460 : ENDPROC
1470 :
1480 : DEFPROC_ClearStatusLine
1490 : PRINTTAB(0,17);STRING$(80," ")
1500 : ENDPROC
1510 :
1520 : REM PROC_View: To be used to run the actual viewing of the data.
1530 : DEFPROC_View
1540 : REPEAT
1550 : PRINTTAB(2,2);"Page: ";Curpage;" of ";Numpages;". " :REM Spaces to get rid of unwelcome full-stops.....
1560 : PROC_DataScreen(Curpage)
1570 : A=GET
1580 : CASE A OF
1590 : WHENASC("Q"),ASC("q")
1600 : IF Curpage+1<=Numpages THEN Curpage=Curpage+1
1610 : Searched_Record=FALSE
1620 : WHENASC("A"),ASC("a")
1630 : IF Curpage-1>=0 THEN Curpage=Curpage-1
1640 : Searched_Record=FALSE
1650 : WHENASC("F"),ASC("f")
1660 : PROC_FindInterface(0)
1670 : WHENASC("C"),ASC("c")
1680 : IF Searched_Record=TRUE THEN PROC_FindInterface(1)
1690 : ENDCASE
1700 : PROC_ClearStatusLine
1710 : CASE Searched_Record OF
1720 : WHEN FALSE
1730 : PRINTTAB(0,15);"Use [Q] and [A] to navigate, [F] to find data, or [X] to exit. "
1740 : WHEN TRUE
1750 : PRINTTAB(0,15);"Use [Q] and [A] to navigate, [C] to Find Again, or [X] to exit."
1760 : ENDCASE
1770 :
1780 : UNTIL A=88 OR A=120
1790 :
1800 : ENDPROC
1810 :
1820 : REM PROC_FindInterface(mode): Provides a user interface for the search function, allowing the user to look for data in any field... Mode 0 is for new searches, Mode 1 is to resume a search.
1830 :
1840 : DEFPROC_FindInterface(mode)
1850 : CLS
1860 : IF mode=0 THEN
1870 : PROC_Screen(8)
1880 : PROC_DataScreen(0)
1890 : eField=0
1900 : Selected_Record=0
1910 : REPEAT
1920 : PROC_EScreenMarkeField(eField)
1930 : A=GET
1940 : CASE A OF
1950 : WHENASC("G"),ASC("g")
1960 : searchfield=eField
1970 : e=TRUE
1980 : WHENASC("A"),ASC("a")
1990 : IF eField<fields-1 THEN eField=eField+1
2000 : e=FALSE
2010 : WHENASC("Q"),ASC("q")
2020 : IF eField>0 THEN eField=eField-1
2030 : e=FALSE
2040 : WHEN13
2050 : searchfield=eField
2060 : e=TRUE
2070 : WHENASC("F"),ASC("f")
2080 : all_fields=TRUE
2090 : searchfield=0
2100 : e=TRUE
2110 : OTHERWISE
2120 : e=FALSE
2130 : ENDCASE
2140 : UNTIL e=TRUE
2150 :
2160 : CLS
2170 : PROC_Screen(9)
2180 : INPUT searchtext$
2190 :
2200 : REM Mode <> 0 (=1), so we're doing a continue-search...
2210 : ENDIF
2220 : Searched_Record=TRUE
2230 : foundpage=FN_Find(searchtext$,searchfield,Selected_Record)
2240 : IF foundpage<>-1 THEN Curpage=foundpage:Selected_Record=Curpage+1:PROC_Screen(10) ELSE PROC_Screen(11)
2250 : ENDPROC
2260 :
2270 : REM PROC_Edit shows the user the records: press [ENTER] to edit record(page).
2280 : REM ALSO save the data on ending...
2290 : DEFPROC_Edit
2300 : PROC_Screen(4)
2310 : REPEAT
2320 : PRINTTAB(2,2);"Edit Page: ";Curpage;" of ";Numpages;". " :REM Spaces to get rid of unwelcome full-stops.....
2330 : PROC_DataScreen(Curpage)
2340 : A=GET
2350 : CASE A OF
2360 : WHENASC("Q"),ASC("q")
2370 : IF Curpage+1<=Numpages THEN Curpage=Curpage+1
2380 : WHENASC("A"),ASC("a")
2390 : IF Curpage-1>=0 THEN Curpage=Curpage-1
2400 : WHENASC("E"),ASC("e")
2410 : Selected=Curpage
2420 : PROC_EditRec(Selected)
2430 : PROC_Screen(4)
2440 : WHENASC("I"),ASC("i")
2450 : PROC_Insert_Record(Curpage)
2460 : WHENASC("U"),ASC("u")
2470 : PROCAdd_Record
2480 : WHENASC("S"),ASC("s")
2490 : PROC_SortInterface
2500 : OTHERWISE
2510 :
2520 : ENDCASE
2530 : PROC_ClearStatusLine
2540 :
2550 : UNTIL A=88 OR A=120
2560 : PROC_Data_Save
2570 : ENDPROC
2580 :
2590 : REMPROC_EditRec(Selected_Record): Provide an interface for choosing a field to edit. This will provide the text-input routine. Selected Record must be the record chosen for editing. There is no way to change the edited field from this routine.
2600 : DEFPROC_EditRec(Selected_Record)
2610 : CLS
2620 : PROC_Screen(6)
2630 : eField=0
2640 : REPEAT
2650 : PROC_Screen(5)
2660 : A=GET
2670 : CASE A OF
2680 : WHENASC("A"),ASC("a")
2690 : IF eField<fields-1 THEN eField=eField+1
2700 : WHENASC("Q"),ASC("q")
2710 : IF eField>0 THEN eField=eField-1
2720 : WHENASC("E"),ASC("e")
2730 : CLS
2740 : PRINTTAB(25,2);STRING$(fieldlengths(eField),"-")
2750 : INPUT TAB(1,1);"New field data, please?",in$
2760 : IF LEN(in$)>fieldlengths(eField) THEN
2770 : PRINT "Please stick to ";fieldlengths(eField);" characters! Press a key." : A=GET
2780 : ELSE
2790 : data$(Selected_Record,eField)=in$
2800 : ENDIF
2810 : CLS : PROC_Screen(6):PROC_Screen(5)
2820 : ENDCASE
2830 : UNTIL A=13
2840 : CLS
2850 : ENDPROC
2860 :
2870 : REMPROC_SortInterface: Prompts the user to select field to sort by, then uses the bubblesort alogarithm to sort it.
2880 : DEFPROC_SortInterface
2890 : CLS
2900 : PROC_Screen(7)
2910 : eField=0
2920 : Selected_Record=0
2930 : REPEAT
2940 : PROC_Screen(5)
2950 : A=GET
2960 : CASE A OF
2970 : WHENASC("A"),ASC("a")
2980 : IF eField<fields-1 THEN eField=eField+1
2990 : WHENASC("Q"),ASC("q")
3000 : IF eField>0 THEN eField=eField-1
3010 : WHEN13
3020 : PROCSortData(eField)
3030 : ENDCASE
3040 : UNTIL A=13
3050 : CLS
3060 : ENDPROC
3070 :
3080 :
3090 : REM PROC_DataScreen(pagenum): To be used for filling in the data in screen 4. Parameter is the record (or page number)
3100 : DEFPROC_DataScreen(pagenum)
3110 : FOR loop_field=0 TO fields-1
3120 :
3130 : PRINTTAB(12,5+loop_field);SPC(fieldlengths(loop_field))
3140 : IF pagenum>=0 THEN PRINTTAB(12,5+loop_field);data$(pagenum,loop_field) ELSE PRINTTAB(12,5+loop_field);"Data"
3150 :
3160 : NEXT loop_field
3170 : ENDPROC
3180 :
3190 : REM PROC_EScreenMarkeField(mrk)
3200 : DEFPROC_EScreenMarkeField(mrk)
3210 : FOR clm=0 TO fields-1
3220 : PRINTTAB(9,5+clm);" "
3230 : NEXT clm
3240 : PRINTTAB(9,5+mrk);"->"
3250 : ENDPROC
3260 :
3270 : REM Proc-Table: For database engine.
3280 : REM PROC_Set_pointer : To point the file-pointer at a particular record and field (working now)
3290 : REM PROC_File_open : To open and initialise the database file. Setting variables
3300 : REM PROC_File_read : To read the data in. (From main% disk file TO data$())
3310 : REM PROC_Data_save : To write the data in data$() into the main% disk file (filename$)
3320 :
3330 : REM Procedure to point the pointer at the start of the record and field (data item) passed.
3340 :
3350 : DEFPROC_Set_pointer(record,field)
3360 :
3370 : REM Start_of_data_offset=40
3380 : REM WE'D BETTER HAVE THE FILE-DIMENSIONS SET UP FOR THIS, OR ALL HELL WILL BREAK LOSE!!!...
3390 : length_of_record=0
3400 : FOR loop=0 TO fields-1
3410 : length_of_record=length_of_record+fieldlengths(loop)+2
3420 : NEXT loop
3430 : IF DEBUG THEN PRINT "Set Rec: ";record;" Set fld: ";field;" RecLen: ";length_of_record
3440 : record_offset=0
3450 : IF DEBUG THEN PRINT "Data starts at: ";Start_of_data_offset
3460 : IF field>0 THEN
3470 : FOR loop=0 TO field-1
3480 : record_offset=record_offset+fieldlengths(loop)+2
3490 : IF DEBUG THEN PRINT "Record offset: ";record_offset
3500 : NEXT loop
3510 : ENDIF
3520 : point=Start_of_data_offset+record_offset+(length_of_record*record)
3530 : IF DEBUG THEN PRINT "Pointer is at: ";point
3540 : PTR#main%=point
3550 : ENDPROC
3560 : REM ----- MARKER End of file opening procedure. "-----"
3570 :
3580 : DEFPROC_CloseFile
3590 : CLOSE #main%
3600 : ENDPROC
3610 :
3620 : DEFPROC_File_open
3630 : REM ----- MARKER start of File-opening procedure. "-----"
3640 : REM This has to be here, and MUST ONLY BE CALLED ONCE, since Archamedies BASIC don't approve of arrays being redimensioned.
3650 : IF NOT Array_Set_Up THEN
3660 : REM 10 is chosen as a sensible maximum number of fields, since otherwise, they would over-write the help text. Max number of pages is 200, since we can't use dymanic arrays...
3670 : DIM data$(200,10)
3680 : DIM fieldlengths(10)
3690 : ENDIF
3700 : Array_Set_Up=TRUE : REM Just in case it is called again.
3710 : REM Do we have a last File Name??
3720 : z%=OPENIN("^.lastfile/d")
3730 : REM ON ERROR Sucess=FALSE
3740 : Sucess=TRUE
3750 : IF DEBUG THEN PRINT "Pre-input Sucess: ";Sucess
3760 : IF DEBUG THEN PRINT "z% (^.lastfile/dat access channel) = ";z%
3770 : REM This next line has caused no end of problems: the newline was in the wrong place, so the interpreter always executed the first set of instructions, instead of the conditional execution that I was expecting.
3780 : IF z%<>0 THEN
3790 : INPUT#z%,filename$
3800 : Sucess=TRUE
3810 : IF DEBUG THEN PRINT "Executing as if z% NOT 0"
3820 : ELSE
3830 : Sucess=FALSE
3840 : filename$=""
3850 : IF DEBUG THEN PRINT "Executing as if z% IS 0"
3860 : ENDIF
3870 : IF DEBUG THEN PRINT "^.lastfile returned filename: ";filename$
3880 : IF DEBUG THEN PRINT "Post-input Sucess: ";Sucess
3890 : REM No ^.lastfile/d present... OR read failed. Using the fact that if a file is opened for input, and it does not exist, the file channel returned is nought(0).
3900 : REM Sucess=FALSE
3910 : IF Changefilename=TRUE THEN Sucess=FALSE
3920 : WHILE Sucess=FALSE
3930 : PRINT "A File Name, please (press [ENTER] to quit) (* to see file list)...???"
3940 : INPUT filename$
3950 : Sucess=TRUE
3960 : REM Get out of the GOTO problem.
3970 : IF filename$="" THEN OSCLI "close" : END
3980 : IF filename$="*" THEN
3990 : CLS:PRINT "Directory Listing"
4000 : OSCLI "."
4010 : Sucess=FALSE
4020 : ENDIF
4030 : ENDWHILE
4040 : CLOSE#z%
4050 : REPEAT
4060 : IF DEBUG THEN OSCLI "."
4070 : REM We should have a file name by now, but we don't know if it exists..
4080 : tempfile%=OPENIN(filename$)
4090 : IF tempfile%=0 THEN
4100 : PRINT "File does not exist, Create and edit it?(Y/N)"
4110 : CASE GET OF
4120 : WHEN ASC("Y"), ASC("y")
4130 : PROC_DefineDatabase
4140 : EMODE=TRUE
4150 : fields=Lines
4160 : records=1
4170 : Numpages=0
4180 :
4190 : main%=OPENOUT(filename$)
4200 : PROC_Data_Save
4210 : CLOSE#main%
4220 :
4230 : REM Deal with a non-existant file: to create and define one.
4240 : OTHERWISE
4250 : filename$=""
4260 : ENDCASE
4270 : ENDIF
4280 : CLOSE#tempfile%
4290 : IF NOT (filename$="") THEN main%=OPENUP(filename$):CLS:PTR#main%=0
4300 : IF DEBUG THEN PRINT "File name is " , filename$ : REM Just a little debugging...
4310 : IF filename$="" THEN Sucess=FALSE: ERROR 0, "Quit: No File Error!!" : REM Because we don't have a file.
4320 : UNTIL Sucess
4330 : z%=OPENOUT("^.lastfile/d")
4340 : PRINT#z%, filename$
4350 : CLOSE#z%
4360 :
4370 : REM ----- MARKER end of File Opening procedure. "-----"
4380 : ENDPROC
4390 :
4400 : DEFPROC_File_read
4410 : REM ----- MARKER Start of File-initialization procedure "-----"
4420 : INPUT#main%,fields
4430 : INPUT#main%,records
4440 : Numpages=records-1
4450 : IF DEBUG THEN PRINT "Fields: ";fields;" Records: ";records
4460 : IF records>0 THEN
4470 : IF DEBUG THEN PRINT "Reading Data Record from file"
4480 : FOR loop=0 TO fields-1
4490 : INPUT#main%,fieldlengths(loop)
4500 : IF DEBUG THEN PRINT "Fieldlength ";loop;" returned: ";fieldlengths(loop)
4510 : NEXT loop
4520 : Start_of_data_offset=PTR#main% :REM This doesn't seem to work... PTR#main% OKOK, it workz
4530 :
4540 : REM Reminder to oneself, we start at record 0, field 0
4550 : FOR loop_record=0 TO records-1
4560 : FOR loop_field=0 TO fields-1
4570 : PROC_Set_pointer(loop_record,loop_field)
4580 : INPUT#main%,data$(loop_record,loop_field)
4590 : IF DEBUG THEN PRINT "Rec: ";loop_record;" Fld: ";loop_field;" = ";data$(loop_record,loop_field)
4600 : NEXT loop_field
4610 : NEXT loop_record
4620 : ENDIF
4630 :
4640 : REM ----- MARKER end of file-initialization procdure. "-----"
4650 :
4660 : ENDPROC
4670 :
4680 : DEFPROC_Data_Save
4690 : REM ----- Start of Data Saving procedure "-----"
4700 : REM Save da DATA, if possible. If not, then we bomb out...
4710 : PRINT "Writing Data Record..." :REM Just to let the user know what is going on...
4720 : PTR#main%=0
4730 : PRINT#main%,fields
4740 : PRINT#main%,records
4750 : FOR loop=0 TO fields-1
4760 : PRINT#main%,fieldlengths(loop)
4770 : NEXT loop
4780 : Start_of_data_offset=PTR#main% :REM This is to prevent hell from breaking loose...
4790 :
4800 : FOR loop_record=0 TO records-1
4810 : FOR loop_field=0 TO fields-1
4820 : PROC_Set_pointer(loop_record,loop_field)
4830 : PRINT#main%, data$(loop_record,loop_field)
4840 : NEXT loop_field
4850 : NEXT loop_record
4860 : REM ----- End of Data Saving procedure "-----"
4870 : ENDPROC
4880 :
4890 : REM PROC_DefineDatabase. This procedure is to be executed when a new database is created. It will provide facilities for choosing the lines/page, and the chars per line, although it may be more efficient to hard-code number of lines, and, characters..
4900 : REM per line...
4910 : DEFPROC_DefineDatabase
4920 : PRINT "Please enter the number of lines you wish to have per screen?"
4930 : REPEAT
4940 : PRINT "Suggest 7, Minimum is 1, Maximum is 10"
4950 : INPUT Lines
4960 : CASE Lines OF
4970 : WHEN Lines<1 : PRINT "Erm, I said MINIMUM is 1!"
4980 : WHEN Lines>10: PRINT "Erm, I said MAXIMUM is 10!"
4990 : ENDCASE
5000 : UNTIL Lines >= 1 AND Lines <= 10
5010 : FOR i=0 TO Lines-1
5020 : REPEAT
5030 : PRINT "Number of chars for line ";i;" (1 to 50) Suggest 40"
5040 : INPUT f
5050 : CASE f OF
5060 : WHEN f<1: PRINT "Erm, I said MINIMUM is 1!"
5070 : WHEN f>50:PRINT "Erm, I said MAXIMUM is 50!"
5080 : ENDCASE
5090 : UNTIL f>=1 AND f<=50
5100 : fieldlengths(i)=f
5110 : NEXT i
5120 : ENDPROC
5130 :
5140 : REM This procedure is to be called by the edit routine, when [I] is pressed, to insert a record in the file, or at the end. Where the record is to be inserted (ie, the new record is created, and the existing one, and ones after it are moved towards
5150 : REM the end of the file.)
5160 : DEFPROC_Insert_Record(InsRec)
5170 : IF records <200 THEN
5180 : FOR loop_rec=records TO InsRec STEP -1
5190 : FOR loop_flds= 0 TO fields
5200 : IF DEBUG THEN PRINT "loop_rec=";loop_rec;" loop_flds=";loop_flds
5210 : data$(loop_rec+1,loop_flds)=data$(loop_rec,loop_flds)
5220 : NEXT loop_flds
5230 : NEXT loop_rec
5240 :
5250 : FOR loop_flds= 0 TO fields
5260 : IF DEBUG THEN PRINT "InsRec=";InsRec
5270 : data$(InsRec,loop_flds)=""
5280 : NEXT loop_flds
5290 :
5300 : records=records+1
5310 : Numpages=Numpages+1
5320 : ELSE
5330 : PROC_Screen(12)
5340 : ENDIF
5350 : ENDPROC
5360 :
5370 : REM Since PROC_Insert_Record doesn't allow for adding a record to the end of the file, I must also create a proc to add a record onto the end...
5380 : REM PROCAdd_Record. Does exactly what it says...
5390 : DEFPROCAdd_Record
5400 : IF records <200 THEN
5410 : records=records+1
5420 : Numpages=Numpages+1
5430 : ELSE
5440 : PROC_Screen(12)
5450 : ENDIF
5460 : ENDPROC
5470 :
5480 : REM PROCSortData(KeyField): sorts the data in data$(,), in ascending order of KeyField.
5490 : REM PROCBubble(item): Used exclusivly by PROCSortData...
5500 :
5510 : DEFPROCSortData(KeyField)
5520 : REPEAT
5530 : REPEA=FALSE
5540 : FOR I = 0 TO records-2
5550 : IF FN_Upper(data$(I,KeyField)) > FN_Upper(data$(I+1,KeyField)) THEN
5560 : IF DEBUG THEN PRINT data$(I,KeyField) ; " is MORE than " ; data$(I+1,KeyField)
5570 : IF DEBUG THEN PRINT "I=";I
5580 : PROCBubble(I)
5590 : REPEA=TRUE
5600 : ENDIF
5610 : NEXT I
5620 : UNTIL REPEA=FALSE
5630 : IF DEBUG THEN A=GET
5640 : ENDPROC
5650 :
5660 : DEFPROCBubble(item)
5670 : FOR M=0 TO fields
5680 : sTEMP$=data$(item,M)
5690 : data$(item,M)=data$(item+1,M)
5700 : data$(item+1,M)=sTEMP$
5710 : NEXT M
5720 : ENDPROC
5730 :
5740 :
5750 : REM FN_Upper$(outstr$): Will take a string, and return the string, in uppercase characters. Will not affect numbers/punctuation etc. Used for sorting/searching data...
5760 :
5770 : DEFFN_Upper(instr$)
5780 :
5790 : outstr$=STRING$(LEN(instr$)," ")
5800 :
5810 : FOR loop=1 TO LEN(instr$)
5820 : IF ASC(MID$(instr$,loop,1)) >= 97 AND ASC(MID$(instr$,loop,1)) <= 122 THEN
5830 : MID$(outstr$,loop,1)=CHR$(ASC(MID$(instr$,loop,1))-(97-65))
5840 : ELSE
5850 : MID$(outstr$,loop,1)=MID$(instr$,loop,1)
5860 : ENDIF
5870 :
5880 : NEXT loop
5890 : =outstr$
5900 :
5910 : REM DEF_FN_Find(findtext$,findfield%,startfrom%): This function will find the specified data in any record, in the specified field, starting from a specified record.
5920 : REM Result will be -1 if not found, or else the record number the data was found in.
5930 :
5940 : DEFFN_Find(findtext$,findfield%,startfrom%)
5950 : IF findfield%=-1 THEN all_fields=1 ELSE all_fields=0
5960 : foundrecord=-1
5970 :
5980 : I=startfrom%
5990 :
6000 : IF all_fields=TRUE THEN
6010 :
6020 : REPEAT
6030 : findfield%=findfield%+1
6040 : IF INSTR(FN_Upper(data$(I,findfield%)),FN_Upper(findtext$)) <>0 THEN foundrecord=I
6050 :
6060 : IF findfield%=fields THEN I=I+1:findfields%=-1
6070 : UNTIL foundrecord <> -1 OR I > records-1
6080 :
6090 : ELSE
6100 :
6110 : REPEAT
6120 : IF INSTR(FN_Upper(data$(I,findfield%)),FN_Upper(findtext$)) <>0 THEN foundrecord=I
6130 : I=I+1
6140 : UNTIL foundrecord <> -1 OR I > records-1
6150 :
6160 : ENDIF
6170 :
6180 : =foundrecord
This system diagram shows the process of transferring data from the source documents, as the data is typed in on the keyboard, to the left, the file is created, and data added to it, as the process, and the new data file is output to the right. The system diagram does not show, for clarity, the validation processes that validate the incoming data. Specifically, keyed in data is checked for the correct range, when specifying field sizes, for example. Strings are also checked to ensure that they are not too long. Errors and user feedback is where the feedback from the data input is sent, since it would make little sense to store these in the data file. These are therefore reported back to the user, indicating what corrective action needs to be taken,
This system diagram shows the old data taken from the old file, and how it is merged with new data, to produce the new data file. This new data can either be added to the old data, adding records, or it can replace the old data, changing the records. Alternatively, the new data can be an instruction to abandon the record, so deleting a record. However, deleting records is not implemented in my program, since it was not specifically requested, and would have been complex to toce. Again, any errors are fed back to the user via the screen, directing them as to what corrective action may be required.
This diagram shows the processes involved in viewing the data. It shows how the data file is taken in as an input to the browsing engine, as are the user commands. These two inputs allow the user to browse through the file. The browsing engine performs all the reading of the data file, and all the searching tasks.
The next bug was found when testing the program's ability to use a data file with a different number of records. Reducing this number then caused the program to malfunction, reporting that the FieldLengths() array caused an Out of Range error. This was later found to have been caused by using the wrong variable in it's definition. Rather than use Fields to define its size, I had used Records. This meant that while testing a file with the same number of records as fields, like 3*3, the error would not be found. Also, when testing a file with mode records than fields, again, this array would be over-sizes, but that would not generate the error, neither would it generate unexpected behaviour.
Now those two major bugs are removed, I looked at how the code appeared to be organised, and realized that I needed to do a lot of tidying-up work, so I began the process of splitting the different code sections into distinct procedures and functions.
I needed to write a procedure to keep track of the last file which was opened, called "Lastfile/DAT", it contains a single record, written in sequential mode, which records the file name of the last file opened or edited, allowing that file to be re-opened immediately, without the user having to specify a file name to open. However, my initial implementation of the procedure which checked for the presence of both lastfile/dat and the data file, was dependant on the operating system flagging an error when an attempt was made to open a non- existant file. This procedure, however, is both vulnerable to interference by other factors, such as hitting [ESCAPE] during the open attempt would lead the program to believe the file did not exist, and the operating system did not flag the error if the file was to be opened in read/write mode. Some operating systems may only flag the error when an attempt is made to read from the file. This procedure, therefore must be platform-specific, which runs contrary to the user requirements. The use of ON ERROR to handle this is also quite inefficient, and adds the danger that the program may get caught in a loop, if the line that restores the error handler to it's original state causes an error. As this technique also uses GOTO statements, it is incompatible with the new modular approach to the code, causing errors relating to the use of GOTO within a procedure. This forced me to open the file, as suggested in the ARM Basic reference, for read mode, and check if the channel number returned by OpenIN() is zero. During the development of the reasonably simple test on the channel number, another hole was uncovered, in my coding. The symptoms were that LastFile/DAT was always treated as non- existant. This was caused by a space at the end of IF <condition> THEN(space) when used in a multi-line IF statement. To fix, the space was removed. This approach now leaves the file opening procedures in a stable state.
The final bug that I found related to this, was caused by the capitalisation of "Records". This was causing one of the fields in the file header to be written out as zero. This was one problem introduced when defining a database, using the Define_Database procedure, as it led to part of the saving loop being re-written, to support the variable file geometry, and I accidentally replaced the lower-case "r" with an upper-case one "R".
Once this sorting algorithm had been implemented, I now found that I was also inserting a blank record at the front. This was happening, because, the searching loop found a record past the end, which was blank, and hence always came before the other records. This was fixed by ensuring that the sort-engine was always passed a valid last record number, and not the number of records. Having, for instance, 4 records, 0;1;2;3. giving the sort-engine the number 4, lead it to sort records 0;1;2;3;4. Since 4 was past the end of the known data, it was blank, hence the strange problems.