a2d/desktop.system/desktop.system.s

2157 lines
50 KiB
ArmAsm

.setcpu "6502"
.org $2000
.include "apple2.inc"
.include "../inc/apple2.inc"
.include "../inc/prodos.inc"
.include "../inc/macros.inc"
;;; ============================================================
;;; Locations in Main LC Bank 2 (past end of custom quit routines)
;; 16 bytes $D395-$D3A4 - set to $FF when entry is copied
;; ("down loaded") to RAM Card.
entry_copied_flags := $D395
;; Quit routine signature/data
copied_to_ramcard_flag := $D3FF ; $00 at start, $C0 mid copy, $80 done
ramcard_prefix := $D3EE
desktop_orig_prefix := $D3AD
;;; ============================================================
.proc copy_desktop_to_ramcard
jmp start
;;; ============================================================
;;; Data buffers and param blocks
date: .word 0 ; written into file
L2005:
.res 832, 0
.byte $02,$00
.addr L2363
path_buf := $D00
.proc get_prefix_params2
param_count: .byte 2 ; GET_PREFIX, but param_count is 2 ??? Bug???
data_buffer: .addr path_buf
.endproc
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params4, path_buf
.byte $00,$01
.addr L2362
L2362: .byte 0
L2363: .res 15, 0
butn1: .byte 0 ; written, but not read
unit_num:
.byte 0
DEFINE_ON_LINE_PARAMS on_line_params,, on_line_buffer
copy_flag:
.byte 0
L2379: .byte 0
on_line_buffer: .res 17, 0
DEFINE_GET_PREFIX_PARAMS get_prefix_params, buffer
DEFINE_SET_PREFIX_PARAMS set_prefix_params, path0
.byte $0A
.addr L2379
.byte $00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00
.byte $07,$60,$2B,$C3,$0F
.byte $00,$00,$0D,$00,$00,$00,$00,$04
.byte $00,$00,$03,$00,$01,$00,$00,$01
.byte $00,$03,$F5,$26,$00,$08,$00,$04
.byte $00
.addr L23C9
.byte $04,$00,$00,$00
L23C9: .byte $00
.byte $00,$00,$00,$01,$00,$04,$00,$21
.byte $28,$27,$00,$00,$00,$04,$00
.addr L23DF
.byte $05,$00,$00,$00
L23DF: .byte $00,$00,$00
.byte $00,$00,$00,$00,$00,$00
DEFINE_CLOSE_PARAMS close_srcfile_params
DEFINE_CLOSE_PARAMS close_dstfile_params
.byte $01
.addr buffer
copy_buffer := $4000
max_copy_count := MLI - copy_buffer
open_srcfile_io_buffer := $0D00
open_dstfile_io_buffer := $1100
DEFINE_OPEN_PARAMS open_srcfile_params, buffer, open_srcfile_io_buffer
DEFINE_OPEN_PARAMS open_dstfile_params, path0, open_dstfile_io_buffer
DEFINE_READ_PARAMS read_srcfile_params, copy_buffer, max_copy_count
DEFINE_WRITE_PARAMS write_dstfile_params, copy_buffer, max_copy_count
DEFINE_CREATE_PARAMS create_params, path0, ACCESS_DEFAULT, 0, 0
.byte $07
.addr path0
.byte $00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params, buffer
.byte 0
;; Files/Directories to copy
str_f1: PASCAL_STRING "DESKTOP.SYSTEM"
str_f2: PASCAL_STRING "DESKTOP2"
str_f3: PASCAL_STRING "DESK.ACC"
str_f4: PASCAL_STRING "PREVIEW"
str_f5: PASCAL_STRING "SELECTOR.LIST"
str_f6: PASCAL_STRING "SELECTOR"
str_f7: PASCAL_STRING "PRODOS"
str_f8: PASCAL_STRING "Quit.tmp"
filename_table:
.addr str_f1,str_f2,str_f3,str_f4,str_f5,str_f6,str_f7,str_f8
num_filenames = 8
str_copying_to_ramcard:
PASCAL_STRING "Copying Apple II DeskTop into RAMCard"
str_tip_skip_copying:
PASCAL_STRING {"Tip: To skip copying to RAMCard, hold down ",15,27,65,24,14," when launching."}
;; Signature of block storage devices ($Cn0x)
sig_bytes:
.byte $20,$00,$03,$00
sig_offsets:
.byte $01,$03,$05,$07
active_device:
.byte 0
;; Selector signature
selector_signature:
.byte $AD,$8B,$C0,$18,$FB,$5C,$04,$D0,$E0
;;; ============================================================
start: sta MIXCLR
sta HIRES
sta TXTCLR
sta CLR80VID
sta AN3_OFF
sta AN3_ON
sta AN3_OFF
sta AN3_ON
sta SET80VID
sta DHIRESON
sta TXTSET
lda DATELO ; Any date set?
ora DATEHI
bne :+
copy16 date, DATELO ; Copy timestamp embedded in this file
: lda MACHID
and #$30 ; bits 4,5 set = 128k
cmp #$30
beq have128k
;; If not 128k machine, just quit back to ProDOS
MLI_CALL QUIT, quit_params
DEFINE_QUIT_PARAMS quit_params
have128k:
;; Save original Quit routine and small loader
;; TODO: Assumes prefix is retained. Compose correct path.
jsr preserve_quit_code
;; (Original code from here on)
resume: lda #$00
sta SHADOW ; IIgs ???
lda DEVNUM ; Most recent device
sta active_device
lda LCBANK2
lda LCBANK2
;; Check quit routine
ldx #$08
: lda SELECTOR,x ; Quit routine?
cmp selector_signature,x
bne nomatch
dex
bpl :-
lda #0
beq match
nomatch:
lda #$80
match: sta $D3AC
lda ROMIN2
ldx #0
jsr set_copied_to_ramcard_flag
;; Point $8 at $C100
lda #0
sta flag
sta $08
lda #$C1
sta $08+1
;; Check slot for signature bytes
check_slot:
ldx #0
: lda sig_offsets,x ; Check $CnXX
tay
lda ($08),y
cmp sig_bytes,x
bne next_slot
inx
cpx #4 ; number of signature bytes
bcc :-
ldy #$FB
lda ($08),y ; Also check $CnFB for low bit
and #$01
beq next_slot
bne found_slot
next_slot:
inc $08+1
lda $08+1
cmp #$C8 ; stop at $C800
bcc check_slot
ldy DEVCNT
: lda DEVLST,y
cmp #$3E
beq :+
dey
bpl :-
jmp fail
: lda #$03
bne :+
found_slot:
lda $08+1
and #$0F ; slot # in A
: sta slot
;; Synthesize unit_num, verify it's a device
asl a
asl a
asl a
asl a
sta on_line_params::unit_num
sta unit_num
MLI_CALL ON_LINE, on_line_params
beq :+
jmp fail
: lda unit_num
cmp #$30 ; make sure it's not slot 3 (aux)
beq :+
sta write_block_params_unit_num
sta write_block2_params_unit_num
MLI_CALL WRITE_BLOCK, write_block_params
bne :+
MLI_CALL WRITE_BLOCK, write_block2_params
: lda on_line_buffer
and #$0F
tay
iny
sty path0
lda #'/'
sta on_line_buffer
sta path0+1
: lda on_line_buffer,y
sta path0+1,y
dey
bne :-
ldx #$C0
jsr set_copied_to_ramcard_flag
addr_call set_ramcard_prefix, path0
jsr check_desktop2_on_device
bcs :+
ldx #$80
jsr set_copied_to_ramcard_flag
jsr copy_2005_to_desktop_orig_prefix
jmp fail
: lda BUTN1
sta butn1
lda BUTN0
bpl start_copy
jmp fail
str_slash_desktop:
PASCAL_STRING "/DeskTop"
;; Overwrite first bytes of get_file_info_params
.proc dir_file_info
.byte $A ; param_count
.addr 0 ; pathname
.byte ACCESS_DEFAULT ; access
.byte FT_DIRECTORY ; filetype
.word 0 ; aux_type
.byte ST_LINKED_DIRECTORY ; storage_type
.endproc
.proc start_copy
ptr := $06
jsr show_copying_screen
MLI_CALL GET_PREFIX, get_prefix_params
beq :+
jmp fail_copy
: dec buffer
ldx #$80
jsr set_copied_to_ramcard_flag
ldy buffer
: lda buffer,y
sta L2005,y
dey
bpl :-
ldy path0
ldx #0
: iny
inx
lda str_slash_desktop,x
sta path0,y
cpx str_slash_desktop
bne :-
sty path0
;; copy file_type, aux_type, storage_type
ldx #7
: lda dir_file_info,x
sta get_file_info_params,x
dex
cpx #3
bne :-
jsr create_file_for_copy
lda path0
sta copy_flag
lda #0
sta filenum
file_loop:
lda filenum
asl a
tax
copy16 filename_table,x, ptr
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta filename_buf,y
dey
bpl :-
jsr copy_file
inc filenum
lda filenum
cmp #num_filenames
bne file_loop
jmp fail2
.endproc
fail2: lda copy_flag
beq :+
sta path0
MLI_CALL SET_PREFIX, set_prefix_params
: jsr write_desktop1
jsr copy_2005_to_desktop_orig_prefix
lda #$00
sta RAMWORKS_BANK ; ???
ldy #BITMAP_SIZE-1
: sta BITMAP,y
dey
bpl :-
jmp copy_selector_entries_to_ramcard
;;; ============================================================
.proc set_copied_to_ramcard_flag
lda LCBANK2
lda LCBANK2
stx copied_to_ramcard_flag
lda ROMIN2
rts
.endproc
.proc set_ramcard_prefix
ptr := $6
target := ramcard_prefix
stax ptr
lda LCBANK2
lda LCBANK2
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta target,y
dey
bpl :-
lda ROMIN2
rts
.endproc
.proc set_desktop_orig_prefix
ptr := $6
target := desktop_orig_prefix
stax ptr
lda LCBANK2
lda LCBANK2
ldy #0
lda (ptr),y
tay
: lda (ptr),y
sta target,y
dey
bpl :-
lda ROMIN2
rts
.endproc
;;; ============================================================
fail: lda #0
sta flag
jmp fail2
.byte 0, $D, 0, 0, 0
;; Generic buffer?
buffer: .res 300, 0
filename_buf:
.res 16, 0
file_type: ; written but not read ???
.byte 0
.res 31, 0 ; unused ???
;;; ============================================================
.proc append_filename_to_buffer
lda filename_buf
bne :+
rts
: ldx #0
ldy buffer
lda #'/'
sta buffer+1,y
iny
loop: cpx filename_buf
bcs done
lda filename_buf+1,x
sta buffer+1,y
inx
iny
jmp loop
done: sty buffer
rts
.endproc
;;; ============================================================
.proc remove_filename_from_buffer
ldx buffer
bne :+
rts
: lda buffer,x
cmp #'/'
beq done
dex
bne :-
stx buffer
rts
done: dex
stx buffer
rts
.endproc
;;; ============================================================
.proc append_filename_to_path0
lda filename_buf
bne :+
rts
: ldx #0
ldy path0
lda #'/'
sta path0+1,y
iny
loop: cpx filename_buf
bcs done
lda filename_buf+1,x
sta path0+1,y
inx
iny
jmp loop
done: sty path0
rts
.endproc
;;; ============================================================
.proc remove_filename_from_path0
ldx path0
bne :+
rts
: lda path0,x
cmp #'/'
beq done
dex
bne :-
stx path0
rts
done: dex
stx path0
rts
.endproc
;;; ============================================================
.proc show_copying_screen
;; Turn on 80-column mode
jsr SLOT3ENTRY
jsr HOME
;; Center string
lda #80
sec
sbc str_copying_to_ramcard
lsr a ; / 2 to center
sta CH
lda #12
sta CV
jsr VTAB
ldy #0
: iny
lda str_copying_to_ramcard,y
ora #$80
jsr COUT
cpy str_copying_to_ramcard
bne :-
;; Center string
lda #80
sec
sbc str_tip_skip_copying
clc
adc #4 ; 4 control characters (for MouseText)
lsr a ; / 2 to center
sta CH
lda #23
sta CV
jsr VTAB
ldy #0
: iny
lda str_tip_skip_copying,y
ora #$80
jsr COUT
cpy str_tip_skip_copying
bne :-
rts
.endproc
;;; ============================================================
.proc fail_copy
lda #0
sta copy_flag
jmp fail
.endproc
;;; ============================================================
;;; Unreferenced ???
.proc copy_input_to_buffer
ldy #0
loop: lda IN,y
cmp #$80|CHAR_RETURN
beq done
and #CHAR_MASK
sta buffer+1,y
iny
jmp loop
done: sty buffer
rts
.endproc
;;; ============================================================
.proc copy_file
jsr append_filename_to_path0
jsr append_filename_to_buffer
MLI_CALL GET_FILE_INFO, get_file_info_params
beq :+
cmp #ERR_FILE_NOT_FOUND
beq cleanup
jmp fail
: lda get_file_info_params::file_type
sta file_type
cmp #FT_DIRECTORY
bne :+
jsr copy_directory
jmp done
: jsr create_file_for_copy
cmp #ERR_DUPLICATE_FILENAME
bne :+
lda filenum
bne cleanup
pla
pla
jmp fail2
: jsr copy_normal_file
cleanup:
jsr remove_filename_from_buffer
jsr remove_filename_from_path0
done: rts
.endproc
;;; ============================================================
.proc copy_directory_impl
ptr := $6
open_io_buffer := $A000
dir_buffer := $A400
dir_bufsize = BLOCK_SIZE
entry_length_offset := $23
file_count_offset := $25
header_length := $2B
DEFINE_OPEN_PARAMS open_params, buffer, open_io_buffer
DEFINE_READ_PARAMS read_params, dir_buffer, dir_bufsize
DEFINE_CLOSE_PARAMS close_params
start: jsr create_file_for_copy
cmp #ERR_DUPLICATE_FILENAME
beq bail
MLI_CALL OPEN, open_params
beq :+
jsr fail_copy
bail: rts
: lda open_params::ref_num
sta read_params::ref_num
sta close_params::ref_num
MLI_CALL READ, read_params
beq :+
jsr fail_copy
rts
: lda #0
sta L2A10
lda #<(dir_buffer + header_length)
sta ptr
lda #>(dir_buffer + header_length)
sta ptr+1
L2997: lda dir_buffer + file_count_offset
cmp L2A10
bne L29B1
L299F: MLI_CALL CLOSE, close_params
beq :+
jmp fail_copy
: jsr remove_filename_from_buffer
jsr remove_filename_from_path0
rts
L29B1: ldy #0
lda (ptr),y
bne :+
jmp L29F6
: and #$0F
tay
: lda (ptr),y
sta filename_buf,y
dey
bne :-
lda (ptr),y
and #$0F
sta filename_buf,y
jsr append_filename_to_path0
jsr append_filename_to_buffer
MLI_CALL GET_FILE_INFO, get_file_info_params
beq :+
jmp fail_copy
: lda get_file_info_params::file_type
sta file_type
jsr create_file_for_copy
cmp #ERR_DUPLICATE_FILENAME
beq :+
jsr copy_normal_file
: jsr remove_filename_from_buffer
jsr remove_filename_from_path0
inc L2A10
L29F6: add16_8 ptr, dir_buffer + entry_length_offset, ptr
lda ptr+1
cmp #>(dir_buffer + dir_bufsize)
bcs :+
jmp L2997
: jmp L299F
L2A10: .byte 0
.endproc
copy_directory := copy_directory_impl::start
;;; ============================================================
.proc copy_normal_file
;; Open source
: MLI_CALL OPEN, open_srcfile_params
beq :+
jsr fail_copy
jmp :-
;; Open destination
: MLI_CALL OPEN, open_dstfile_params
beq :+
jsr fail_copy
jmp :-
: lda open_srcfile_params::ref_num
sta read_srcfile_params::ref_num
sta close_srcfile_params::ref_num
lda open_dstfile_params::ref_num
sta write_dstfile_params::ref_num
sta close_dstfile_params::ref_num
;; Read a chunk
loop: copy16 #max_copy_count, read_srcfile_params::request_count
read: MLI_CALL READ, read_srcfile_params
beq :+
cmp #ERR_END_OF_FILE
beq done
jsr fail_copy
jmp read
;; Write the chunk
: copy16 read_srcfile_params::trans_count, write_dstfile_params::request_count
ora read_srcfile_params::trans_count
beq done
write: MLI_CALL WRITE, write_dstfile_params
beq :+
jsr fail_copy
jmp write
;; More to copy?
: lda write_dstfile_params::trans_count
cmp #<max_copy_count
bne done
lda write_dstfile_params::trans_count+1
cmp #>max_copy_count
beq loop
;; Close source and destination
done: MLI_CALL CLOSE, close_srcfile_params
MLI_CALL CLOSE, close_dstfile_params
rts
.endproc
;;; ============================================================
.proc create_file_for_copy
;; Copy file_type, aux_type, storage_type
ldx #7
: lda get_file_info_params,x
sta create_params,x
dex
cpx #3
bne :-
MLI_CALL CREATE, create_params
beq :+
cmp #ERR_DUPLICATE_FILENAME
beq :+
jsr fail_copy
: rts
.endproc
;;; ============================================================
.proc check_desktop2_on_device
lda active_device
cmp #$3E ; ???
bne :+
jmp next
;; Check slot for signature bytes
: and #$70 ; Compute $Cn00
lsr a
lsr a
lsr a
lsr a
ora #$C0
sta $08+1
lda #0
sta $08
ldx #0 ; Compare signature bytes
bloop: lda sig_offsets,x
tay
lda ($08),y
cmp sig_bytes,x
bne error
inx
cpx #4 ; Number of signature bytes
bcc bloop
ldy #$FB ; Also check $CnFB
lda ($08),y
and #$01
bne next
error: sec
rts
next: MLI_CALL GET_PREFIX, get_prefix_params2
bne error
;; Append "DeskTop2" to path
ldx path_buf
ldy #0
loop: inx
iny
lda str_desktop2,y
sta path_buf,x
cpy str_desktop2
bne loop
stx path_buf
;; ... and get info
MLI_CALL GET_FILE_INFO, get_file_info_params4
beq error
clc ; ok
rts
str_desktop2:
PASCAL_STRING "DeskTop2"
.endproc
;;; ============================================================
.proc write_desktop1_impl
open_io_buffer := $1000
dt1_addr := $2000
dt1_size := $45
DEFINE_OPEN_PARAMS open_params, str_desktop1_path, open_io_buffer
str_desktop1_path:
PASCAL_STRING "DeskTop/DESKTOP.SYSTEM"
DEFINE_WRITE_PARAMS write_params, dt1_addr, dt1_size
DEFINE_CLOSE_PARAMS close_params
start: MLI_CALL OPEN, open_params
bne :+
lda open_params::ref_num
sta write_params::ref_num
sta close_params::ref_num
MLI_CALL WRITE, write_params
bne :+
MLI_CALL CLOSE, close_params
: rts
.endproc
write_desktop1 := write_desktop1_impl::start
;;; ============================================================
.proc copy_2005_to_desktop_orig_prefix
addr_call set_desktop_orig_prefix, L2005
rts
.endproc
.byte 0
path0: .res 65, 0
;;; ============================================================
filenum:
.byte 0 ; index of file being copied
flag: .byte 0 ; written but not read ???
slot: .byte 0
DEFINE_WRITE_BLOCK_PARAMS write_block_params, prodos_loader_blocks, 0
write_block_params_unit_num := write_block_params::unit_num
DEFINE_WRITE_BLOCK_PARAMS write_block2_params, prodos_loader_blocks + 512, 1
write_block2_params_unit_num := write_block2_params::unit_num
PAD_TO $2D00
;;; ============================================================
prodos_loader_blocks:
.assert * = $2D00, error, "Segment length mismatch"
.incbin "../inc/pdload.dat"
.endproc ; copy_desktop_to_ramcard
;;; ============================================================
.assert * = $3100, error, "Segment length mismatch"
;;; SPECULATION: This copies Selector entries marked
;;; "Down load" / "At boot" to the RAMCard as well
.proc copy_selector_entries_to_ramcard
;; File format:
;; $ 0 - number of entries (0-7) in first batch (Run List???)
;; $ 1 - number of entries (0-15) in second batch (Other Run List???)
;; $ 2 - 24 * 16-byte data entries
;; $0 - label (length-prefixed, 15 bytes)
;; $F - active_flag (other flags, i.e. download on ... ?)
;; bit 6 = "down loaded" flag ???
;; $182 - 24 * 64-byte pathname
;; $782 - EOF
selector_buffer := $4400
selector_buflen := $800
.proc process_selector_list
ptr := $6
jsr SLOT3ENTRY
jsr HOME
lda LCBANK2
lda LCBANK2
lda copied_to_ramcard_flag
pha
lda ROMIN2
pla
bne :+
jmp invoke_selector_or_desktop
: lda LCBANK2
lda LCBANK2
ldx #$17
lda #0
: sta entry_copied_flags,x
dex
bpl :-
lda ROMIN2
;; Load and iterate over the selector file
jsr read_selector_list
beq :+
jmp bail
: lda #0
sta entry_num
entry_loop:
lda entry_num
cmp selector_buffer ; done?
beq done_entries
jsr compute_label_addr
stax ptr
ldy #$0F ; check active flag
lda (ptr),y
bne next_entry
lda entry_num
jsr compute_path_addr
jsr L38B2
jsr L3489
lda LCBANK2
lda LCBANK2
ldx entry_num
lda #$FF
sta entry_copied_flags,x
lda ROMIN2
next_entry:
inc entry_num
jmp entry_loop
done_entries:
;; Process entries again ???
lda #0
sta entry_num
entry_loop2:
lda entry_num
cmp selector_buffer + 1 ; ???
beq bail
clc
adc #8 ; offset by 8 ???
jsr compute_label_addr
stax ptr
ldy #$0F
lda (ptr),y ; check active flag
bne next_entry2
lda entry_num
clc
adc #8
jsr compute_path_addr
jsr L38B2
jsr L3489
lda LCBANK2
lda LCBANK2
lda entry_num
clc
adc #8
tax
lda #$FF
sta entry_copied_flags,x
lda ROMIN2
next_entry2:
inc entry_num
jmp entry_loop2
bail: jmp invoke_selector_or_desktop
entry_num:
.byte 0
.endproc
;;; ============================================================
open_path2_io_buffer := $0800
DEFINE_OPEN_PARAMS open_path2_params, path2, open_path2_io_buffer
DEFINE_READ_PARAMS read_4bytes_params, buf_4_bytes, 4
buf_4_bytes: .res 4, 0
DEFINE_CLOSE_PARAMS close_params
DEFINE_READ_PARAMS read_39bytes_params, filename, 39
DEFINE_READ_PARAMS read_5bytes_params, buf_5_bytes, 5
buf_5_bytes: .res 5, 0
.res 4, 0
DEFINE_CLOSE_PARAMS close_srcdir_params
DEFINE_CLOSE_PARAMS close_dstdir_params
.byte 1
.addr path2
dircopy_buffer := $1100
dircopy_bufsize := $0B00
open_srcdir_io_buffer := $0D00
open_dstdir_io_buffer := $1C00
DEFINE_OPEN_PARAMS open_srcdir_params, path2, open_srcdir_io_buffer
DEFINE_OPEN_PARAMS open_dstdir_params, path1, open_dstdir_io_buffer
DEFINE_READ_PARAMS read_srcdir_params, dircopy_buffer, dircopy_bufsize
DEFINE_WRITE_PARAMS write_dstdir_params, dircopy_buffer, dircopy_bufsize
DEFINE_CREATE_PARAMS create_dir_params, path1, ACCESS_DEFAULT
DEFINE_CREATE_PARAMS create_params, path1, 0
.byte 0, 0
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params2, path2
.byte 0
DEFINE_GET_FILE_INFO_PARAMS get_file_info_params3, path1
.byte $00,$02,$00,$00,$00
file_info:
filename:
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $40,$35,$3D,$35,$86,$31,$60,$00
path1: .res 65, 0
path2: .res 65, 0
L320A: .res 64, 0
L324A: .res 64, 0
L328A: .res 16, 0
L329A: .byte $00
L329B: .byte $0D
L329C: .byte $00
ref_num:.byte $00
L329E: .byte $00
L329F: .res 170, 0
L3349: .byte $00
L334A: .byte $00
;;; ============================================================
.proc L334B
ldx L3349
lda L329E
sta L329F,x
inx
stx L3349
rts
.endproc
;;; ============================================================
.proc L3359
ldx L3349
dex
lda L329F,x
sta L329E
stx L3349
rts
.endproc
;;; ============================================================
.proc L3367
lda #$00
sta L329C
sta L334A
MLI_CALL OPEN, open_path2_params
beq :+
jmp handle_error_code
: lda open_path2_params::ref_num
sta ref_num
sta read_4bytes_params::ref_num
MLI_CALL READ, read_4bytes_params
beq :+
jmp handle_error_code
: jsr L33A4
rts
.endproc
;;; ============================================================
.proc L3392
lda ref_num
sta close_params::ref_num
MLI_CALL CLOSE, close_params
beq :+
jmp handle_error_code
: rts
.endproc
;;; ============================================================
.proc L33A4
inc L329C
lda ref_num
sta read_39bytes_params::ref_num
MLI_CALL READ, read_39bytes_params
beq :+
jmp handle_error_code
: inc L334A
lda L334A
cmp L329B
bcc done
lda #0
sta L334A
lda ref_num
sta read_5bytes_params::ref_num
MLI_CALL READ, read_5bytes_params
beq :+
jmp handle_error_code
: lda read_5bytes_params::trans_count
cmp read_5bytes_params::request_count
rts
done: return #0
.endproc
;;; ============================================================
.proc L33E3
lda L329C
sta L329E
jsr L3392
jsr L334B
jsr append_filename_to_path2
jsr L3367
rts
.endproc
.proc L33F6
jsr L3392
jsr noop
jsr remove_filename_from_path2
jsr L3359
jsr L3367
jsr L340C
jsr remove_filename_from_path1_alt2
rts
.endproc
.proc L340C
lda L329C
cmp L329E
beq :+
jsr L33A4
jmp L340C
: rts
.endproc
;;; ============================================================
.proc L341B
lda #$00
sta L329A
jsr L3367
loop: jsr L33A4
bne next
lda filename
beq loop
lda filename
sta L346F
and #$0F
sta filename
lda #$00
sta L3467
jsr do_copy_alt
lda L3467
bne loop
lda file_info + 16
cmp #$0F
bne loop
jsr L33E3
inc L329A
jmp loop
next: lda L329A
beq done
jsr L33F6
dec L329A
jmp loop
done: jsr L3392
rts
.endproc
;;; ============================================================
L3467: .byte 0
do_copy_alt:
jmp do_copy
remove_filename_from_path1_alt2:
jmp remove_filename_from_path1_alt
noop: rts
L346F: .byte 0
;;; ============================================================
;;; Unreferenced ???
.proc copy_input_to_path2
ldy #0
loop: lda IN,y
cmp #$80|CHAR_RETURN
beq done
and #CHAR_MASK
sta path2+1,y
iny
jmp loop
done: sty path2
rts
.endproc
;;; ============================================================
.res 3, 0
.proc L3489
lda #$FF
sta L353B
jsr L3777
ldx path1
lda #'/'
sta path1+1,x
inc path1
ldy #$00
ldx path1
: iny
inx
lda L328A,y
sta path1,x
cpy L328A
bne :-
stx path1
MLI_CALL GET_FILE_INFO, get_file_info_params3
cmp #ERR_FILE_NOT_FOUND
beq okerr
cmp #ERR_VOL_NOT_FOUND
beq okerr
cmp #ERR_PATH_NOT_FOUND
beq okerr
rts
okerr: MLI_CALL GET_FILE_INFO, get_file_info_params2
beq L34DD
cmp #ERR_VOL_NOT_FOUND
beq prompt
cmp #ERR_FILE_NOT_FOUND
bne fail
prompt: jsr show_insert_prompt
jmp okerr
fail: jmp handle_error_code
L34DD: lda get_file_info_params2::storage_type
cmp #ST_VOLUME_DIRECTORY
beq is_dir
cmp #ST_LINKED_DIRECTORY
beq is_dir
lda #$00
beq :+
is_dir: lda #$FF
: sta is_dir_flag
;; copy file_type, aux_type, storage_type
ldy #7
: lda get_file_info_params2,y
sta create_params,y
dey
cpy #3
bne :-
lda #ACCESS_DEFAULT
sta create_params::access
jsr L35A9
bcc :+
jmp show_no_space_prompt
;; copy dates
: COPY_STRUCT DateTime, get_file_info_params2::create_date, create_params::create_date
;; create the file
lda create_params::storage_type
cmp #ST_VOLUME_DIRECTORY
bne :+
lda #ST_LINKED_DIRECTORY
sta create_params::storage_type
: MLI_CALL CREATE, create_params
beq :+
jmp handle_error_code
: lda is_dir_flag
beq do_dir
jmp L341B
.byte 0
rts
do_dir: jmp copy_dir
is_dir_flag:
.byte 0
.endproc
;;; ============================================================
L353B: .byte 0
L353C: .byte 0
remove_filename_from_path1_alt:
jmp remove_filename_from_path1
;;; ============================================================
.proc do_copy
lda file_info + 16 ; file_type ???
cmp #$0F ; FT_DIRECTORY ???
bne do_file
;; Directory ???
jsr append_filename_to_path2
jsr show_copying_screen
MLI_CALL GET_FILE_INFO, get_file_info_params2
beq ok
jmp handle_error_code
onerr: jsr remove_filename_from_path1
jsr remove_filename_from_path2
lda #$FF
sta L3467
jmp exit
ok: jsr append_filename_to_path1
jsr create_dir
bcs onerr
jsr remove_filename_from_path2
jmp exit
;; File ???
do_file:
jsr append_filename_to_path1
jsr append_filename_to_path2
jsr show_copying_screen
MLI_CALL GET_FILE_INFO, get_file_info_params2
beq :+
jmp handle_error_code
: jsr L35A9
bcc :+
jmp show_no_space_prompt
: jsr remove_filename_from_path2
jsr create_dir
bcs cleanup
jsr append_filename_to_path2
jsr copy_dir
jsr remove_filename_from_path2
jsr remove_filename_from_path1
exit: rts
cleanup:
jsr remove_filename_from_path1
rts
.endproc
;;; ============================================================
.proc L35A9
MLI_CALL GET_FILE_INFO, get_file_info_params2
beq :+
jmp handle_error_code
: lda #0
sta L3641
sta L3641+1
MLI_CALL GET_FILE_INFO, get_file_info_params3
beq :+
cmp #ERR_FILE_NOT_FOUND
beq L35D7
jmp handle_error_code
: copy16 get_file_info_params3::blocks_used, L3641
L35D7: lda path1
sta L363F
ldy #$01
L35DF: iny
cpy path1
bcs L3635
lda path1,y
cmp #'/'
bne L35DF
tya
sta path1
sta L3640
MLI_CALL GET_FILE_INFO, get_file_info_params3
beq :+
jmp handle_error_code
: sub16 get_file_info_params3::aux_type, get_file_info_params3::blocks_used, L363D
sub16 L363D, L3641, L363D
cmp16 L363D, get_file_info_params2::blocks_used
bcs L3635
sec
bcs :+
L3635: clc
: lda L363F
sta path1
rts
L363D: .word 0
L363F: .byte 0
L3640: .byte 0
L3641: .word 0
.endproc
;;; ============================================================
.proc copy_dir
MLI_CALL OPEN, open_srcdir_params
beq :+
jsr handle_error_code
: MLI_CALL OPEN, open_dstdir_params
beq :+
jmp handle_error_code
: lda open_srcdir_params::ref_num
sta read_srcdir_params::ref_num
sta close_srcdir_params::ref_num
lda open_dstdir_params::ref_num
sta write_dstdir_params::ref_num
sta close_dstdir_params::ref_num
loop: copy16 #dircopy_bufsize, read_srcdir_params::request_count
MLI_CALL READ, read_srcdir_params
beq :+
cmp #ERR_END_OF_FILE
beq finish
jmp handle_error_code
: copy16 read_srcdir_params::trans_count, write_dstdir_params::request_count
ora read_srcdir_params::trans_count
beq finish
MLI_CALL WRITE, write_dstdir_params
beq :+
jmp handle_error_code
: lda write_dstdir_params::trans_count
cmp #<dircopy_bufsize
bne finish
lda write_dstdir_params::trans_count+1
cmp #>dircopy_bufsize
beq loop
finish: MLI_CALL CLOSE, close_dstdir_params
MLI_CALL CLOSE, close_srcdir_params
jsr get_file_info_and_copy
jsr do_set_file_info
rts
.endproc
;;; ============================================================
.proc create_dir
;; Copy file_type, aux_type, storage_type
ldx #7
: lda get_file_info_params2,x
sta create_dir_params,x
dex
cpx #3
bne :-
lda #ACCESS_DEFAULT
sta create_dir_params::access
;; Copy dates
COPY_STRUCT DateTime, get_file_info_params2::create_date, create_dir_params::create_date
;; Create it
lda create_dir_params::storage_type
cmp #ST_VOLUME_DIRECTORY
bne :+
lda #ST_LINKED_DIRECTORY
sta create_dir_params::storage_type
: MLI_CALL CREATE, create_dir_params
clc
beq :+
jmp handle_error_code
: rts
.endproc
;;; ============================================================
.res 4, 0
;;; ============================================================
.proc append_filename_to_path2
lda filename
bne :+
rts
: ldx #$00
ldy path2
lda #'/'
sta path2+1,y
iny
loop: cpx filename
bcs done
lda filename+1,x
sta path2+1,y
inx
iny
jmp loop
done: sty path2
rts
.endproc
;;; ============================================================
.proc remove_filename_from_path2
ldx path2
bne loop
rts
loop: lda path2,x
cmp #'/'
beq done
dex
bne loop
stx path2
rts
done: dex
stx path2
rts
.endproc
;;; ============================================================
.proc append_filename_to_path1
lda filename
bne :+
rts
: ldx #0
ldy path1
lda #'/'
sta path1+1,y
iny
loop: cpx filename
bcs done
lda filename+1,x
sta path1+1,y
inx
iny
jmp loop
done: sty path1
rts
.endproc
;;; ============================================================
.proc remove_filename_from_path1
ldx path1
bne loop
rts
loop: lda path1,x
cmp #'/'
beq done
dex
bne loop
stx path1
rts
done: dex
stx path1
rts
.endproc
;;; ============================================================
.proc L3777
ldy #0
sta L353C
dey
loop: iny
lda L324A,y
cmp #'/'
bne :+
sty L353C
: sta path2,y
cpy L324A
bne loop
ldy L320A
loop2: lda L320A,y
sta path1,y
dey
bpl loop2
rts
.endproc
;;; ============================================================
.proc do_set_file_info
lda #7 ; SET_FILE_INFO param_count
sta get_file_info_params3
MLI_CALL SET_FILE_INFO, get_file_info_params3
lda #10 ; GET_FILE_INFO param_count
sta get_file_info_params3
rts
.endproc
.proc get_file_info_and_copy
MLI_CALL GET_FILE_INFO, get_file_info_params2
bne fail
COPY_BYTES $B, get_file_info_params2::access, get_file_info_params3::access
rts
fail: pla
pla
rts
.endproc
;;; ============================================================
;;; Compute first offset into selector file - A*16 + 2
.proc compute_label_addr
addr := selector_buffer + $2
jsr ax_times_16
clc
adc #<addr
tay
txa
adc #>addr
tax
tya
rts
.endproc
;;; ============================================================
;;; Compute second offset into selector file - A*64 + $182
.proc compute_path_addr
addr := selector_buffer + $182
jsr ax_times_64
clc
adc #<addr
tay
txa
adc #>addr
tax
tya
rts
.endproc
;;; ============================================================
.byte $00,$00
;;; ============================================================
.proc read_selector_list_impl
open_io_buffer := $4000
DEFINE_OPEN_PARAMS open_params, str_selector_list, open_io_buffer
str_selector_list:
PASCAL_STRING "Selector.List"
DEFINE_READ_PARAMS read_params, selector_buffer, selector_buflen
DEFINE_CLOSE_PARAMS close_params
start: MLI_CALL OPEN, open_params
bne :+
lda open_params::ref_num
sta read_params::ref_num
MLI_CALL READ, read_params
MLI_CALL CLOSE, close_params
lda #0
: rts
.endproc
read_selector_list := read_selector_list_impl::start
;;; ============================================================
.proc ax_times_16
ldx #0
stx bits
.repeat 4
asl a
rol bits
.endrepeat
ldx bits
rts
bits: .byte 0
.endproc
;;; ============================================================
.proc ax_times_64
ldx #0
stx bits
.repeat 6
asl a
rol bits
.endrepeat
ldx bits
rts
bits: .byte $00
.endproc
;;; ============================================================
.proc invoke_selector_or_desktop_impl
sys_start := $2000
sys_size := $400
open_dt2_io_buffer := $5000
open_sel_io_buffer := $5400
DEFINE_OPEN_PARAMS open_desktop2_params, str_desktop2, open_dt2_io_buffer
DEFINE_OPEN_PARAMS open_selector_params, str_selector, open_sel_io_buffer
DEFINE_READ_PARAMS read_params, sys_start, sys_size
DEFINE_CLOSE_PARAMS close_everything_params
str_selector:
PASCAL_STRING "Selector"
str_desktop2:
PASCAL_STRING "DeskTop2"
start: MLI_CALL CLOSE, close_everything_params
MLI_CALL OPEN, open_selector_params
beq selector
MLI_CALL OPEN, open_desktop2_params
beq desktop2
brk ; just crash
desktop2:
lda open_desktop2_params::ref_num
jmp read
selector:
lda open_selector_params::ref_num
read: sta read_params::ref_num
MLI_CALL READ, read_params
MLI_CALL CLOSE, close_everything_params
jmp sys_start
.endproc
invoke_selector_or_desktop := invoke_selector_or_desktop_impl::start
;;; ============================================================
.proc L38B2
ptr := $6
stax ptr
ldy #$00
lda (ptr),y
tay
: lda (ptr),y
sta L324A,y
dey
bpl :-
ldy L324A
: lda L324A,y
and #CHAR_MASK
cmp #'/'
beq L38D2
dey
bne :-
L38D2: dey
sty L324A
L38D6: lda L324A,y
and #CHAR_MASK
cmp #'/'
beq :+
dey
bpl L38D6
: ldx #$00
: iny
inx
lda L324A,y
sta L328A,x
cpy L324A
bne :-
stx L328A
lda LCBANK2
lda LCBANK2
ldy ramcard_prefix
: lda ramcard_prefix,y
sta L320A,y
dey
bpl :-
lda ROMIN2
rts
.endproc
;;; ============================================================
str_copying:
PASCAL_STRING "Copying:"
str_insert:
PASCAL_STRING "Insert the source disk and press <Return> to continue or <ESC> to cancel"
str_not_enough:
PASCAL_STRING "Not enough room in the RAMCard, press <Return> to continue"
str_error:
PASCAL_STRING "Error $"
str_occured:
PASCAL_STRING " occured when copying "
str_not_completed:
PASCAL_STRING "The copy was not completed, press <Return> to continue."
;;; ============================================================
.proc show_copying_screen
jsr HOME
lda #0
jsr VTABZ
lda #0
jsr set_htab
addr_call cout_string, str_copying
addr_call cout_string_newline, path2
rts
.endproc
;;; ============================================================
.proc show_insert_prompt
lda #0
jsr VTABZ
lda #0
jsr set_htab
addr_call cout_string, str_insert
jsr wait_enter_escape
cmp #CHAR_ESCAPE
bne :+
jmp finish_and_invoke
: jsr HOME
rts
.endproc
;;; ============================================================
.proc show_no_space_prompt
lda #0
jsr VTABZ
lda #0
jsr set_htab
addr_call cout_string, str_not_enough
jsr wait_enter_escape
jsr HOME
jmp invoke_selector_or_desktop
.endproc
;;; ============================================================
.proc handle_error_code
cmp #ERR_OVERRUN_ERROR
bne :+
jsr show_no_space_prompt
jmp finish_and_invoke
: cmp #ERR_VOLUME_DIR_FULL
bne show_error
jsr show_no_space_prompt
jmp finish_and_invoke
.endproc
;;; ============================================================
.proc show_error
;; Show error
pha
addr_call cout_string, str_error
pla
jsr PRBYTE
addr_call cout_string, str_occured
addr_call cout_string_newline, path2
addr_call cout_string, str_not_completed
;; Wait for keyboard
sta KBDSTRB
loop: lda KBD
bpl loop
and #CHAR_MASK
sta KBDSTRB
cmp #'M'
beq monitor
cmp #'m'
beq monitor
cmp #CHAR_RETURN
bne loop
jsr HOME
jmp invoke_selector_or_desktop
.endproc
monitor:
jmp MONZ
;;; ============================================================
.proc cout_string_newline
jsr cout_string
lda #$80|CHAR_RETURN
jmp COUT
;; fall through
.endproc
.proc cout_string
ptr := $6
stax ptr
ldy #0
lda (ptr),y
sta @len
beq done
: iny
lda ($06),y
ora #$80
jsr COUT
@len := *+1
cpy #0 ; self-modified
bne :-
done: rts
.endproc
.proc set_htab
sta CH
rts
.endproc
;;; ============================================================
.proc wait_enter_escape
lda KBD
bpl wait_enter_escape
sta KBDSTRB
and #CHAR_MASK
cmp #CHAR_ESCAPE
beq done
cmp #CHAR_RETURN
bne wait_enter_escape
done: rts
.endproc
;;; ============================================================
.proc finish_and_invoke
jsr HOME
jmp invoke_selector_or_desktop
.endproc
;;; ============================================================
.endproc ; copy_selector_entries_to_ramcard
;;; ============================================================
;;; Loaded at $1000 by DeskTop2 on Quit, and copies $1100-$13FF
;;; to Language Card Bank 2 $D100-$D3FF, to restore saved quit
;;; (selector/dispatch) handler, then does ProDOS QUIT.
str_quit_code: PASCAL_STRING "Quit.tmp"
PROC_AT quit_restore_proc, $1000
lda LCBANK2
lda LCBANK2
ldx #0
:
.repeat 3, i
lda $1100 + ($100 * i), x
sta SELECTOR + ($100 * i), x
.endrepeat
dex
bne :-
lda ROMIN2
MLI_CALL QUIT, quit_params
DEFINE_QUIT_PARAMS quit_params
PAD_TO $1100
END_PROC_AT
.assert .sizeof(quit_restore_proc) = $100, error, "Proc length mismatch"
.proc preserve_quit_code_impl
quit_code_io := $800
quit_code_addr := $1000
quit_code_size := $400
DEFINE_CREATE_PARAMS create_params, str_quit_code, ACCESS_DEFAULT, $F1
DEFINE_OPEN_PARAMS open_params, str_quit_code, quit_code_io
DEFINE_WRITE_PARAMS write_params, quit_code_addr, quit_code_size
DEFINE_CLOSE_PARAMS close_params
start: lda LCBANK2
lda LCBANK2
ldx #0
:
lda quit_restore_proc, x
sta $1000, x
.repeat 3, i
lda SELECTOR + ($100 * i), x
sta $1100 + ($100 * i), x
.endrepeat
dex
bne :-
lda ROMIN2
;; Create file (if needed)
copy16 DATELO, create_params::create_date
copy16 TIMELO, create_params::create_time
MLI_CALL CREATE, create_params
beq :+
cmp #ERR_DUPLICATE_FILENAME
bne done
;; Populate it
: MLI_CALL OPEN, open_params
lda open_params::ref_num
sta write_params::ref_num
sta close_params::ref_num
MLI_CALL WRITE, write_params
MLI_CALL CLOSE, close_params
done: rts
.endproc
preserve_quit_code := preserve_quit_code_impl::start
;;; ============================================================
PAD_TO $4000
.assert * = $4000, error, "Segment size mismatch"