When calling the OSGBPB routine from machine code you will need to use the absolute address &40D1. However, when CALLing this routine from BBC BASIC it is recommended that you use the BBC Micro-compatible address &FFD1.
The OSGBPB routines can be used to transfer a number of bytes to or from open files and retrieve file system information.
Reading or writing individual bytes at a time using BGET# (OSBGET) or BPUT# (OSBPUT) can be rather slow when you have a large number of bytes to transfer so you may wish to use this OS call to increase the speed of your program.
On entry, the Z80 register A contains the number of the routine to use defining the information to be transferred. HL points to a 13-byte control block with the following format:
|&00||File handle||One byte|
|&01~&04||Pointer to data in memory||Four bytes, LSB first|
|&05~&08||Number of bytes/items to transfer||Four bytes, LSB first|
|&09~&0C||File pointer to be used for transfer||Four bytes, LSB first|
The fields in the control block act as inputs and outputs. After transferring a number of bytes to or from a file the Number of bytes to transfer field is updated to contain the number of bytes left to read or write if the requested transfer could not be completed (for example, requesting to read 200 bytes from a 100 byte file). The pointer to data in memory and file pointer fields are also updated to their new values. On completion the carry flag is reset if the transfer completed successfully and set if not all of the number of bytes/items to transfer specified could be transferred.
When using OSGBPB from BASIC you may wish to use a wrapper procedure like the following. Before use you would need to allocate RAM for the control block using the DIM statement.
DEF PROC_osgbpb(cmd%,chn%,addr%,num%,ptr%) A%=cmd% H%=control DIV 256:L%=control control?0=chn% control!1=addr% control!5=num% control!9=ptr% CALL &FFD1 ENDPROC
|1||Put bytes to file, using the new sequential pointer.|
|2||Put bytes to file, ignoring the new sequential pointer.|
|3||Get bytes from file, using the new sequential pointer.|
|4||Get bytes from the file, ignoring the new sequential pointer.|
|8||Read file names sequentially.|
All other routine numbers are undefined and should not be used.
If more bytes or items have been requested than are available (eg the end of the file has been reached) the carry flag is set on exit and the number of bytes/items to transfer field in the control block ($05~$08) contains the number of bytes/items that could not be transferred. The sequential pointer and data in memory pointers are always updated to point to the next items to transfer.
When retrieving file names (A=8) the file pointer should first be set to 0 to reset to the first file and then left alone until all file names have been read. The data returned is:
- Length of filename 1
- Filename 1
- Length of filename 2
- Filename 2 ...
You can wrap routine 8 as follows for easy of use in BASIC programs:
10 osgbpb=&FFD1:DIM osgbpb_con 12:DIM osgbpb_fname 13 20 DEFPROC_ResetGetFile:osgbpb_con!9=0:ENDPROC 30 DEFFN_GetNextFile LOCAL L%,H%,A%:L%=osgbpb_con:H%=osgbpb_con DIV256:A%=8:osgbpb_con!1=osgbpb_fname:osgbpb_con!5=1:CALLosgbpb:osgbpb_fname?(1+?osgbpb_fname)=13:IF osgbpb_con!5:=""ELSE=$(osgbpb_fname+1)
You should call PROC_ResetGetFile first to reset to the first file then call FN_GetNextFile to retrieve file names. FN_GetNextFile will return the empty string ("") when there are no more file names to retrieve.
40 PROC_ResetGetFile 50 REPEAT 60 name$=FN_GetNextFile 70 IF name$<>"" PRINT name$ 80 UNTIL name$=""