ORCALib/stdio.asm

6257 lines
176 KiB
NASM

keep obj/stdio
mcopy stdio.macros
case on
****************************************************************
*
* StdIO - Standard I/O Library
*
* This code implements the tables and subroutines needed to
* support the standard C library STDIO.
*
* November 1988
* Mike Westerfield
*
* Copyright 1988
* Byte Works, Inc.
*
* Note: Portions of this library appear in SysFloat.
*
****************************************************************
*
StdIO start dummy segment
copy equates.asm
end
****************************************************************
*
* void clearerr(stream)
* FILE *stream;
*
* Clears the error flag for the given stream.
*
* Inputs:
* stream - file to clear
*
****************************************************************
*
clearerr start
stream equ 4 input stream
tsc
phd
tcd
ph4 <stream verify that stream exists
jsl ~VerifyStream
bcs lb1
ldy #FILE_flag clear the error flag
lda [stream],Y
and #$FFFF-_IOERR-_IOEOF
sta [stream],Y
lb1 pld
lda 2,S
sta 6,S
pla
sta 3,S
pla
rtl
end
****************************************************************
*
* int fclose(stream)
* FILE *stream;
*
* Inputs:
* stream - pointer to the file buffer to close
*
* Outputs:
* A - EOF for an error; 0 if there was no error
*
****************************************************************
*
fclose start
nameBuffSize equ 8*1024 pathname buffer size
err equ 1 return value
p equ 3 work pointer
stdfile equ 7 is this a standard file?
csubroutine (4:stream),8
phb
phk
plb
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs rts_err
ph4 <stream do any pending I/O
jsl fflush
sta err initialize err to fflush result
stz stdfile not a standard file
lda stream+2 bypass file disposal if the file is
cmp #^stdin+4 one of the standard ones
bne cl0
lda stream
cmp #stdin+4
beq lb1
cmp #stdout+4
beq lb1
cmp #stderr+4
bne cl0
lb1 inc stdfile
bra cl3a
cl0 lla p,stderr+4 find the file record that points to this
ldy #2 one
cl1 lda [p],Y
tax
ora [p]
jeq rts_err
lda [p]
cmp stream
bne cl2
cpx stream+2
beq cl3
cl2 stx p+2
sta p
bra cl1
cl3 lda [stream] remove stream from the file list
sta [p]
lda [stream],Y
sta [p],Y
cl3a ldy #FILE_flag if the buffer was allocated by fopen then
lda [stream],Y
and #_IOMYBUF
beq cl3b
ldy #FILE_base+2 dispose of the file buffer
lda [stream],Y
pha
dey
dey
lda [stream],Y
pha
jsl free
cl3b ldy #FILE_flag if the file was opened by tmpfile then
lda [stream],Y
and #_IOTEMPFILE
beq cl3f
ph4 #nameBuffSize p = malloc(nameBuffSize)
jsl malloc
sta p
stx p+2
ora p+2 if p == NULL then
bne cl3c
lda #EOF flag error
sta err
bra cl3f just close the file
cl3c lda p
sta grPathname grPathname = p
stx grPathname+2
clc dsPathname = p+2
adc #2
bcc cl3d
inx
cl3d sta dsPathname
stx dsPathname+2
lda #nameBuffSize p->size = nameBuffSize
sta [p]
ldy #FILE_file clRefnum = grRefnum = stream->_file
lda [stream],Y
beq cl4
sta grRefnum
sta clRefNum
GetRefInfoGS gr GetRefInfoGS(gr)
bcs cl3e
OSClose cl OSClose(cl)
DestroyGS ds DestroyGS(ds)
cl3e ph4 <p free(p)
jsl free
bra cl4 else
cl3f ldy #FILE_file close the file
lda [stream],Y
beq cl4
sta clRefNum
OSClose cl
cl4 lda stdfile if this is not a standard file then
bne cl5
ph4 <stream dispose of the file buffer
jsl free
bra cl7 else
cl5 add4 stream,#sizeofFILE-4,p reset the standard out stuff
ldy #sizeofFILE-2
cl6 lda [p],Y
sta [stream],Y
dey
dey
cpy #2
bne cl6
cl7 bra rts no error found
rts_err lda #EOF
sta err
rts plb
creturn 2:err
cl dc i'1' parameter block for OSclose
clRefNum ds 2
gr dc i'3' parameter block for GetRefInfoGS
grRefnum ds 2
ds 2
grPathname ds 4
ds dc i'1' parameter block for DestroyGS
dsPathname ds 4
end
****************************************************************
*
* int feof(stream)
* FILE *stream;
*
* Inputs:
* stream - file to check
*
* Outputs:
* Returns _IOEOF if an end of file has been reached; else
* 0.
*
****************************************************************
*
feof start
stream equ 4 input stream
tsc
phd
tcd
ph4 <stream verify that stream exists
jsl ~VerifyStream
ldx #_IOEOF
bcs lb1
ldy #FILE_flag check for eof
lda [stream],Y
and #_IOEOF
tax
lb1 pld
lda 2,S
sta 6,S
pla
sta 3,S
pla
txa
rtl
end
****************************************************************
*
* int ferror(stream)
* FILE *stream;
*
* Inputs:
* stream - file to check
*
* Outputs:
* Returns _IOERR if an end of file has been reached; else
* 0.
*
****************************************************************
*
ferror start
stream equ 4 input stream
tsc
phd
tcd
ph4 <stream verify that stream exists
jsl ~VerifyStream
ldx #_IOERR
bcs lb1
ldy #FILE_flag return the error status
lda [stream],Y
and #_IOERR
tax
lb1 pld
lda 2,S
sta 6,S
pla
sta 3,S
pla
txa
rtl
end
****************************************************************
*
* int fflush(steam)
* FILE *stream;
*
* Write any pending characters to the output file
*
* Inputs:
* stream - file buffer
*
* Outputs:
* A - EOF for an error; 0 if there was no error
*
****************************************************************
*
fflush start
err equ 1 return value
sp equ 3 stream work pointer
csubroutine (4:stream),6
phb
phk
plb
lda stream if stream = nil then
ora stream+2
bne fa3
lda stderr+4 sp = stderr.next
sta sp
lda stderr+6
sta sp+2
stz err err = 0
fa1 lda sp while sp <> nil
ora sp+2
jeq rts
ph4 <sp fflush(sp);
jsl fflush
tax if returned value <> 0 then
beq fa2
sta err err = returned value
fa2 ldy #2 sp = sp^.next
lda [sp],Y
tax
lda [sp]
sta sp
stx sp+2
bra fa1 endwhile
fa3 lda #EOF assume there is an error
sta err
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs rts
ldy #FILE_flag if the mode is not writing, quit
lda [stream],Y
bit #_IOWRT
beq fl1a
tax
ldy #FILE_file set the reference number
lda [stream],Y
sta wrRefNum
ldy #FILE_base set the starting location
lda [stream],Y
sta wrDataBuffer
iny
iny
lda [stream],Y
sta wrDataBuffer+2
sec set the # of bytes to write
ldy #FILE_ptr
lda [stream],Y
sbc wrDataBuffer
sta wrRequestCount
iny
iny
lda [stream],Y
sbc wrDataBuffer+2
sta wrRequestCount+2
ora wrRequestCount skip the write if there are no
beq fl1 characters
txa
bit #_IOAPPEND if append mode, force to EOF
beq fa4
lda wrRefNum
jsr ~ForceToEOF
fa4 OSwrite wr write the info
bcc fl1
ph4 <stream
jsr ~ioerror
bra rts
fl1 ldy #FILE_flag get flags
lda [stream],Y
fl1a bit #_IOREAD if the file is being read then
beq fl2a
ph4 <stream set the mark to current position
jsl ftell
cmp #-1
bne fl2b
cpx #-1
beq fl2
fl2b sta smPosition
stx smPosition+2
ldy #FILE_file
lda [stream],Y
sta smRefNum
OSSet_Mark sm
fl2 ldy #FILE_flag get flags
lda [stream],Y
fl2a bit #_IORW if the file is open for read/write then
beq fl3
and #$FFFF-_IOWRT-_IOREAD turn off the reading and writing flags
sta [stream],Y
fl3 ph4 <stream prepare file for output
jsl ~InitBuffer
stz err no error found
rts plb
creturn 2:err
wr dc i'5' parameter block for OSwrite
wrRefNum ds 2
wrDataBuffer ds 4
wrRequestCount ds 4
ds 4
dc i'1'
sm dc i'3' parameter block for OSSet_Mark
smRefNum ds 2
dc i'0'
smPosition ds 4
end
****************************************************************
*
* int fgetc(stream)
* FILE *stream;
*
* Read a character from a file
*
* Inputs:
* stream - file to read from
*
* Outputs:
* A - character read; EOF for an error
*
****************************************************************
*
fgetc start
getc entry
c equ 1 character read
p equ 3 work pointer
csubroutine (4:stream),6
phb
phk
plb
ph4 <stream verify that stream exists
jsl ~VerifyStream
bcs lb0
ldy #FILE_flag quit with error if the end of file
lda [stream],Y has been reached or an error has been
and #_IOEOF+_IOERR encountered
beq lb1
lb0 lda #EOF
sta c
brl gc9
lb1 ldy #FILE_pbk if there is a char in the putback buffer
lda [stream],Y
bmi lb2
and #$00FF return it
sta c
ldy #FILE_pbk+2 pop the putback buffer
lda [stream],Y
tax
lda #$FFFF
sta [stream],Y
ldy #FILE_pbk
txa
sta [stream],Y
brl gc9
lb2 ldy #FILE_file branch if this is a disk file
lda [stream],Y
bpl gc2
cmp #stdinID if stream = stdin then
bne gc1
jsl SYSKEYIN get a character
tax branch if not eof
bne st1
lda #_IOEOF set EOF flag
ora >stdin+4+FILE_flag
sta >stdin+4+FILE_flag
jsl SYSKEYIN read the closing cr
lda #EOF return EOF
st1 sta c
brl gc9
gc1 ph4 <stream else flag the error
jsr ~ioerror
lda #EOF
sta c
brl gc10
gc2 ldy #FILE_flag if the file is not read enabled then
lda [stream],Y
bit #_IOREAD
bne gc2a
bit #_IOWRT it is an error if it is write enabled
bne gc1
bra gc2b
gc2a ldy #FILE_cnt we're ready if there are characters
lda [stream],Y left
iny
iny
ora [stream],Y
jne gc8
gc2b ldy #FILE_flag if input is unbuffered then
lda [stream],Y
bit #_IONBF
beq gc3
stz rdDataBuffer+2 set up to read one char to c
tdc
clc
adc #c
sta rdDataBuffer
lla rdRequestCount,1
bra gc4
gc3 ldy #FILE_base else set up to read a buffer full
lda [stream],Y
sta rdDataBuffer
iny
iny
lda [stream],Y
sta rdDataBuffer+2
ldy #FILE_size
lda [stream],Y
sta rdRequestCount
iny
iny
lda [stream],Y
sta rdRequestCount+2
gc4 ldy #FILE_file set the file reference number
lda [stream],Y
sta rdRefNum
OSRead rd read the data
bcc gc7 if there was a read error then
ldy #FILE_flag
cmp #$4C if it was eof then
bne gc5
jsr endreads end reading state
ldy #FILE_flag
lda #_IOEOF set the EOF flag
bra gc6 else
gc5 lda #_IOERR set the error flag
gc6 ora [stream],Y
sta [stream],Y
lda #EOF return EOF
sta c
brl gc10
gc7 ldy #FILE_flag we're done if the read is unbuffered
lda [stream],Y
and #_IONBF
jne gc9
clc set the end of the file buffer
ldy #FILE_end
lda rdDataBuffer
adc rdTransferCount
sta [stream],Y
iny
iny
lda rdDataBuffer+2
adc rdTransferCount+2
sta [stream],Y
jsr resetptr reset the file pointer
ldy #FILE_cnt set the # chars in the buffer
lda rdTransferCount
sta [stream],Y
iny
iny
lda rdTransferCount+2
sta [stream],Y
ldy #FILE_flag note that the file is read enabled
lda [stream],Y
ora #_IOREAD
sta [stream],Y
gc8 ldy #FILE_ptr get the next character
lda [stream],Y
sta p
clc
adc #1
sta [stream],Y
iny
iny
lda [stream],Y
sta p+2
adc #0
sta [stream],Y
lda [p]
and #$00FF
sta c
ldy #FILE_cnt dec the # chars in the buffer
sec
lda [stream],Y
sbc #1
sta [stream],Y
bcs gc8a
iny
iny
lda [stream],Y
dec A
sta [stream],Y
gc8a ldy #FILE_flag if the file is read/write
lda [stream],Y
and #_IORW
beq gc9
ldy #FILE_cnt and the buffer is empty then
lda [stream],Y
iny
iny
ora [stream],Y
bne gc9
jsr endreads end reading state
gc9 lda c if c = \r then
cmp #13
bne gc10
ldy #FILE_flag if this is a text file then
lda [stream],Y
and #_IOTEXT
beq gc10
lda #10
sta c
gc10 plb
creturn 2:c
;
; Local subroutine - end "reading" state to prepare for possible writes
;
endreads ldy #FILE_flag if the file is read/write
lda [stream],Y
bit #_IORW
beq resetptr
and #$FFFF-_IOREAD end reading state
sta [stream],Y
resetptr ldy #FILE_base reset the file pointer (alt entry point)
lda [stream],Y
tax
iny
iny
lda [stream],Y
ldy #FILE_ptr+2
sta [stream],Y
dey
dey
txa
sta [stream],Y
rts
;
; Local data
;
rd dc i'4' parameter block for OSRead
rdRefNum ds 2
rdDataBuffer ds 4
rdRequestCount ds 4
rdTransferCount ds 4
dc i'1' cache priority
end
****************************************************************
*
* char *fgets(s, n, stream)
* char *s;
* int n;
* FILE *stream;
*
* Reads a line into the string s.
*
* Inputs:
* s - location to put the string read.
* n - size of the string
* stream - file to read from
*
* Outputs:
* Returns NULL if an EOF is encountered, placing any
* characters read before the EOF into s. Returns S if
* a line or part of a line is read.
*
****************************************************************
*
fgets start
RETURN equ 13 RETURN key code
LF equ 10 newline
disp equ 1 disp in s
csubroutine (4:s,2:n,4:stream),2
ph4 <stream verify that stream exists
jsl ~VerifyStream
bcs err
stz disp no characters processed so far
dec n leave room for the null terminator
bmi err
bne lb1
short M n = 1: store null terminator only
lda #0
sta [s]
long M
bra rts
lb1 ph4 <stream get a character
jsl fgetc
tax if error or EOF encountered
bpl lb2
lda disp if no characters read, return NULL
beq err
ldy #FILE_flag if error encountered, return NULL
lda [stream],Y
and #_IOERR
beq rts else return s
err stz s
stz s+2
bra rts
lb2 cmp #RETURN if the char is a return, switch to lf
bne lb3
lda #LF
lb3 ldy disp place the char in the string
sta [s],Y (null terminates automatically)
inc disp
cmp #LF quit if it was an LF
beq rts
dec n next character
bne lb1
rts creturn 4:s
end
****************************************************************
*
* int fgetpos(FILE *stream, fpos_t *pos);
*
* Inputs:
* stream - pointer to stream to get position of
* pos - pointer to location to place position
*
* Outputs:
* A - 0 if successful; else -1 if not
* errno - if unsuccessful, errno is set to EIO
*
****************************************************************
*
fgetpos start
err equ 1 error code
csubroutine (4:stream,4:pos),2
ph4 <stream get the position
jsl ftell
cmp #-1 if the position = -1 then
bne lb1
cpx #-1
bne lb1
sta err err = -1
bra lb2 return
lb1 sta [pos] else
txa *pos = position
ldy #2
sta [pos],Y
stz err err = 0
lb2 anop endif
creturn 2:err
end
****************************************************************
*
* FILE *fopen(filename, type)
* char *filename, *type;
*
* Inputs:
* filename - pointer to the file name
* type - pointer to the type string
*
* Outputs:
* X-A - pointer to the file variable; NULL for an error
*
****************************************************************
*
fopen start
BIN equ 6 file type for BIN files
TXT equ 4 file type for TXT files
fileType equ 1 file type letter
fileBuff equ 3 pointer to the file buffer
buffStart equ 7 start of the file buffer
OSname equ 11 pointer to the GS/OS file name
;
; initialization
;
csubroutine (4:filename,4:type),14
phb use our data bank
phk
plb
stz fileBuff no file so far
stz fileBuff+2
lda [type] make sure the file type is in ['a','r','w']
and #$00FF
sta fileType
ldx #$0002
cmp #'a'
beq cn1
cmp #'w'
beq cn1
ldx #$0001
cmp #'r'
beq cn1
lda #EINVAL
sta >errno
brl rt2
;
; create a GS/OS file name
;
cn1 stx opAccess set the access flags
ph4 <filename get the length of the name buffer
jsl ~osname
sta OSname
stx OSname+2
ora OSname+2
jeq rt2
move4 OSname,opName
;
; check for file modifier characters + and b
;
lda #TXT we must open a new file - determine it's
sta crFileType type by looking for the 'b' designator
ldy #1
lda [type],Y
jsr Modifier
bcc cm1
lda [type],Y
jsr Modifier
bcc cm1
lda fileType if mode is 'w' or 'a'
cmp #'r'
beq cm1
lda [type],Y check for 'x' in type string
and #$00FF
cmp #'x'
beq of1
cm1 anop
;
; open the file
;
OSopen op try to open an existing file
bcc of2
lda fileType if the type is 'r', flag an error
cmp #'r'
bne of1
lda #ENOENT
sta >errno
brl rt1
of1 move4 OSname,crPathName create the file
OScreate cr
bcs of1a
OSopen op open the file
bcc of2
of1a cmp #$0047 check for dupPathname error=>file exists
bne errEIO
lda #EEXIST
bra err1
errEIO lda #EIO
err1 sta >errno
brl rt1
of2 lda fileType if the file type is 'w' then
cmp #'w'
bne of3
lda opRefNum reset it
sta efRefNum
OSSet_EOF ef
bra of4
of3 cmp #'a' else if the file type is 'a' then
bne ar1
lda opRefNum
jsr ~ForceToEOF append to it
of4 bcc ar1 allow "not a block device error"
cmp #$0058
bne errEIO flag any other error
;
; allocate and fill in the file record
;
ar1 ph4 #sizeofFILE get space for the file record
jsl malloc
sta fileBuff
stx fileBuff+2
ora fileBuff+2
beq ar2
ph4 #BUFSIZ get space for the file buffer
jsl malloc
sta buffStart
stx buffStart+2
ora buffStart+2
bne ar3
ph4 <fileBuff memory error
jsl free
ar2 lda #ENOMEM
sta >errno
brl rt1
ar3 ldy #2 insert the record right after stderr
lda >stderr+4
sta [fileBuff]
lda >stderr+6
sta [fileBuff],Y
lda fileBuff
sta >stderr+4
lda fileBuff+2
sta >stderr+6
lda buffStart set the start of the buffer
ldy #FILE_base
sta [fileBuff],Y
iny
iny
lda buffStart+2
sta [fileBuff],Y
ldy #FILE_ptr+2
sta [fileBuff],Y
dey
dey
lda buffStart
sta [fileBuff],Y
ldy #FILE_size set the buffer size
lda #BUFSIZ
sta [fileBuff],Y
iny
iny
lda #^BUFSIZ
sta [fileBuff],Y
ldy #1 set the flags
lda [type],Y
and #$00FF
cmp #'+'
beq ar3a
cmp #'b'
bne ar4
iny
lda [type],Y
and #$00FF
cmp #'+'
bne ar4
ar3a lda #_IOFBF+_IORW+_IOMYBUF
bra ar6
ar4 lda fileType
cmp #'r'
beq ar5
lda #_IOFBF+_IOWRT+_IOMYBUF
bra ar6
ar5 lda #_IOFBF+_IOREAD+_IOMYBUF
ar6 ldy #FILE_flag
ldx crFileType
cpx #BIN
beq ar6a
ora #_IOTEXT
ar6a ldx fileType
cpx #'a'
bne ar6b
ora #_IOAPPEND
ar6b sta [fileBuff],Y
ldy #FILE_cnt no chars in buffer
lda #0
sta [fileBuff],Y
iny
iny
sta [fileBuff],Y
ldy #FILE_pbk nothing in the putback buffer
lda #$FFFF
sta [fileBuff],Y
ldy #FILE_pbk+2
sta [fileBuff],Y
ldy #FILE_file set the file ID
lda opRefNum
sta [fileBuff],Y
;
; return the result
;
rt1 ph4 <OSname dispose of the file name buffer
jsl free
rt2 plb restore caller's data bank
creturn 4:fileBuff return
;
; Modifier - local subroutine to check modifier character
;
; Returns: C=0 if no modifier found, else C=1
;
Modifier and #$00FF
beq md3
cmp #'+'
bne md1
lda #$0003
sta opAccess
iny
sec
rts
md1 cmp #'b'
bne md2
lda #BIN
sta crFileType
iny
md2 sec
rts
md3 clc
rts
;
; local data areas
;
op dc i'3' parameter block for OSopen
opRefNum ds 2
opName ds 4
opAccess ds 2
ef dc i'3' parameter block for OSSet_EOF
efRefNum ds 2
dc i'0'
dc i4'0'
cr dc i'7' parameter block for OScreate
crPathName ds 4
dc i'$C3'
crFileType ds 2
dc i4'0'
dc i'1'
dc i4'0'
dc i4'0'
dc r'fgetc'
dc r'fputc'
dc r'fclose'
end
****************************************************************
*
* FILE *freopen(filename, type, stream)
* char *filename, *type;
* FILE *stream;
*
* Inputs:
* filename - pointer to the file name
* type - pointer to the type string
* stream - file buffer to use
*
* Outputs:
* X-A - pointer to the file variable; NULL for an error
*
****************************************************************
*
freopen start
BIN equ 6 file type for BIN files
TXT equ 4 file type for TXT files
fileType equ 1 file type letter
buffStart equ 3 start of the file buffer
OSname equ 7 pointer to the GS/OS file name
fileBuff equ 11 file buffer to return
;
; initialization
;
csubroutine (4:filename,4:type,4:stream),14
phb use our data bank
phk
plb
stz fileBuff the open is not legal, yet
stz fileBuff+2
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs rt2
lda [type] make sure the file type is in ['a','r','w']
and #$00FF
sta fileType
cmp #'a'
beq cl1
cmp #'w'
beq cl1
cmp #'r'
beq cl1
lda #EINVAL
sta >errno
brl rt2
;
; close the old file
;
cl1 ldy #FILE_file branch if the file is not a disk file
lda [stream],Y
bmi cn1
ph4 <stream do any pending I/O
jsl fflush
ldy #FILE_file close the file
lda [stream],Y
sta clRefNum
OSclose cl
ldy #FILE_flag if the buffer was allocated by fopen then
lda [stream],Y
and #_IOMYBUF
beq cn1
ldy #FILE_base+2 dispose of the file buffer
lda [stream],Y
pha
dey
dey
lda [stream],Y
pha
jsl free
;
; create a GS/OS file name
;
cn1 lda filename bail out if filename is NULL
ora filename+2 (reopening same file not supported)
jeq rt2
ph4 <filename get the length of the name buffer
jsl ~osname
sta OSname
stx OSname+2
ora OSname+2
jeq rt2
move4 OSname,opName
;
; open the file
;
lda #TXT we must open a new file - determine it's
sta crFileType type by looking for the 'b' designator
ldy #1
lda [type],Y
and #$00FF
cmp #'+'
bne nl1
iny
lda [type],Y
and #$00FF
nl1 cmp #'b'
bne nl2
lda #BIN
sta crFileType
iny
cpy #2
bne nl2
lda [type],Y
and #$00FF
cmp #'+'
bne nl2
iny
nl2 lda fileType check for 'x' in type string
cmp #'r'
beq nl3
lda [type],Y
and #$00FF
cmp #'x'
beq of1
nl3 OSopen op try to open an existing file
bcc of2
lda fileType if the type is 'r', flag an error
cmp #'r'
bne of1
errEIO ph4 <stream
jsr ~ioerror
brl rt1
of1 move4 OSname,crPathName create the file
OScreate cr
bcc of1a
cmp #$0047 check for dupPathname error=>file exists
bne errEIO
ph4 <stream
jsr ~ioerror
lda #EEXIST
sta >errno
brl rt1
of1a OSopen op open the file
bcs errEIO
of2 lda fileType if the file type is 'w', reset it
cmp #'w'
bne of3
lda opRefNum
sta efRefNum
OSSet_EOF ef
bra of4
of3 cmp #'a' else if the file type is 'a' then
bne ar1
lda opRefNum
jsr ~ForceToEOF append to it
of4 bcc ar1 allow "not a block device error"
cmp #$0058
bne errEIO flag any other error
;
; fill in the file record
;
ar1 ph4 #BUFSIZ get space for the file buffer
jsl malloc
sta buffStart
stx buffStart+2
ora buffStart+2
bne ar3
lda #ENOMEM memory error
sta >errno
brl rt1
ar3 move4 stream,fileBuff set the file buffer address
lda buffStart set the start of the buffer
ldy #FILE_base
sta [fileBuff],Y
iny
iny
lda buffStart+2
sta [fileBuff],Y
ldy #FILE_ptr+2
sta [fileBuff],Y
dey
dey
lda buffStart
sta [fileBuff],Y
ldy #FILE_size set the buffer size
lda #BUFSIZ
sta [fileBuff],Y
iny
iny
lda #^BUFSIZ
sta [fileBuff],Y
ldy #1 set the flags
lda [type],Y
cmp #'+b'
beq ar3a
and #$00FF
cmp #'+'
bne ar4
ar3a lda #_IOFBF+_IORW+_IOMYBUF
bra ar6
ar4 lda fileType
cmp #'r'
beq ar5
lda #_IOFBF+_IOWRT+_IOMYBUF
bra ar6
ar5 lda #_IOFBF+_IOREAD+_IOMYBUF
ar6 ldy #FILE_flag
ldx crFileType
cpx #BIN
beq ar6a
ora #_IOTEXT
ar6a ldx fileType
cpx #'a'
bne ar6b
ora #_IOAPPEND
ar6b sta [fileBuff],Y
ldy #FILE_cnt no chars in buffer
lda #0
sta [fileBuff],Y
iny
iny
sta [fileBuff],Y
ldy #FILE_pbk nothing in the putback buffer
lda #$FFFF
sta [fileBuff],Y
ldy #FILE_pbk+2
sta [fileBuff],Y
ldy #FILE_file set the file ID
lda opRefNum
sta [fileBuff],Y
;
; return the result
;
rt1 ph4 <OSname dispose of the file name buffer
jsl free
rt2 plb restore caller's data bank
creturn 4:fileBuff return
;
; local data areas
;
op dc i'2' parameter block for OSopen
opRefNum ds 2
opName ds 4
ef dc i'3' parameter block for OSSet_EOF
efRefNum ds 2
dc i'0'
dc i4'0'
cr dc i'7' parameter block for OScreate
crPathName ds 4
dc i'$C3'
crFileType ds 2
dc i4'0'
dc i'1'
dc i4'0'
dc i4'0'
cl dc i'1' parameter block for OSclose
clRefNum ds 2
;
; Force inclusion of functions that have weak references elsewhere
;
dc r'fputc,fgetc'
end
****************************************************************
*
* int fprintf(stream, char *format, additional arguments)
*
* Print the format string to standard out.
*
****************************************************************
*
fprintf start
using ~printfCommon
phb use local addressing
phk
plb
plx remove the return address
ply
pla save the stream
sta stream
pla
sta stream+2
phy restore return address/data bank
phx
ldx stream
plb
pha verify that stream exists
phx
jsl ~VerifyStream
bcc lb1
lda #EIO
sta >errno
lda #EOF
bra rts
lb1 lda #put set up output routine
sta >~putchar+4
lda #>put
sta >~putchar+5
tsc find the argument list address
clc
adc #8
sta >args
pea 0
pha
jsl ~printf call the formatter
sec compute the space to pull from the stack
pla
sbc >args
clc
adc #4
sta >args
pla
phb remove the return address
plx
ply
tsc update the stack pointer
clc
adc >args
tcs
phy restore the return address
phx
plb
lda >~numChars return the value
rtl return
put phb remove the char from the stack
phk
plb
plx
pla
ply
pha
phx
plb
lda stream+2 write to a file
pha
lda stream
pha
phy
jsl fputc
rts rtl
args ds 2 original argument address
stream ds 4 stream address
end
****************************************************************
*
* int fputc(c, stream)
* char c;
* FILE *stream;
*
* Write a character to a file
*
* Inputs:
* c - character to write
* stream - file to write to
*
* Outputs:
* A - character written; EOF for an error
*
****************************************************************
*
fputc start
putc entry
c2 equ 5 output char
p equ 1 work pointer
csubroutine (2:c,4:stream),6
ph4 <stream verify that stream exists
jsl ~VerifyStream
bcs lb0
ldy #FILE_flag quit with error if an error has been
lda [stream],Y encountered
and #_IOERR
beq lb1
lb0 lda #EOF
sta c
brl pc8
lb1 ldy #FILE_flag if the file is not prepared for
lda [stream],Y writing then
bit #_IOWRT
bne lb2
bit #_IOREAD if it is being read then
bne pc2 flag the error
ora #_IOWRT set the writing flag
sta [stream],Y
lb2 ldy #FILE_file branch if this is a disk file
lda [stream],Y
bpl pc3
cmp #stdoutID if stream = stdout then
bne pc1
ph2 <c write the character
jsl ~stdout
brl pc8
pc1 cmp #stderrID else if stream = stderr then
bne pc2
lda c (for \n, write \r)
cmp #10
bne pc1a
lda #13
pc1a pha write to error out
jsl SYSCHARERROUT
brl pc8
pc2 ph4 <stream else stream = stdin; flag the error
jsr ~ioerror
lda #EOF
sta c
brl pc8
pc3 lda c set the output char
sta c2
ldy #FILE_flag if this is a text file then
lda [stream],Y
and #_IOTEXT
beq pc3a
lda c if the char is lf then
cmp #10
bne pc3a
lda #13 substitute a cr
sta c2
pc3a ldy #FILE_cnt if the buffer is full then
lda [stream],Y
iny
iny
ora [stream],Y
bne pc4
pc3b ldy #FILE_flag purge it
lda [stream],Y
pha
ph4 <stream
jsl fflush
ldy #FILE_flag
pla
sta [stream],Y
pc4 ldy #FILE_ptr deposit the character in the buffer,
lda [stream],Y incrementing the buffer pointer
sta p
clc
adc #1
sta [stream],Y
iny
iny
lda [stream],Y
sta p+2
adc #0
sta [stream],Y
short M
lda c2
sta [p]
long M
ldy #FILE_cnt dec the buffer counter
sec
lda [stream],Y
sbc #1
sta [stream],Y
bcs pc5
iny
iny
lda [stream],Y
dec A
sta [stream],Y
pc5 ldy #FILE_cnt if the buffer is full
lda [stream],Y
iny
iny
ora [stream],Y
beq pc7
lda c2 or if (c = '\n') and (flag & _IOLBF)
cmp #13
beq pc5a
cmp #10
bne pc6
pc5a ldy #FILE_flag
lda [stream],Y
and #_IOLBF
bne pc7
pc6 ldy #FILE_flag or is flag & _IONBF then
lda [stream],Y
and #_IONBF
beq pc8
pc7 ldy #FILE_flag flush the stream
lda [stream],Y
pha
ph4 <stream
jsl fflush
ldy #FILE_flag
pla
sta [stream],Y
pc8 creturn 2:c
end
****************************************************************
*
* int fputs(s,stream)
* char *s;
*
* Print the string to standard out.
*
****************************************************************
*
fputs start
err equ 1 return code
csubroutine (4:s,4:stream),2
ph4 <stream verify that stream exists
jsl ~VerifyStream
lda #EOF
sta err
bcs lb4
stz err no error so far
bra lb2 skip initial increment
lb1 inc4 s next char
lb2 ph4 <stream push the stream, just in case...
lda [s] exit loop if at end of string
and #$00FF
beq lb3
pha push char to write
jsl fputc write the character
cmp #EOF loop if no error
bne lb1
sta err set the error code
bra lb4
lb3 pla remove stream from the stack
pla
lb4 creturn 2:err
end
****************************************************************
*
* size_t fread(ptr, element_size, count, stream)
* void *ptr;
* size_t element_size;
* size_t count;
* FILE *stream;
*
* Reads element*count bytes to stream, putting the bytes in
* ptr.
*
* Inputs:
* ptr - location to store the bytes read
* element_size - size of each element
* count - number of elements
* stream - file to read from
*
* Outputs:
* Returns the number of elements actually read.
*
****************************************************************
*
fread start
temp equ 1
p equ 5
csubroutine (4:ptr,4:element_size,4:count,4:stream),8
phb
phk
plb
stz rdTransferCount set the # of elements read
stz rdTransferCount+2
stz extraCount no putback characters read yet
stz extraCount+2
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs lb6
ldy #FILE_flag quit if end of file has been reached
lda [stream],Y
bit #_IOEOF
jne lb6
mul4 element_size,count,rdRequestCount set the # of bytes
move4 rdRequestCount,temp save full request count
pb1 lda rdRequestCount quit if the request count is 0
ora rdRequestCount+2
jeq lb4
ldy #FILE_pbk if there is a putback character
lda [stream],Y
bmi lb0
short M read it in
sta [ptr]
long M
inc4 ptr adjust pointer and counts
dec4 rdRequestCount
inc4 extraCount
ldy #FILE_pbk+2 pop the putback buffer
lda [stream],Y
tax
lda #$FFFF
sta [stream],Y
ldy #FILE_pbk
txa
sta [stream],Y
bra pb1 loop to check for another putback chr
lb0 ldy #FILE_file set the file ID number
lda [stream],Y
bpl lb2 branch if it is a file
cmp #stdinID if the file is stdin then
jne lb6
lda >stdin+4+FILE_flag
and #_IOEOF
jne lb6
lb1 jsl SYSKEYIN read the bytes
tax branch if not eof
bne lb1a
lda #_IOEOF set EOF flag
ora >stdin+4+FILE_flag
sta >stdin+4+FILE_flag
jsl SYSKEYIN read the closing cr
brl lb4
lb1a short M set character
sta [ptr]
long M
inc4 rdTransferCount
inc4 ptr
dec4 rdRequestCount
lda rdRequestCount
ora rdRequestCount+2
bne lb1
brl lb4
lb2 sta rdRefNum set the reference number
ldy #FILE_flag if the file is being read then
lda [stream],Y
bit #_IOREAD
beq lb2c
lb2a ldy #FILE_cnt while there is buffered data...
lda [stream],Y
iny
iny
ora [stream],Y
beq lb2c
lda rdRequestCount ...and the request count is not 0
ora rdRequestCount+2
beq lb4
ldy #FILE_ptr get the next character
lda [stream],Y
sta p
clc
adc #1
sta [stream],Y
iny
iny
lda [stream],Y
sta p+2
adc #0
sta [stream],Y
short M
lda [p]
sta [ptr]
long M
ldy #FILE_cnt dec the # chars in the buffer
sec
lda [stream],Y
sbc #1
sta [stream],Y
bcs lb2b
iny
iny
lda [stream],Y
dec A
sta [stream],Y
lb2b inc4 ptr adjust pointer and counts
dec4 rdRequestCount
inc4 extraCount
bra lb2a
lb2c move4 ptr,rdDataBuffer set the start address
OSRead rd read the bytes
bcc lb4
cmp #$4C if the error was $4C then
bne lb3
jsr SetEOF set the EOF flag
bra lb4
lb3 ph4 <stream I/O error
jsr ~ioerror
lb4 add4 rdTransferCount,extraCount
lb5 lda temp if there were too few elements read then
cmp rdTransferCount
bne lb5a
lda temp+2
cmp rdTransferCount+2
beq lb5b
lb5a jsr SetEOF set the EOF flag
! set the # records read
lb5b div4 rdTransferCount,element_size
lb6 move4 rdTransferCount,temp
plb
creturn 4:temp
;
; Local data
;
rd dc i'5' parameter block for OSRead
rdRefNum ds 2
rdDataBuffer ds 4
rdRequestCount ds 4
rdTransferCount ds 4
dc i'1'
extraCount ds 4 # characters read from putback or buffer
;
; Set the EOF flag
;
SetEOF ldy #FILE_flag set the eof flag
lda [stream],Y
ora #_IOEOF
bit #_IORW if file is read/write
beq se1
and #$FFFF-_IOREAD turn off the read flag
se1 sta [stream],Y
ldy #FILE_base reset ptr to prepare for possible writes
lda [stream],Y
tax
iny
iny
lda [stream],Y
ldy #FILE_ptr+2
sta [stream],Y
dey
dey
txa
sta [stream],Y
rts
end
****************************************************************
*
* int fscanf(stream, format, additional arguments)
* char *format;
* FILE *stream;
*
* Read a string from a stream.
*
****************************************************************
*
fscanf start
using ~scanfCommon
phb use local addressing
phk
plb
plx remove the return address
ply
pla save the stream
sta stream
pla
sta stream+2
phy restore return address/data bank
phx
plb
ph4 >stream verify that stream exists
jsl ~VerifyStream
bcc lb1
lda #EOF
rtl
lb1 lda #get set up our routines
sta >~getchar+10
lda #>get
sta >~getchar+11
lda #unget
sta >~putback+12
lda #>unget
sta >~putback+13
lda #~RemoveWordFromStack
sta >~RemoveWord+1
lda #>~RemoveWordFromStack
sta >~RemoveWord+2
lda #0
sta >~isVarArgs
brl ~scanf
get ph4 stream get a character
jsl fgetc
rtl
unget ldx stream+2 put a character back
phx
ldx stream
phx
pha
jsl ungetc
rtl
stream ds 4
end
****************************************************************
*
* int fseek(stream,offset,wherefrom)
* FILE *stream;
* long int offset;
* int wherefrom;
*
* Change the read/write location for the stream.
*
* Inputs:
* stream - file to change
* offset - position to move to
* wherefrom - move relative to this location
*
* Outputs:
* Returns non-zero for error
*
****************************************************************
*
fseek start
__fseek entry
err equ 1 return value
csubroutine (4:stream,4:offset,2:wherefrom),2
phb
phk
plb
lda #-1 assume we will get an error
sta err
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs rts
ph4 <stream purge the file
jsl fflush
ldy #FILE_file set the file reference
lda [stream],Y
jmi lb6
sta gpRefNum
sta spRefNum
lda wherefrom if position is relative to the end then
cmp #SEEK_END
bne lb2
OSGet_EOF gp get the eof
jcs erEIO
add4 offset,gpPosition add it to the offset
bra lb3
lb2 cmp #SEEK_CUR else if relative to current position then
bne lb3
ph4 <stream get the current position
jsl ftell
clc add it to the offset
adc offset
sta offset
txa
adc offset+2
sta offset+2
lb3 OSGet_EOF gp get the end of the file
jcs erEIO
lda offset+2 if the offset is >= EOF then
cmp gpPosition+2
bne lb4
lda offset
cmp gpPosition
lb4 ble lb5
move4 offset,spPosition extend the file
OSSet_EOF sp
bcs erEIO
lb5 move4 offset,spPosition
OSSet_Mark sp
bcs erEIO
lb6 ldy #FILE_flag clear the EOF flag
lda [stream],Y
and #$FFFF-_IOEOF
bit #_IORW if file is open for reading and writing
beq lb6a
and #$FFFF-_IOREAD-_IOWRT clear the READ and WRITE flags
lb6a sta [stream],Y
ldy #FILE_cnt clear the character count
lda #0
sta [stream],Y
iny
iny
sta [stream],Y
ldy #FILE_base+2 reset the file pointer
lda [stream],Y
tax
dey
dey
lda [stream],Y
ldy #FILE_ptr
sta [stream],Y
iny
iny
txa
sta [stream],Y
ldy #FILE_pbk nothing in the putback buffer
lda #$FFFF
sta [stream],Y
ldy #FILE_pbk+2
sta [stream],Y
stz err
rts plb
creturn 2:err
erEIO ph4 <stream flag an IO error
jsr ~ioerror
bra rts
gp dc i'2' parameter block for OSGet_EOF
gpRefNum ds 2
gpPosition ds 4
sp dc i'3' parameter block for OSSet_EOF
spRefNum ds 2 and OSSet_Mark
dc i'0'
spPosition ds 4
end
****************************************************************
*
* int fsetpos(FILE *stream, fpos_t *pos);
*
* Inputs:
* stream - pointer to stream to set position of
* pos - pointer to location to set position
*
* Outputs:
* A - 0 if successful; else -1 if not
* errno - if unsuccessful, errno is set to EIO
*
****************************************************************
*
fsetpos start
err equ 1 error code
csubroutine (4:stream,4:pos),2
ph2 #SEEK_SET
ldy #2
lda [pos],Y
pha
lda [pos]
pha
ph4 <stream
jsl fseek
sta err
creturn 2:err
end
****************************************************************
*
* long int ftell(stream)
* FILE *stream;
*
* Find the number of characters already passed in the file.
*
* Inputs:
* stream - strem to find the location in
*
* Outputs:
* Returns the position, or -1L for an error.
*
****************************************************************
*
ftell start
pos equ 1 position in the file
csubroutine (4:stream),4
phb
phk
plb
lda #-1 assume an error
sta pos
sta pos+2
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs rts
ldy #FILE_flag if the file is being written then
lda [stream],Y
bit #_IOWRT
beq lb0
ph4 <stream do any pending writes
jsl fflush
tax
bne rts
lb0 ldy #FILE_file get the file's mark
lda [stream],Y
sta gmRefNum
OSGet_Mark gm
bcc lb1
lda #EIO
sta >errno
bra rts
lb1 move4 gmPosition,pos set the position
ldy #FILE_flag if the file is being read then
lda [stream],Y
bit #_IOREAD
beq rts
sec subtract off characters left to be
ldy #FILE_cnt read
lda pos
sbc [stream],Y
sta pos
iny
iny
lda pos+2
sbc [stream],Y
sta pos+2
ldy #FILE_pbk dec pos by 1 for each char in the
lda [stream],Y putback buffer then
bmi rts
dec4 pos
ldy #FILE_pbk+2
lda [stream],Y
bmi rts
dec4 pos
rts plb
creturn 4:pos
gm dc i'2' parameter block for OSGetMark
gmRefNum ds 2
gmPosition ds 4
end
****************************************************************
*
* size_t fwrite(ptr, element_size, count, stream)
* void *ptr;
* size_t element_size;
* size_t count;
* FILE *stream;
*
* Writes element*count bytes to stream, taking the bytes from
* ptr.
*
* Inputs:
* ptr - pointer to the bytes to write
* element_size - size of each element
* count - number of elements
* stream - file to write to
*
* Outputs:
* Returns the number of elements actually written.
*
****************************************************************
*
fwrite start
csubroutine (4:ptr,4:element_size,4:count,4:stream),0
phb
phk
plb
stz wrTransferCount set the # of elements written
stz wrTransferCount+2
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs lb6
mul4 element_size,count,wrRequestCount set the # of bytes
lda wrRequestCount quit if the request count is 0
ora wrRequestCount+2
jeq lb6
ldy #FILE_file set the file ID number
lda [stream],Y
bpl lb4 branch if it is a file
cmp #stdoutID if the file is stdout then
bne lb2
lb1 lda [ptr] write the bytes
pha
jsl ~stdout
inc4 ptr
dec4 wrRequestCount
lda wrRequestCount
ora wrRequestCount+2
bne lb1
move4 count,wrTransferCount set the # of elements written
brl lb6
lb2 cmp #stderrID if the file is stderr then
jne lb6
lb3 lda [ptr] write the bytes
pha
jsl SYSCHARERROUT
inc4 ptr
dec4 wrRequestCount
lda wrRequestCount
ora wrRequestCount+2
bne lb3
move4 count,wrTransferCount set the # of elements written
bra lb6
lb4 sta wrRefNum set the reference number
ph4 <stream purge the file
jsl fflush
move4 ptr,wrDataBuffer set the start address
ldy #FILE_flag if append mode, force to EOF
lda [stream],Y
bit #_IOAPPEND
beq lb4a
lda wrRefNum
jsr ~ForceToEOF
lb4a OSWrite wr write the bytes
bcc lb5
ph4 <stream I/O error
jsr ~ioerror
! set the # records written
lb5 div4 wrTransferCount,element_size,count
lb6 plb
creturn 4:count return
wr dc i'5' parameter block for OSWrite
wrRefNum ds 2
wrDataBuffer ds 4
wrRequestCount ds 4
wrTransferCount ds 4
dc i'1'
end
****************************************************************
*
* int getchar()
*
* Read a character from standard in. No errors are possible.
*
* The character read is returned in A. The null character
* is mapped into EOF.
*
****************************************************************
*
getchar start
;
; Determine which method to use
;
lda >stdin use fgetc if stdin has changed
cmp #stdin+4
bne fl1
lda >stdin+2
cmp #^stdin+4
bne fl1
lda >stdin+4+FILE_file use fgetc if stdio has a bogus file ID
cmp #stdinID
bne fl1
;
; get the char from the keyboard
;
lda >stdin+4+FILE_pbk if there is a char in the putback
bmi lb1 buffer then
and #$00FF save it in X
tax
lda >stdin+4+FILE_pbk+2 pop the buffer
sta >stdin+4+FILE_pbk
lda #$FFFF
sta >stdin+4+FILE_pbk+2
txa restore the char
bra lb2
lb1 jsl SYSKEYIN else get a char from the keyboard
tax branch if not eof
bne lb2
lda #_IOEOF set EOF flag
ora >stdin+4+FILE_flag
sta >stdin+4+FILE_flag
jsl SYSKEYIN read the closing cr
lda #EOF return EOF
lb2 cmp #13 if the char is \r then
bne lb3
lda #10 return \n
lb3 rtl
;
; Call fgetc
;
fl1 ph4 >stdin
dc i1'$22',s3'fgetc' jsl fgetc
rtl
end
****************************************************************
*
* char *gets(s)
* char s;
*
* Read a line from standard in.
*
* Inputs:
* s - string to read to.
*
* Outputs:
* Returns a pointer to the string
*
****************************************************************
*
gets start
LF equ 10 \n key code
disp equ 1 disp in s
csubroutine (4:s),2
stz disp no characters processed so far
lb1 jsl getchar get a character
tax if error or EOF encountered
bpl lb2
lda disp if no characters read, return NULL
beq err
ph4 >stdin if error encountered, return NULL
jsl ferror
tax
beq rts else return s
err stz s
stz s+2
bra rts
lb2 cmp #LF quit if it was a \n
beq lb3
ldy disp place the char in the string
sta [s],Y
inc disp
bra lb1 next character
lb3 ldy disp null terminate
short M
lda #0
sta [s],Y
long M
rts creturn 4:s
end
****************************************************************
*
* void perror(s);
* char *s;
*
* Prints the string s and the error in errno to standard out.
*
****************************************************************
*
perror start
maxErr equ EILSEQ max error in sys_errlist
s equ 4 string address
tsc set up DP addressing
phd
tcd
lda s skip prefix string if it is NULL/empty
ora s+2
beq lb0
lda [s]
and #$00FF
beq lb0
ph4 >stderr write the error string
ph4 <s
jsl fputs
ph4 >stderr write ': '
pea ':'
jsl fputc
ph4 >stderr
pea ' '
jsl fputc
lb0 ph4 >stderr write the error message
lda >errno
cmp #maxErr+1
blt lb1
lda #0
lb1 asl A
asl A
tax
lda >sys_errlist+2,X
pha
lda >sys_errlist,X
pha
jsl fputs
ph4 >stderr write lf
pea 10
jsl fputc
pld remove parm and return
lda 2,S
sta 6,S
pla
sta 3,S
pla
rtl
end
****************************************************************
*
* int printf(format, additional arguments)
* char *format;
*
* Print the format string to standard out.
*
****************************************************************
*
printf start
using ~printfCommon
lda #putchar
sta >~putchar+4
lda #>putchar
sta >~putchar+5
tsc find the argument list address
clc
adc #8
sta >args
pea 0
pha
jsl ~printf call the formatter
sec compute the space to pull from the stack
pla
sbc >args
clc
adc #4
sta >args
pla
phb remove the return address
plx
ply
tsc update the stack pointer
clc
adc >args
tcs
phy restore the return address
phx
plb
lda >~numChars return the value
rtl return
args ds 2 original argument address
end
****************************************************************
*
* int putchar(c)
* char c;
*
* Print the character to standard out. The character is
* returned. No errors are possible.
*
* The character \n is automatically followed by a $0D, which
* causes the IIGS to respond the way \n works on other machines.
*
****************************************************************
*
putchar start
using ~printfCommon
_n equ 10 linefeed character
_r equ 13 RETURN key code
;
; Determine which method to use
;
lda >stdout use fgetc if stdin has changed
cmp #stdout+4
bne fl1
lda >stdout+1
cmp #>stdout+4
bne fl1
lda >stdout+4+FILE_file use fgetc if stdio has a bogus file ID
cmp #stdoutID
bne fl1
;
; Write to the CRT
;
~stdout entry
php remove the parameter from the stack
plx
ply
pla
phy
phx
plp
pha save the parameter
cmp #_n if this is a line feed, do a
bne lb1 carriage return, instead.
lda #_r
lb1 pha write the character
jsl SYSCHAROUT
pla return the input character
rtl
;
; Use fputc
;
fl1 ph4 >stdout
lda 8,S
pha
dc i1'$22' jsl fputc
dc s3'fputc'
phb
plx
ply
pla
phy
phx
plb
rtl
end
****************************************************************
*
* int puts(s)
* char *s;
*
* Print the string to standard out. A zero is returned; no
* error is possible.
*
****************************************************************
*
puts start
LINEFEED equ 10 linefeed character
err equ 1 erro code
csubroutine (4:s),2
stz err no error
lb1 lda [s] print the string
and #$00FF
beq lb2
pha
jsl putchar
inc4 s
bra lb1
lb2 pea LINEFEED print the linefeed
jsl putchar
creturn 2:err
end
****************************************************************
*
* int remove(filename)
* char *filename;
*
* Inputs:
* filename - name of the file to delete
*
* Outputs:
* Returns zero if successful, GS/OS error code if not.
*
****************************************************************
*
remove start
err equ 1 return code
csubroutine (4:filename),2
phb
phk
plb
ph4 <filename convert to a GS/OS file name
jsl ~osname
sta dsPathName
stx dsPathName+2
ora dsPathName+2
bne lb1
lda #$FFFF
sta err
bra lb2
lb1 OSDestroy ds delete the file
sta err set the error code
bcc lb1a
lda #ENOENT
sta >errno
lb1a ph4 dsPathName dispose of the name buffer
jsl free
lb2 plb
creturn 2:err
ds dc i'1' parameter block for OSDestroy
dsPathName ds 4
end
****************************************************************
*
* int rename(oldname,newname)
* char *filename;
*
* Inputs:
* filename - name of the file to delete
*
* Outputs:
* Returns zero if successful, GS/OS error code if not.
*
****************************************************************
*
rename start
err equ 1 return code
csubroutine (4:oldname,4:newname),2
phb
phk
plb
ph4 <oldname convert oldname to a GS/OS file name
jsl ~osname
sta cpPathName
stx cpPathName+2
ora cpPathName+2
bne lb1
lda #$FFFF
sta err
bra lb4
lb1 ph4 <newname convert newname to a GS/OS file name
jsl ~osname
sta cpNewPathName
stx cpNewPathName+2
ora cpNewPathName+2
bne lb2
lda #$FFFF
sta err
bra lb3
lb2 OSChange_Path cp rename the file
sta err set the error code
ph4 cpNewPathName dispose of the new name buffer
jsl free
lb3 ph4 cpPathName dispose of the old name buffer
jsl free
lb4 plb
creturn 2:err
cp dc i'2' parameter block for OSChange_Path
cpPathName ds 4
cpNewPathName ds 4
end
****************************************************************
*
* void rewind(stream)
* FILE *stream;
*
* Rewind the read/write location for the stream.
*
* Inputs:
* stream - file to change
*
****************************************************************
*
rewind start
csubroutine (4:stream),0
ph4 <stream verify that stream exists
jsl ~VerifyStream
bcs ret
ph2 #SEEK_SET
ph4 #0
ph4 <stream
jsl __fseek
ldy #FILE_flag clear the error flag
lda [stream],Y
and #$FFFF-_IOERR
sta [stream],Y
ret creturn
end
****************************************************************
*
* int scanf(format, additional arguments)
* char *format;
*
* Read a string from standard in.
*
****************************************************************
*
scanf start
using ~scanfCommon
lda #getchar
sta >~getchar+10
lda #>getchar
sta >~getchar+11
lda #unget
sta >~putback+12
lda #>unget
sta >~putback+13
lda #~RemoveWordFromStack
sta >~RemoveWord+1
lda #>~RemoveWordFromStack
sta >~RemoveWord+2
lda #0
sta >~isVarArgs
brl ~scanf
unget tax
lda >stdin+2
pha
lda >stdin
pha
phx
jsl ungetc
rtl
end
****************************************************************
*
* int setbuf (FILE *stream, char *)
*
* Set the buffer type and size.
*
* Inputs:
* stream - file to set the buffer for
* buf - buffer to use, or NULL for automatic buffer
*
* Outputs:
* Returns zero if successful, -1 for an error
*
****************************************************************
*
setbuf start
err equ 1 return code
csubroutine (4:stream,4:buf),2
lda buf
ora buf+2
bne lb1
ph4 #0
ph2 #_IONBF
bra lb2
lb1 ph4 #BUFSIZ
ph2 #_IOFBF
lb2 ph4 <buf
ph4 <stream
jsl __setvbuf
sta err
creturn 2:err
end
****************************************************************
*
* int setvbuf(stream,buf,type,size)
* FILE *stream;
* char *buf;
* int type,size;
*
* Set the buffer type and size.
*
* Inputs:
* stream - file to set the buffer for
* buf - buffer to use, or NULL for automatic buffer
* type - buffer type; _IOFBF, _IOLBF or _IONBF
* size - size of the buffer
*
* Outputs:
* Returns zero if successful, -1 for an error
*
*********************************