;
; int open (const char* name, int flags, ...); /* May take a mode argument */
;
+; Be sure to keep the value priority of closeallfiles lower than that of
+; closeallstreams (which is the high level C file I/O counterpart and must be
+; called before closeallfiles).
+
.export _open
+ .destructor closeallfiles, 17
+ .import SETLFS, OPEN, CLOSE
.import addysp, popax
- .import scratch, fnparse, fncomplete, fnset
- .import getdiskerror
- .import __errno, __oserror
+ .import scratch, fnparse, fnaddmode, fncomplete, fnset
+ .import opencmdchannel, closecmdchannel, readdiskerror
+ .import __oserror
.import fnunit
+ .import _close
.importzp sp, tmp2, tmp3
.include "errno.inc"
.include "fcntl.inc"
- .include "cbm.inc"
.include "filedes.inc"
;--------------------------------------------------------------------------
-; initstdout: Open the stdout and stderr file descriptors for the screen.
+; 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
- cpy #4 ; correct # of arguments (bytes)?
- beq parmok ; parameter count ok
- tya ; parm count < 4 shouldn't be needed to be...
- sec ; ...checked (it generates a c compiler warning)
- sbc #4
- tay
- jsr addysp ; fix stack, throw away unused parameters
+; 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
bcs nofile
stx tmp2
-; Check the flags. We cannot have:
-;
-; - both, read and write flags set
-; - the append flag set
-;
-
- lda tmp3
- and #O_RDWR
- beq invflags ; Neither read nor write
- cmp #O_RDWR
- beq invflags ; Jump if both set
- cmp #O_RDONLY
- beq doread
-
-; Write bit is set. We cannot open a file for writing without creating it,
-; so check for the O_CREAT bit.
+; 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_CREAT
- beq invflags
+ and #(O_RDWR | O_CREAT)
+ cmp #O_RDONLY ; Open for reading?
+ beq doread ; Yes: Branch
+ cmp #(O_WRONLY | O_CREAT) ; Open for writing?
+ bne invflags ; No: Invalid open mode
; If O_TRUNC is set, scratch the file, but ignore any errors
beq notrunc
jsr scratch
-; Complete the the file name
+; Complete the the file name. Check for append mode here.
notrunc:
- lda #'w'
- jsr fncomplete
+ lda tmp3 ; Get the mode again
+ ldx #'a'
+ and #O_APPEND ; Append mode?
+ bne append ; Branch if yes
+ ldx #'w'
+append: txa
+ jsr fncomplete ; Add type and mode to the name
; Setup the real open flags
; Read bit is set. Add an 'r' to the name
doread: lda #'r'
- jsr fncomplete
+ jsr fnaddmode ; Add the mode to the name
lda #LFN_READ
; Common read/write code. Flags in A, handle in tmp2
jsr OPEN
bcs error
-; Read the error channel
+; Open the the drive command channel and read it
ldx fnunit
- jsr getdiskerror
- cmp #0
- beq isopen ; Branch if no error
-
-; We had an error, close the file
-
- pha
- lda tmp2
- clc
- adc #LFN_OFFS
- jsr CLOSE
- pla
- bne error ; Branch always
+ jsr opencmdchannel
+ bne closeandexit
+ ldx fnunit
+ jsr readdiskerror
+ bne closeandexit ; Branch on error
; File is open. Mark it as open in the table
-isopen: ldx tmp2
+ ldx tmp2
lda tmp3
sta fdtab,x
lda fnunit
sta __errno+1
beq errout
+; Error entry: Close the file and exit
+closeandexit:
+ pha
+ lda tmp2
+ clc
+ adc #LFN_OFFS
+ jsr CLOSE
+ ldx fnunit
+ jsr closecmdchannel
+ pla
+ bne error ; Branch always
.endproc