;license:MIT ;(c) 2018 by 4am & qkumba ; ; ProRWTS2 glue functions ; ; Public functions ; - LoadFile ; - LoadDHRFile ; - SaveSmallFile ; ; A general note about paths: ; ; LoadFile, LoadDHRFile, and SaveSmallFile support files in subdirectories. ; Directories are delimited by '/' like ProDOS. At program startup, we get the ; current directory and save it; that is the PROGRAM ROOT DIRECTORY. All ; pathnames are relative to the PROGRAM ROOT DIRECTORY. There is no concept of ; setting or changing the 'current' directory. ; ; The PROGRAM ROOT DIRECTORY is not guaranteed to be the root directory of the ; underlying ProDOS disk (although it can be). But it doesn't matter, because ; these functions provide no access to any directory above the PROGRAM ROOT ; DIRECTORY. You can't use '..' to access the parent directory, and you can't ; start a pathname with '/' to access the root directory of the underlying ; ProDOS disk. ; ; Examples: ; 'PREFS.CONF' points to a file named 'PREFS.CONF' in the PROGRAM ROOT ; DIRECTORY. ; ; 'FX/RIPPLE' points to a file named 'RIPPLE' in a directory named 'FX' in the ; PROGRAM ROOT DIRECTORY. gRootDirectory !word $FDFD ;------------------------------------------------------------------------------ ; LoadFile ; Load a file into memory all at once, using ProRWTS2, at the load address ; specified by the file's ProDOS metadata. Hey, do you have a text file that ; doesn't have a load address? This routine will happily load it at $0000, and ; your program will likely crash as a result. So give it a load address as if ; it were a binary file. ; ; supports paths, see note ; ; in: stack contains 2 bytes of parameters: ; +1 address of filename ; out: all flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------------------------------------------------------ LoadFile +PARAMS_ON_STACK 2 +LDPARAM 1 +STAY namlo ; set filename jsr traverse ; go to subdirectory, set up filename for read lda #cmdread ; read (instead of write) sta reqcmd lda #0 ; 0 = read into main memory sta auxreq lda #$FF ; read entire file (ProRWTS2 will figure out exact size) sta sizehi jmp hddopendir ; exit via ProRWTS2 ;------------------------------------------------------------------------------ ; LoadDHRFile ; load .A2FC file (uncompressed double hi-res graphics) into memory ; all at once, using ProRWTS2 ; first $2000 bytes of file are loaded into auxiliary memory $2000..$3FFF ; second $2000 bytes of file are loaded into main memory $2000..$3FFF ; ; supports paths, see note ; ; in: stack contains 2 bytes of parameters: ; +1 address of filename ; out: all flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------------------------------------------------------ LoadDHRFile +PARAMS_ON_STACK 2 +LDPARAM 1 +STAY namlo ; set filename jsr traverse ; go to subdirectory, set up filename for read lda #$00 ; read first $2000 bytes sta sizelo lda #$20 sta sizehi lda #1 ; 1 = read into aux memory sta auxreq lda #cmdread ; read (instead of write) sta reqcmd jsr hddopendir ; call ProRWTS2 lda #$20 ; read next $2000 bytes sta sizehi dec auxreq ; 0 = read into main memory clc ; not a subdirectory jmp hddrdwrpart ; call ProRWTS2 ;------------------------------------------------------------------------------ ; SaveSmallFile ; Save a file into memory all at once, using ProRWTS2. ; /!\ Only first block (512 bytes) is written. Keep those files small. /!\ ; /!\ All 512 bytes are written to disk. Clear buffer before calling. /!\ ; ; supports paths, see note ; ; in: stack contains 4 bytes of parameters: ; +1 address of filename ; +3 address of data buffer ; out: all flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------------------------------------------------------ SaveSmallFile +PARAMS_ON_STACK 4 +LDPARAM 1 +STAY namlo ; set filename for ProRWTS2 +LDPARAM 3 +STAY ldrlo ; set data buffer address for ProRWTS2 jsr traverse ; go to subdirectory, set up filename for read lda #cmdwrite ; write (instead of read) sta reqcmd jmp hddopendir ; exit via ProRWTS2 ;------------------------------------------------------------------------------ ; traverse [private] ; ; in: (namlo) points to length-prefixed pathname+filename ; out: all flags clobbered ; all registers clobbered ;------------------------------------------------------------------------------ traverse +LDAY gRootDirectory sta @myreadblock+1 sty @myreadblock+3 ; reset 'root' directory (saved at program start) ;search for '/' character in filename ldx #0 ldy #0 lda (namlo), y tay - inx dey bmi @go ; no '/', just do the read lda (namlo), y cmp #'/' bne - sty sizelo txa pha @myreadblock @myx80_parms ldx #2 lda #0 jsr hddreaddirsel lda #NAME_LENGTH sta bloklo lda #>(hdddirbuf - 1) sta blokhi ;there can be only one page crossed, so we can increment here @mynextent1 inc blokhi @mynextent ldy #0 lda (bloklo), y pha and #$0f tax -- iny lda (bloklo), y cmp (namlo), y beq @myfoundname ;match failed, move to next directory in this block, if possible - pla @myskiphdr clc lda bloklo adc #ENTRY_SIZE sta bloklo bcs @mynextent1 cmp #$ff ;4 + ($27 * $0d) bne @mynextent ;read next directory block when we reach the end of this block lda hdddirbuf + NEXT_BLOCK_LO ldx hdddirbuf + NEXT_BLOCK_HI bcs + @myfoundname dex bne -- ;parse path until last directory is seen iny lda (namlo), y cmp #'/' bne - pla and #$20 ;Volume Directory Header XOR subdirectory bne @myskiphdr tya eor #$ff adc sizelo sta sizelo clc tya adc namlo sta namlo ;cache block number of current directory ;as starting position for subsequent searches ldy #(KEY_POINTER + 1) lda (bloklo), y tax dey lda (bloklo), y sta (reloc + unrhddblocklo - unrelochdd) + 1 stx (reloc + unrhddblockhi - unrelochdd) + 1 + sta @myx80_parms + 1 stx @myx80_parms + 3 ++ lda sizelo bne @myreadblock tay pla sta (namlo), y @go rts promote !pseudopc $bf00 { lda $c08b clc bcc @do_enter ;$bf06 rts ;clock interface, must be RTS on real ProDOS if program uses $20x @do_enter lda $c08b jmp ProDOS_enter !text "q4!" ;$bf10 !word $c1d1, $c2d1, $c3d1, $c4d1, $c5d1, $c6d1, $c7d1 ProDOS_exit bit $c081 rts ProDOS_fatal ;only for debugging, will be removed pha lda $c081 jsr $fe89 jsr $fe93 pla jsr $fdda jmp $ff59 ProDOS_prefix=$bfd0 ; !fill $2e } end_promote ;------------------------------------------------------------------------------ ; ProDOS_enter ; intercept certain ProDOS requests ; wrap them to ProRWTS2 file requests ; ; in: return address+1 is command and pointer to parameter block ; out: all flags clobbered ; A=0, X and Y preserved ; stack set to next instruction after parameters ;------------------------------------------------------------------------------ packet = first_zp ;word buffer = first_zp+2 ;word ProDOS_enter !ifdef PASS2 { !set CloseHandles = @imp_close } else { ;PASS2 !set PASS2=1 } jsr @swap_zp pla sta @fetchaddr+1 pla sta @fetchaddr+2 jsr @fetchbyte sta @request+1 jsr @fetchbyte sta packet jsr @fetchbyte sta packet+1 lda @fetchaddr+2 pha lda @fetchaddr+1 pha txa pha tya pha @request lda #$d1 cmp #$c4 beq @do_getattrib cmp #$c7 beq @do_prefix cmp #$c8 beq @do_open cmp #$ca beq @do_read cmp #$cb beq @do_write cmp #$cc beq @do_close cmp #$ce beq @do_seek ;;any others?? jmp ProDOS_fatal @do_getattrib jmp @imp_getattrib @do_prefix jmp @imp_prefix @do_open jmp @imp_open @do_read jmp @imp_read @do_write jmp @imp_write @do_close jsr @imp_close ;subroutine special case because of dual-use jmp @restore_zp @do_seek jmp @imp_seek @imp_getattrib lda packet+1 pha lda packet pha ldx #namlo jsr @setbuffer1 lda #$60 sta attribpatch jsr hddopendir lda #$10 sta attribpatch pla sta packet pla sta packet+1 ldy #5 lda ldrlo2 sta (packet), y iny lda ldrlo2+1 sta (packet), y jmp @restore_zp @imp_prefix ldx #buffer jsr @setbuffer1 ldy ProDOS_prefix @copy_prefix lda ProDOS_prefix, y sta (buffer), y dey bpl @copy_prefix jmp @restore_zp @imp_open ldx #namlo jsr @setbuffer1 iny inc @handles+1 @handles ldx #0 iny lda (packet), y sta @handle-1, x tax jsr @patch_buffer iny lda #1 sta (packet), y lda #0 sta reqcmd sta sizehi sta sizelo jsr hddopendir lda #0 sta blkidx beq @jmp_zp ;always @imp_seek lda #cmdseek !byte $2c @imp_read lda #cmdread !byte $2c @imp_write lda #cmdwrite sta reqcmd pha jsr @set_rdwrbuff pla bne @set_blocks lda ldrhi sta sizehi lda ldrlo sta sizelo @set_blocks jsr hddrdwrpart @jmp_zp jmp @restore_zp @imp_close lda @handles+1 beq @close_ret dec @handles+1 bne @close_ret lda #>hddencbuf @patch_buffer sta encbufpatch1+1 sta encbufpatch2+1 tax inx stx dirbufpatch1+1 inx stx dirbufpatch2+2 stx dirbufpatch3+2 stx dirbufpatch4+2 stx dirbufpatch6+1 stx dirbufpatch7+2 stx dirbufpatch9+2 stx dirbufpatch10+1 inx stx dirbufpatch5+2 stx dirbufpatch8+2 @close_ret rts @fetchbyte inc @fetchaddr+1 bne @fetchaddr inc @fetchaddr+2 @fetchaddr lda $d1d1 rts @set_rdwrbuff ldy #1 lda (packet), y tax lda @handle-1, x tax jsr @patch_buffer ldx #ldrlo iny jsr @setbuffer ldx #sizelo iny !byte $2c @setbuffer1 ldy #1 @setbuffer lda (packet), y sta $0,x iny lda (packet), y sta $1,x rts @swap_zp ldx #last_zp-first_zp @save_zp lda first_zp,x ldy @saved_zp,x sta @saved_zp,x sty first_zp,x dex bpl @save_zp rts @restore_zp jsr @swap_zp pla ;saved inside ProDOS_enter tay pla tax lda #0 clc jmp ProDOS_exit @handle !byte 0, 0 ;only up to two handles at a time @saved_zp !fill (last_zp - first_zp) + 1