1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-22 17:29:34 +00:00

POSIX file I/O by Oliver Schmidt

git-svn-id: svn://svn.cc65.org/cc65/trunk@3457 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2005-04-12 09:12:48 +00:00
parent 49d1b8f553
commit feacac1394
12 changed files with 828 additions and 84 deletions

View File

@ -43,6 +43,7 @@ OBJS= _scrsize.o \
cclear.o \
cgetc.o \
chline.o \
close.o \
clrscr.o \
color.o \
cputc.o \
@ -57,6 +58,9 @@ OBJS= _scrsize.o \
diosectsize.o \
diowrite.o \
dosdetect.o \
filedes.o \
fileerr.o \
filename.o \
get_ostype.o \
getenv.o \
gotoxy.o \
@ -65,7 +69,9 @@ OBJS= _scrsize.o \
kbhit.o \
mainargs.o \
mli.o \
open.o \
oserrlist.o \
oserror.o \
randomize.o \
rcout.o \
read.o \
@ -75,6 +81,7 @@ OBJS= _scrsize.o \
rpread.o \
rrdkey.o \
rvtabz.o \
rwcommon.o \
systime.o \
sysuname.o \
tgi_mode_table.o\

41
libsrc/apple2/close.s Normal file
View File

@ -0,0 +1,41 @@
;
; Oliver Schmidt, 30.12.2004
;
; int __fastcall__ close (int fd);
;
.export _close
.import closedirect, freebuffer
.import errnoexit, oserrexit
.import return0
.include "filedes.inc"
_close:
; Process fd
jsr getfd ; Returns A, Y and C
bcs errno
; Check for device
bmi zerofd
; Close file
jsr closedirect ; Preserves Y
bcs oserr
; Mark fdtab slot as free
zerofd: lda #$00
sta fdtab + FD::REF_NUM,y
; Cleanup I/O buffer
jsr freebuffer
; Return success
jmp return0
; Return errno
errno: jmp errnoexit
; Return oserror
oserr: jmp oserrexit

16
libsrc/apple2/filedes.inc Normal file
View File

@ -0,0 +1,16 @@
;
; Oliver Schmidt, 30.12.2004
;
; File descriptor management for the POSIX I/O routines
;
.struct FD
REF_NUM .byte
FLAGS .byte
BUFFER .addr
.endstruct
.global fdtab
.global getfd
MAX_FDS = 8

64
libsrc/apple2/filedes.s Normal file
View File

@ -0,0 +1,64 @@
;
; Oliver Schmidt, 30.12.2004
;
; File descriptor management for the POSIX I/O routines
;
.include "errno.inc"
.include "fcntl.inc"
.include "filedes.inc"
getfd:
; Check for handle >= 256
cpx #$00
bne error
; Check for handle >= MAX_FDS
cmp #MAX_FDS
bcs error
.if .sizeof(FD) = 4
; Convert handle to fdtab slot
asl
asl
.else
.error "Assertion failed"
.endif
; Check for fdtab slot in use
tay
lda fdtab + FD::REF_NUM,y
beq error
; Return success
clc
rts
; Load errno code and return error
error: lda #EINVAL
sec
rts
.data
fdtab: .if .sizeof(FD) = 4
.byte $80 ; STDIN_FILENO ::REF_NUM
.byte O_RDONLY ; STDIN_FILENO ::FLAGS
.addr $0000 ; STDIN_FILENO ::BUFFER
.byte $80 ; STDOUT_FILENO::REF_NUM
.byte O_WRONLY ; STDOUT_FILENO::FLAGS
.addr $0000 ; STDOUT_FILENO::BUFFER
.byte $80 ; STDERR_FILENO::REF_NUM
.byte O_WRONLY ; STDERR_FILENO::FLAGS
.addr $0000 ; STDERR_FILENO::BUFFER
.else
.error "Assertion failed"
.endif
.res (MAX_FDS - 3) * .sizeof(FD)

18
libsrc/apple2/fileerr.s Normal file
View File

@ -0,0 +1,18 @@
;
; Oliver Schmidt, 15.01.2004
;
; Error handling for ProDOS 8 file I/O
;
.export errnoexit, oserrexit
.include "errno.inc"
errnoexit:
jsr __seterrno ; Returns with A = 0
oserrexit:
sta __oserror
lda #$FF
tax
rts

97
libsrc/apple2/filename.s Normal file
View File

@ -0,0 +1,97 @@
;
; Oliver Schmidt, 30.12.2004
;
; File name handling for ProDOS 8 file I/O
;
.export pushname, popname
.import subysp, addysp, decsp1
.include "zeropage.inc"
.include "mli.inc"
pushname:
sta ptr1
stx ptr1+1
; Alloc pathname buffer
ldy #64+1 ; Max pathname length + zero
jsr subysp
; Check for full pathname
ldy #$00
lda (ptr1),y
cmp #'/'
beq copy
; Check for system prefix
lda PFIXPTR
bne copy
; Use unit number of most recent accessed device
lda DEVNUM
sta mliparam + MLI::ON_LINE::UNIT_NUM
; Use allocated pathname buffer
lda sp
ldx sp+1
sta mliparam + MLI::ON_LINE::DATA_BUFFER
stx mliparam + MLI::ON_LINE::DATA_BUFFER+1
; Get volume name
lda #ON_LINE_CALL
ldx #ON_LINE_COUNT
jsr callmli
bcs addsp65
; Get volume name length
lda (sp),y
and #15 ; Max volume name length
; Bracket volume name with slashes to form prefix
sta tmp1
lda #'/'
sta (sp),y
ldy tmp1
iny ; Leading slash
sta (sp),y
iny ; Trailing slash
; Adjust source pointer for copy
sty tmp1
lda ptr1
sec
sbc tmp1
bcs :+
dec ptr1+1
: sta ptr1
; Copy source to allocated pathname buffer
copy: lda (ptr1),y
sta (sp),y
beq setlen
iny
cpy #64+1 ; Max pathname length + zero
bcc copy
; Load oserror code
lda #$40 ; "Invalid pathname syntax"
; Free pathname buffer
addsp65:ldy #64+1
bne addsp ; Branch always
; Alloc and set length byte
setlen: tya
jsr decsp1 ; Preserves A
ldy #$00
sta (sp),y
; Return success
tya
rts
popname:
; Cleanup stack
ldy #1 + 64+1 ; Length byte + max pathname length + zero
addsp: jmp addysp ; Preserves A

247
libsrc/apple2/open.s Normal file
View File

@ -0,0 +1,247 @@
;
; Oliver Schmidt, 30.12.2004
;
; int open (const char* name, int flags, ...);
;
; 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, closedirect, freebuffer
.destructor closeallfiles, 17
.import pushname, popname
.import errnoexit, oserrexit
.import __aligned_malloc, _free
.import addysp, incsp4, pushax, popax
.include "zeropage.inc"
.include "errno.inc"
.include "fcntl.inc"
.include "mli.inc"
.include "filedes.inc"
_open:
; Throw away all parameters except name
; and flags occupying together 4 bytes
dey
dey
dey
dey
jsr addysp
; Start with first fdtab slot
ldy #$00
; Check for free fdtab slot
: lda fdtab + FD::REF_NUM,y
beq found
.if .sizeof(FD) = 4
; Advance to next fdtab slot
iny
iny
iny
iny
.else
.error "Assertion failed"
.endif
; Check for end of fdtab
cpy #MAX_FDS * .sizeof(FD)
bcc :-
; Load errno codes
lda #ENOMEM ^ EMFILE
enomem: eor #ENOMEM
; Cleanup stack
jsr incsp4 ; Preserves A
; Return errno
jmp errnoexit
; Save fdtab slot
found: tya
pha
; Alloc I/O buffer
lda #$00
ldx #>$0400
jsr pushax ; Preserves A
ldx #>$0100
jsr __aligned_malloc
; Restore fdtab slot
pla
tay
; Get and check I/O buffer high byte
txa
beq enomem
; Set I/O buffer high byte (low byte remains zero)
sta fdtab + FD::BUFFER+1,y
sty tmp2 ; Save fdtab slot
; Get and save flags
jsr popax
sta tmp3
; Get and push name
jsr popax
jsr pushname
bne oserr1
; Set pushed name
lda sp
ldx sp+1
sta mliparam + MLI::OPEN::PATHNAME
stx mliparam + MLI::OPEN::PATHNAME+1
; Check for create flag
lda tmp3 ; Restore flags
and #O_CREAT
beq open
.if MLI::CREATE::PATHNAME = MLI::OPEN::PATHNAME
; PATHNAME already set
.else
.error "Assertion failed"
.endif
; Set all other parameters from template
ldx #(MLI::CREATE::CREATE_TIME+1) - (MLI::CREATE::PATHNAME+1) - 1
: lda CREATE,x
sta mliparam + MLI::CREATE::ACCESS,x
dex
bpl :-
; Create file
lda #CREATE_CALL
ldx #CREATE_COUNT
jsr callmli
bcc open
; Check for ordinary errors
cmp #$47 ; "Duplicate filename"
bne oserr2
; Check for exclusive flag
lda tmp3 ; Restore flags
and #O_EXCL
beq open
lda #$47 ; "Duplicate filename"
; Cleanup name
oserr2: jsr popname ; Preserves A
oserr1: ldy tmp2 ; Restore fdtab slot
; Cleanup I/O buffer
pha ; Save oserror code
jsr freebuffer
pla ; Restore oserror code
; Return oserror
jmp oserrexit
open: ldy tmp2 ; Restore fdtab slot
; Set allocated I/O buffer
ldx fdtab + FD::BUFFER+1,y
sta mliparam + MLI::OPEN::IO_BUFFER ; A = 0
stx mliparam + MLI::OPEN::IO_BUFFER+1
; Open file
lda #OPEN_CALL
ldx #OPEN_COUNT
jsr callmli
bcs oserr2
; Get and save fd
ldx mliparam + MLI::OPEN::REF_NUM
stx tmp1 ; Save fd
; Set flags and check for truncate flag
lda tmp3 ; Restore flags
sta fdtab + FD::FLAGS,y
and #O_TRUNC
beq done
; Set fd and zero size
stx mliparam + MLI::EOF::REF_NUM
ldx #$02
lda #$00
: sta mliparam + MLI::EOF::EOF,x
dex
bpl :-
; Set file size
lda #SET_EOF_CALL
ldx #EOF_COUNT
jsr callmli
bcc done
; Cleanup file
pha ; Save oserror code
lda tmp1 ; Restore fd
jsr closedirect
pla ; Restore oserror code
bne oserr2 ; Branch always
; Store fd
done: lda tmp1 ; Restore fd
sta fdtab + FD::REF_NUM,y
.if .sizeof(FD) = 4
; Convert fdtab slot to handle
tya
lsr
lsr
.else
.error "Assertion failed"
.endif
; Cleanup name
jsr popname ; Preserves A
; Return success
ldx #$00
rts
freebuffer:
; Free I/O buffer
lda #$00
ldx fdtab + FD::BUFFER+1,y
jmp _free
closeallfiles:
; All open files
lda #$00
closedirect:
; Set fd
sta mliparam + MLI::CLOSE::REF_NUM
; Call close
lda #CLOSE_CALL
ldx #CLOSE_COUNT
jmp callmli
.rodata
CREATE: .byte %11000011 ; ACCESS: Standard full access
.byte $06 ; FILE_TYPE: Standard binary file
.word $0000 ; AUX_TYPE: Load address N/A
.byte $01 ; STORAGE_TYPE: Standard seedling file
.word $0000 ; CREATE_DATE: Current date
.word $0000 ; CREATE_TIME: Current time

62
libsrc/apple2/oserror.s Normal file
View File

@ -0,0 +1,62 @@
;
; Ullrich von Bassewitz, 17.05.2000
;
; int __fastcall__ _osmaperrno (unsigned char oserror);
;
.export __osmaperrno
.include "errno.inc"
__osmaperrno:
ldx #ErrTabSize
: cmp ErrTab-2,x ; Search for the error code
beq :+ ; Jump if found
dex
dex
bne :- ; Next entry
; Code not found, return EUNKNOWN
lda #<EUNKNOWN
ldx #>EUNKNOWN
rts
; Found the code
: lda ErrTab-1,x
ldx #$00 ; High byte always zero
rts
.rodata
ErrTab: .byte $01, ENOSYS ; Invalid MLI function code number
.byte $04, EINVAL ; Incorrect parameter count
.byte $25, ENOMEM ; Interrupt table full
.byte $27, EIO ; I/O error
.byte $28, ENODEV ; No device connected
.byte $2B, EACCES ; Write protected
; .byte $2E, EUNKNOWN ; Disk switched
.byte $2F, ENODEV ; No disk in drive
.byte $40, EINVAL ; Invalid pathname syntax
.byte $42, EMFILE ; Too many files open
.byte $43, EINVAL ; Bad reference number
.byte $44, ENOENT ; Bad pathname
.byte $45, ENOENT ; Volume not mounted
.byte $46, ENOENT ; File not found
.byte $47, EEXIST ; File already exists
.byte $48, ENOSPC ; Disk full
.byte $49, ENOSPC ; Directory full
; .byte $4A, EUNKNOWN ; Incompatible ProDOS version
.byte $4B, EINVAL ; Unsupported storage type
; .byte $4C, EUNKNOWN ; End of file
.byte $4D, ESPIPE ; Position past EOF
.byte $4E, EACCES ; Access denied
.byte $50, EINVAL ; File already open
; .byte $51, EUNKNOWN ; File count bad
.byte $52, ENODEV ; Not a ProDOS disk
.byte $53, ERANGE ; Parameter out of range
.byte $55, EMFILE ; Too many devices mounted
.byte $56, EINVAL ; Bad buffer address
; .byte $57, EUNKNOWN ; Duplicate volume name
; .byte $5A, EUNKNOWN ; Damaged disk free space bit map
ErrTabSize = (* - ErrTab)

View File

@ -1,50 +1,105 @@
;
; Ullrich von Bassewitz, 30.05.1998
; Oliver Schmidt, 12.01.2005
;
; int read (int fd, void* buf, int count);
;
; THIS IS A HACK!
; int __fastcall__ read (int fd, void* buf, unsigned count);
;
.export _read
.import popax, _cputc, RDKEY
.importzp ptr1, ptr2, ptr3
.constructor initprompt
.export _read
.import rwprolog, rwcommon
.import errnoexit
.import RDKEY, COUT
_read: jsr popax ; get count
sta ptr2
stx ptr2+1 ; save it for later
jsr popax ; get buf
sta ptr1
stx ptr1+1
jsr popax ; get fd and discard it
lda #$00
sta ptr3
sta ptr3+1 ; set count
.include "zeropage.inc"
.include "errno.inc"
.include "fcntl.inc"
.include "mli.inc"
.include "filedes.inc"
.include "apple2.inc"
L1: lda ptr2
ora ptr2+1 ; count zero?
beq L9
jsr RDKEY
and #$7F ; clear high bit.
pha
jsr _cputc
pla
ldy #$00 ; offset into string
sta (ptr1),y ; save char
inc ptr1
bne L2
inc ptr1+1
L2: inc ptr3 ; increment count
bne L3
inc ptr3+1
L3: cmp #$0D ; CR?
bne L1
.segment "INIT"
; Done, return the count
initprompt:
; Set prompt <> ']' to let DOS 3.3 know that we're
; not in Applesoft immediate mode and thus keep it
; from scanning our device I/O for DOS commands.
lda #$80 ; Same value used at $D52C
sta PROMPT
rts
L9: lda ptr3
ldx ptr3+1
rts
.code
_read:
; Get parameters
jsr rwprolog
bcs errno
tax ; Save fd
; Check for read access
lda fdtab + FD::FLAGS,y
and #O_RDONLY
beq einval
; Check for device
txa ; Restore fd
bmi device
; Do read
ldy #READ_CALL
jmp rwcommon
; Set counter to zero
device: lda #$00
sta ptr3
sta ptr3+1
; Check for zero count
lda ptr2
ora ptr2+1
beq check
; Read from device and echo to device
next: jsr RDKEY
jsr COUT
; Clear hi bit and check for '\r'
and #$7F
cmp #$0D
bne :+
; Replace with '\n' and set count to zero
lda #$0A
ldy #$00
sty ptr2
sty ptr2+1
; Put char into buf
: ldy #$00
sta (ptr1),y
; Increment pointer
inc ptr1
bne :+
inc ptr1+1
; Increment counter
: inc ptr3
bne check
inc ptr3+1
; Check for counter less than count
check: lda ptr3
cmp ptr2
bcc next
ldx ptr3+1
cpx ptr2+1
bcc next
; Return success, AX already set
rts
; Load errno code
einval: lda #EINVAL
; Return errno
errno: jmp errnoexit

59
libsrc/apple2/rwcommon.s Normal file
View File

@ -0,0 +1,59 @@
;
; Oliver Schmidt, 12.01.2005
;
.export rwprolog, rwcommon, rwepilog
.import oserrexit
.import popax
.include "zeropage.inc"
.include "fcntl.inc"
.include "mli.inc"
.include "filedes.inc"
rwprolog:
; Save count
sta ptr2
stx ptr2+1
; Get and save buf
jsr popax
sta ptr1
stx ptr1+1
; Get and process fd
jsr popax
jmp getfd ; Returns A, Y and C
rwcommon:
; Set fd
sta mliparam + MLI::RW::REF_NUM
; Set buf
lda ptr1
ldx ptr1+1
sta mliparam + MLI::RW::DATA_BUFFER
stx mliparam + MLI::RW::DATA_BUFFER+1
; Set count
lda ptr2
ldx ptr2+1
sta mliparam + MLI::RW::REQUEST_COUNT
stx mliparam + MLI::RW::REQUEST_COUNT+1
; Call read or write
tya
ldx #RW_COUNT
jsr callmli
bcc rwepilog
cmp #$4C ; "End of file"
bne oserr
rwepilog:
; Return success
lda mliparam + MLI::RW::TRANS_COUNT
ldx mliparam + MLI::RW::TRANS_COUNT+1
rts
; Return oserror
oserr: jmp oserrexit

View File

@ -1,52 +1,123 @@
;;
;; Kevin Ruland
;;
;; int write (int fd, const void* buf, int count);
;;
;; for now will only write to fd = stdout
;;
;
; Oliver Schmidt, 12.01.2005
;
; int __fastcall__ write (int fd, const void* buf, unsigned count);
;
.export _write
.import popax, COUT
.importzp ptr1, ptr2, ptr3
.export _write
.import rwprolog, rwcommon, rwepilog
.import errnoexit, oserrexit
.import COUT
.proc _write
.include "zeropage.inc"
.include "errno.inc"
.include "fcntl.inc"
.include "mli.inc"
.include "filedes.inc"
sta ptr2 ; Save count for later
stx ptr2+1
sta ptr3
sta ptr3+1 ; save for result
jsr popax ; get buf
sta ptr1
stx ptr1+1
jsr popax ; get fd and discard
L1: lda ptr2
ora ptr2+1 ; count zero?
beq L9
ldy #$00
lda (ptr1),y
cmp #$0A ; Check for \n = Crtl-j
bne rawout
lda #$0D ; Issue cr
rawout:
ora #$80
jsr COUT
inc ptr1
bne L2
inc ptr1+1
L2: lda ptr2
bne L3
dec ptr2
dec ptr2+1
jmp L1
L3: dec ptr2
jmp L1
_write:
; Get parameters
jsr rwprolog
bcs errno
tax ; Save fd
; No error, return count
; Check for write access
lda fdtab + FD::FLAGS,y
and #O_WRONLY
beq einval
L9: lda ptr3
ldx ptr3+1
rts
; Check for device
txa ; Restore fd
bmi device
.endproc
; Check for append flag
lda fdtab + FD::FLAGS,y
and #O_APPEND
beq write
; Set fd
stx mliparam + MLI::EOF::REF_NUM
; Get file size
lda #GET_EOF_CALL
ldx #EOF_COUNT
jsr callmli
bcs oserr
.if MLI::MARK::REF_NUM = MLI::EOF::REF_NUM
; REF_NUM already set
.else
.error "Assertion failed"
.endif
.if MLI::MARK::POSITION = MLI::EOF::EOF
; POSITION already set
.else
.error "Assertion failed"
.endif
; Set file pointer
lda #SET_MARK_CALL
ldx #MARK_COUNT
jsr callmli
bcs oserr
; Do write
write: lda fdtab + FD::REF_NUM,y
ldy #WRITE_CALL
jmp rwcommon
; Save count for epilog
device: ldx ptr2
lda ptr2+1
stx mliparam + MLI::RW::TRANS_COUNT
sta mliparam + MLI::RW::TRANS_COUNT+1
; Check for zero count
ora ptr2
beq done
; Get char from buf
ldy #$00
next: lda (ptr1),y
; Replace '\n' with '\r'
cmp #$0A
bne :+
lda #$0D
; Set hi bit and write to device
: ora #$80
.ifndef __APPLE2ENH__
cmp #$E0 ; Test for lowercase
bcc output
and #$DF ; Convert to uppercase
.endif
output: jsr COUT ; Preserves X and Y
; Increment pointer
iny
bne :+
inc ptr1+1
; Decrement count
: dex
bne next
dec ptr2+1
bpl next
; Return success
done: jmp rwepilog
; Load errno code
einval: lda #EINVAL
; Return errno
errno: jmp errnoexit
; Return oserror
oserr: jmp oserrexit

View File

@ -43,6 +43,7 @@ OBJS= _scrsize.o \
cclear.o \
cgetc.o \
chline.o \
close.o \
clrscr.o \
color.o \
cputc.o \
@ -57,6 +58,9 @@ OBJS= _scrsize.o \
diosectsize.o \
diowrite.o \
dosdetect.o \
filedes.o \
fileerr.o \
filename.o \
get_ostype.o \
getenv.o \
gotoxy.o \
@ -65,7 +69,9 @@ OBJS= _scrsize.o \
kbhit.o \
mainargs.o \
mli.o \
open.o \
oserrlist.o \
oserror.o \
randomize.o \
rcout.o \
read.o \
@ -75,6 +81,7 @@ OBJS= _scrsize.o \
rpread.o \
rrdkey.o \
rvtabz.o \
rwcommon.o \
systime.o \
sysuname.o \
textframe.o \