SEQUENTIAL / RANDOM ACCESS
FILE UTILITY
By
Larry Kenny
Edited and Annotated By
David Solly
HTMLized and Edited By
William McBrine
Most of the editing was done for the sake of saving the reader's eye-sight and for easier transfer to electronic media such as this web site. Otherwise, this instruction manual is as Larry Kenny wrote it.
David Solly
Bibliotheca Sagittarii
Ottawa, Ontario
March 24, 2000
Sequential random/access file utility / by Larry Kenny. – Edited and annotated by David Solly. – Ottawa, ON : Bibliotheca Sagittarii, ©2000.
– "Larken Electronics, Navan ©1988"-t.p.
– Includes index.
Built into every T/S 2068 is the capability to use up to fifteen devices for data input and output. The different devices are connected, in software, through the T/S 2068's channels. The main devices used for the T/S 2068 output are the upper screen, lower screen and the printer. The main input device is the keyboard. The commands PRINT, INPUT and INKEY$ are used to send and retrieve data from these or any other devices. The commands in their plain form default to the commonly used channels.
Example:
| Command | Default Channel | Description |
| #2 | Send output to the upper screen. |
|
| LPRINT | #3 | Sent output to the T/S 2040 printer. |
| INPUT | #0 | Input data from the keyboard. Print to the lower part of
the screen (Ch#0). |
| INKEY$ | #0 | Read from the keyboard. |
All these commands can be directed to other channels by using a channel identifier after the command.
Examples:
10 PRINT #0; "HELLO"
This line will print the word "HELLO" on the lower part of the screen.
10 PRINT #3; "HELLO"
This line will print the word "HELLO" on the printer.
INPUT # and INKEY$ # can also be used to read data from channels other than the keyboard (Ch0).
The LKS/R utility allows you to send data or read data from the disk drive using PRINT #, INPUT #, or INKEY$ #. The command syntax for PRINT #, INPUT #, and INKEY$ # is the same as for INPUT, PRINT, and INKEY$.
Note:
The LKS/R uses the same command structure as LKDOS. LKS/R commands are preceded by a RANDOMIZE USR 26800. The LKS/R is resident in RAM just below the memory location PROG. Don't confuse the PRINT # and INPUT # commands with the «PRINT #4:» command prefix used for LKDOS or Larken Extended BASIC.
The PRINT #, INPUT # and INKEY$ # commands which are used to send and read data from a file are not preceded by the LKDOS «RANDOMIZE USR» prefix.
The LKS/R uses the OPEN # command in two modes: output mode and random access mode. The syntax is:
RANDOMIZE USR 26800: OPEN# channel, "file name", OUT : REM Output type
RANDOMIZE USR 26800: OPEN# channel, "file name", RND : REM Random type
(OUT and RND are tokens on the «O» and «T» keys. channel is a channel number from 2 to 15)
Here's an example program that opens a file as output, then sends data to the file, then closes the file:
10 REM Create file program
20 RANDOMIZE USR 26800: OPEN# 7, "TEST",OUT
30 FOR A = 1 TO 10
40 INPUT #7; "THIS IS RECORD # "; A
50 NEXT A
60 RANDOMIZE USR 26800: CLOSE# 7
Running this program will create a file on the disk. To see the contents of this file type the following LKDOS command:
RANDOMIZE USR 100: PRINT "TEST".
The next example program will read the file back a record at a time using the INPUT # command. The file is opened as a random type:
10 REM Read file records
20 RANDOMIZE USR 26800: OPEN# 7,"TEST",RND
30 INPUT #7; A$;
40 PAUSE 60: REM Delay to show records are read one at a time
50 PRINT A$
60 GOTO 30
You will have noticed that the T/S 2068 makes a noise when using the INPUT # command. This is just a small bug in the T/S 2068 ROM left over from the key scan routine.
An End of File error is produced when a file is read right to the very end. Even though the file is at the end, it's still open. You can move the file pointer to the start of the file by using the command PRINT #7; TAB 0; (described later on), or you can close the file and re-open it.
Warning!
An open file (output or random) must be closed before you remove the disk
from the drive. Failing to do so will corrupt the data on the disk.
Here is another example of reading a file — this time using the INKEY$ # command. INKEY$ reads a character at a time and does not produce the key click noise.
Warning!
Be sure to close the file from the previous program with
RANDOMIZE USR 26800: CLOSE# 7 before going further.
10 REM Read file using INKEY$
20 RANDOMIZE USR: 26800: OPEN# 7, "TEST",RND
30 LET A$ = INKEY$ #7
50 GOTO 30
After reading the last character of a file, the LKS/R will return a CHR$(266) (i.e. STOP) as its next character before causing an End of File error. Using INKEY$ #, it's possible to detect the end of the file before an error arises.
To tell LKS/R the length of the file records (only needed when using the TAB and search command), we use the DATA command.
Example:
RANDOMIZE USR 26800; DATA channel, recordlength
Record lengths can be up to 2K but lengths of 32, 64, 138 or 256 bytes are more common.
INPUT commands can send data to a channel as well as read from it. For example, in the command INPUT "Enter Name"; a$ the INPUT command first sends the text "Enter Name" to the channel, then reads in a$, then sends a final CHR$(13) because there is not a semicolon after a$.
The correct syntax for INPUTing from a files is INPUT #channel; a$;.
Multiple inputs can be done in one command with INPUT LINE a$; LINE b$; LINE c$;
The LINE type input cannot be used for inputting numeric variables.
Records can be separated using carriage returns, apostrophes (') or commas.
Example:
PRINT #channel; "Record 1", "Record 2" ' "Record 3"
Example:
LET x = USR 26800: DATA channel, record length, "word to find".
This command will search from the current file position to the end of the file, looking for an occurrence of the specified text. If a match is found, x will be the number of records that the command had to search through to find the match. (It's the relative number of records from the initial position, not the absolute record number. To get the absolute record number, add the initial position to the return value x.) The search command can be repeated to find the next occurrences of the text string. If a match is not found, x will be 65535. The search command can only be used in random mode (RND). This command runs much faster than the equivalent BASIC routine.
The TAB function allows for true random-access filing. This is something usually only found on very expensive computers. Using the TAB function and fixed length records, records can be updated and modified; and by specifying record lengths of one half or one quarter of the actual record length, parts of a record can be pointed to directly. If you try to access a record number that doesn't exist in the file a Number Too Big error will occur.
Example:
RANDOMIZE USR 26800: OPEN# 5, "file", OUT
The LKS/R uses a 5K (5100 bytes) buffer for each file open. These start at the top of RAM above RAMTOP and descend downward 5K for each additional file opened. When a file is opened, the LKS/R will use the first available buffer closest to the top of memory.
The system variable P_RAMT (23732), minus 256 bytes for UDGs, is used to find where the top of RAM is; so if you need some memory reserved at RAMTOP for machine code routines, you can poke P_RAMT down lower to preserve high RAM. Do this before opening any files.
You'll need to move RAMTOP with a CLEAR x command, with x depending on how many files you have open at once. When the LKS/R is loaded, it clears RAMTOP down low enough for two files to be opened. To calculate what value you should clear for the maximum number of files that you'll have open at once, use: P_RAMT - 256 - (1500 * number of files open).
It may seem that 5K per buffer is a lot of memory to give up. However, when you consider that this buffer will allow the T/S 2068 to access up to 800K of stored data per disk, then it's not such a bad compromise.
Example:
10 INPUT #7; a$;
20 PAPER 0
Were you to run this, you would corrupt your file because PAPER 0 will send a control code to channel #7. To avoid any file corruption, use a PRINT; command before the attribute command to make the screen, which is channel #2, the last channel open, thus: 20 PRINT;: PAPER 0
«R» to read the next record,
«E» to edit a record,
«A» to append a new record,
«S» to search for a text string starting from the current record,
«C» to close the file, and
«N» to start a new file (though not on the master disk!).
The key points of interest are:
LBASE could have two or more files open at once, so records could be sorted to other files. This is another way of sorting the database.
Records can be inserted into the middle of a file by using two files. Open a new file as output; send a certain number of records to the new file; then send the inserted record or a blank record, and finally send the rest of the old records to the new file.
LBASE uses an unfielded record. Data is just entered in free form. Data fields could be added if required.
A more elaborate search command could be added – like the one in Profile®. One could add Boolean logic operators to do inclusive and exclusive searches. The programming for these new features could be done in machine code or compiled BASIC to improve speed.
10 RAND USR 26800: OPEN #6, "Source",RND
20 RAND USR 26800: OPEN #7, "Target",OUT
30 INPUT #6; LINE a$; : PRINT #7; a$
[TEXT APPEARS TO BE MISSING HERE]
The routine will return the character in the accumulator. A CHR$(226) signals that you've read the last byte of the file; or you could let a BASIC ON ERROR handle the end of file.
Once the address of the channel's input and output routines are found using #1230, these could be stored in memory by our routine so #1230 does not need to be called for each character. This would speed up the code significantly.
For keeping track of records, you need to keep a counter; or you could count file separators if you're sure that they're consistent.
BASIC can be compiled to significantly increase the speed of sorting, copying and manual searching. However, the OPEN, CLOSE and DATA commands will have to be left in interpreted BASIC.
The index register is used extensively in the code. The addresses of the file channels in the channel table point to entry points in the code, that just load the IX register with the address of the corresponding file information block, and then jump to the common code used for input and output for all files.
When a file is opened for output, if the file already exists, then the file information block (FIB) is set to the end of the existing data, and any new data is appended to the file. As each flock is filled, it's saved, the block number is added to the file's directory block list in the directory cell, and the block number of a new block is fetched from the track map, and marked as used in the track map. It's marked as used even before it's completely filled, because while the file is open, we don't want any other file to claim it.
When a file is opened as output, an error message will occur if a read attempt is made.
When a file is opened as RND, the FIB is set to point to the beginning of the file. The file can be read from or written to, so whenever the pointers reach the end of a block, the block is first saved, then the next block is loaded. Saving the block first ensures that any new data in the block is not lost. It's the reason for most of the disk activity as you read a RND type file. Some disk systems have a separate input-only file operation which runs faster. The sequential input in the V3 EPROM is for input only, so it can read a file much faster than the RND type in LKS/R.
Closing a file saves the block in the buffer to disk, disconnects the stream that points to the channel, marks the file closed in the FIB and, if the file type is output, enters the current block in the directory cell.
The search command tries to speed up disk searches. The current block is saved to ensure that no new or altered data is lost. Thereafter, it doesn't save any of the blocks while searching through them. This can't be done easily from outside the code, so external customised searches will be a little slower.
When the code sees a TAB character, it reads in the next two bytes to get the record number. It multiplies the record number by the length and then divides the product by 5090 to determine which block the record is in. The remainder is the offset into that block. The code then loads in that block and sets up the FIB to point to the block and offset.
Using a RAMDISK will increase the speed of file searches and file access significantly. The file can be copied to the RAMDISK for use and the copied back to disk when you're done.
Machine code copy routines could really speed up copying.