The whole 'leaving gaps' issue is normal in a sense, and is expected of programs that operate on the file level. Notice that, as long as the file you're working with is the last file on the disk, no gap would be left if it is deleted and subsequently saved back.
On the other hand, doing a MOVE within a game program is certainly an overkill and
not what most people would expect. It's a bit like if a PC game tried to defragment the HDD on its own!
Random access and other unusual formats are best avoided. I doubt most people have any idea what those are (myself included), and I don't remember a single program that used those on a regular basis for its functionality.
(Why not just keep a single 961 byte file? Loading 4 sectors and 1 sector takes virtually the same time, and this is more efficient in terms of using the disk space.)
Seven.FFF wrote: ↑Sat Dec 16, 2017 10:05 pm
There are calls to read (#05) and write(#06) individual sectors, but I can't see how to read the track and sector numbers from the catalogue. I know what my initial sectors are, as I built the disk, but I would corrupt the disk if I assumed that, as someone might do their own disk operations that moved the file.
You can use a combination of #0A and #08 to read the track/sector information, and then read/save the data with #05 and #06. Sort of like this:
Code: Select all
Overwrite
ld hl,FileDescriptor
ld c,#13 ;copy the file descriptor to TR-DOS system variables
call #3D13
ld a,9 ;find a file with matching 9 first bytes in the descriptor (filename and type)
ld (#5D06),a ;uses the extra buffer, as do file level operations
ld c,#0A
call #3D13
ld a,c
inc c ;C will contain #FF if the file with this name wasn't found
jr z,NoFile
ld c,#08 ;#3D13 C=#08: loads a file descriptor specified in A at #5CDD
call #3D13
ld hl,SaveAddress ;or LD HL,(#5CE6) to assume the same saving address as in the file descriptor
ld de,(#5CEB) ;file descriptor: track and sector
ld a,(#5CEA) ;file descriptor: length, sectors
ld b,a
ld c,#06 ;#3D13 C=#06: save sectors
call #3D13
ret
Another option is to do the #0A/#08 thing once in the beginning, store the file locations/lengths in memory, and then just use #05/#06 as needed. This would help to reduce unnecessary drive head movements to track 0 and back (is faster). Also, #05/#06 have the advantage of not requiring the extra buffer in order to work.
Seven.FFF wrote: ↑Sat Dec 16, 2017 10:05 pm
I also discovered that writing to a read-only disk displays the nice Retry, Ignore, Abort message, which clears my screen. I worked round this by saving and restoring the screen before and after all my disk commands. I read in Russian about a service screen - is this what's happening here? Has my screen already been saved, and I could restore it by calling TR-DOS?
It's definitely not doing anything that convenient.
The correct way to go about this is to intercept the Retry/Abort/Ignore message. The following code comes from my unfinished #3D13 driver so again, pretty much untested, but I believe it should be something along these lines.
Code: Select all
OneTimeInit
ld a,#C3 ;#5CC2: is used by TR-DOS to call the BASIC 48 ROM routines, typically contains a RET
ld (#5CC2),a ;is also executed upon error during a #3D13 call (see #0201)
ld hl,ErrorHandler ;here, it is set to 'JP ErrorHandler'
ld (#5CC3),hl
ret
DOS
ld,(iy+0),#FF ;set #5C3A to 'no error', this is checked before exiting in #0201 but isn't reset by the DOS
push hl
ld (#5C3D),sp ;#5C3D: ERRSP
ld hl,0 ;zero out the two byte error code at #5D0F
ld (#5D0F),hl
pop hl
call #3D13
ret z ;Z: OK, NZ: ERROR
ld a,c ;C = error code
cp 20
jr z,Break ;20: break
sub 6
jr z,NoDisc ;6: no disc
dec a
jr z,DiscError ;7: disc error (abort)
jr UnhandledError
;intercept the Retry/Abort/Ignore message
ErrorHandler
ex (sp),hl ;will eventually return if entered upon NO DISC or ABORT, with the error code in C
push af
ld a,h
cp #0D ;the RIA situation is indicated by #0D6B on the stack (both 5.03 and 5.01)
jr z,.ria
pop af ;otherwise, we continue
ex (sp),hl ;LIST, CAT, FORMAT and the like display additional messages, not handled here
ret
.ria
ld hl,12 ;10+2
add hl,sp
ld sp,hl
call RIAMessage ;our custom RIA procedure here, A should return an "R"/"I"/"A" ASCII code
ld hl,#3F7E ;5.01 uses #3F74
push hl ;return the user's response to TR-DOS
jp #3D2F