cc65/libsrc/cbm/open.s

197 lines
4.9 KiB
ArmAsm

;
; Ullrich von Bassewitz, 16.11.2002
;
; int open (const char* name, int flags, ...); /* May take a mode argument */
.export _open
.destructor closeallfiles, 5
.import addysp, popax
.import scratch, fnparse, fnaddmode, fncomplete, fnset
.import opencmdchannel, closecmdchannel, readdiskerror
.import fnunit, fnisfile
.import _close
.importzp sp, tmp2, tmp3
.include "errno.inc"
.include "fcntl.inc"
.include "filedes.inc"
.include "cbm.inc"
;--------------------------------------------------------------------------
; closeallfiles: Close all open files.
.proc closeallfiles
ldx #MAX_FDS-1
loop: lda fdtab,x
beq next ; Skip unused entries
; Close this file
txa
pha ; Save current value of X
ldx #0
jsr _close
pla
tax
; Next file
next: dex
bpl loop
rts
.endproc
;--------------------------------------------------------------------------
; _open
.proc _open
; Throw away any additional parameters passed through the ellipsis
dey ; Parm count < 4 shouldn't be needed to be...
dey ; ...checked (it generates a c compiler warning)
dey
dey
beq parmok ; Branch if parameter count ok
jsr addysp ; Fix stack, throw away unused parameters
; Parameters ok. Pop the flags and save them into tmp3
parmok: jsr popax ; Get flags
sta tmp3
; Get the filename from stack and parse it. Bail out if is not ok
jsr popax ; Get name
jsr fnparse ; Parse it
tax
bne oserror ; Bail out if problem with name
; Get a free file handle and remember it in tmp2
jsr freefd
lda #EMFILE ; Load error code
bcs seterrno ; Jump in case of errors
stx tmp2
; Check the flags. We cannot have both, read and write flags set, and we cannot
; open a file for writing without creating it.
lda tmp3
and #(O_RDWR | O_CREAT)
cmp #O_RDONLY ; Open for reading?
beq doread ; Yes: Branch
cmp #(O_WRONLY | O_CREAT) ; Open for writing?
beq dowrite
; Invalid open mode
lda #EINVAL
; Error entry. Sets _errno, clears __oserror, returns -1
seterrno:
jmp ___directerrno
; Error entry: Close the file and exit. OS error code is in A on entry
closeandexit:
pha
lda tmp2
clc
adc #LFN_OFFS
jsr CLOSE
ldx fnunit
jsr closecmdchannel
pla
; Error entry: Set oserror and errno using error code in A and return -1
oserror:jmp ___mappederrno
; Read bit is set. Add an 'r' to the name
doread: lda #'r'
jsr fnaddmode ; Add the mode to the name
lda #LFN_READ
bne common ; Branch always
; If O_TRUNC is set, scratch the file, but ignore any errors
dowrite:
lda tmp3
and #O_TRUNC
beq notrunc
jsr scratch
; Complete the file name. Check for append mode here.
notrunc:
lda tmp3 ; Get the mode again
and #O_APPEND ; Append mode?
bne append ; Branch if yes
; Setup the name for create mode
lda #'w'
jsr fncomplete ; Add type and mode to the name
jmp appendcreate
; Append bit is set. Add an 'a' to the name
append: lda #'a'
jsr fnaddmode ; Add open mode to file name
appendcreate:
lda #LFN_WRITE
; Common read/write code. Flags in A, handle in tmp2
common: sta tmp3
jsr fnset ; Set the file name
lda tmp2
clc
adc #LFN_OFFS
ldx fnunit
ldy fnisfile ; Is this a standard file on disk?
beq nofile ; Branch if not
tay ; Use the LFN also as SA for files
nofile: ; ... else use SA=0 (read)
jsr SETLFS ; Set the file params
jsr OPEN
bcs oserror
; Open the drive command channel and read it
ldx fnunit
jsr opencmdchannel
bne closeandexit
ldx fnunit
jsr readdiskerror
bne closeandexit ; Branch on error
; File is open. Mark it as open in the table
ldx tmp2
lda tmp3
sta fdtab,x
lda fnunit
sta unittab,x ; Remember
; Done. Return the handle in a/x
txa ; Handle
ldx #0
stx ___oserror ; Clear __oserror
rts
.endproc