1
0
mirror of https://github.com/RevCurtisP/C02.git synced 2024-11-29 16:51:10 +00:00
C02/include/cbm/fileio.a02

695 lines
24 KiB
Plaintext
Raw Normal View History

;C02 Module file.h02 Assembly Language Routines
;for all Commodore 8 bit machines
; Requires error code definitions from error.a02,
; External routines FSFLFA, RESRXY, STRLEN
; and the following RAM locations definitions
; external zero page byte pairs SRCLO,SRCHI and DSTLO,DSTHI
; and external bytes TEMP1, TEMP2
; NOTE: Reading from CASSETTE will not produce an EOF
;Kernal Device Numbers
KEYBRD EQU 0
CASST1 EQU 1
MODEM1 EQU 2
SCREEN EQU 3
PRNTR1 EQU 4
PRNTR2 EQU 5
PRNTR3 EQU 6
PRNTR4 EQU 7
DRIVE1 EQU 8
DRIVE2 EQU 9
DRIVE3 EQU 10
DRIVE4 EQU 11
DRIVE5 EQU 12
DRIVE6 EQU 13
DRIVE7 EQU 14
DRIVE8 EQU 15
;Disk Numbers (Within Drive)
DISK0 EQU $00
DISK1 EQU $40
;File Open Modes
MWRITE EQU $80
MREAD EQU $00
;File Load Modes
MABSLT EQU $80 ;Absolute (Use File Header Address)
MRELCT EQU $00 ;Relocate (Use Specified Address)
;File Types
FTASC EQU $00 ;ASCII Text (SEQ)
FTBAS EQU $10 ;Basic Program (PRG)
FTBIN EQU $20 ;Binary File (PRG)
FTUSR EQU $30 ;User-Defined (USR)
;Zero Page System Variables (Names Subject to Change)
FSIOST EQU $90 ;Kernal I/O Status Word
FSNOFL EQU $98 ;Number of Open I/O Files
FSRCVB EQU $A4 ;Serial Bus Received Byte
FSSVLO EQU $AC ;Save Address (Low Byte)
FSSVHI EQU $AD ;Save Address (High Byte)
FSFNLN EQU $B7 ;Length of Current Filename
FSLFNO EQU $B8 ;Current Logical File Number
FSSADR EQU $B9 ;Current Secondary Address
FSDVNO EQU $BA ;Current Device Number
FSFNLO EQU $BB ;Pointer: Current Filename (LSB)
FSFNHI EQU $BC ;Pointer: Current Filename (MSB)
;IEC STATUS Bit Masks
FSSTTO EQU $03 ;Disk - Read/Write Timeout $21 //Error - Operation Timed Out
FSSTSB EQU $04 ;Tape - Short Block
FSSTLB EQU $08 ;Tape - Long Block
FSSTRE EQU $10 ;Tape - Read Error
FSSTCE EQU $20 ;Both - Checksum Error
FSSTEF EQU $40 ;Both - End of File
FSSTNP EQU $80 ;Disk - Device Not Present
FSSTET EQU $80 ;Tape - End of Tape
;RS-232 Status Bit Masks
;$01 - Parity Error
;$02 - Framing Error
;$04 - Receive Overrun
;$10 - CTS Missing
;$40 - DSR Missing
;$80 - BREAK Detected
;fsioet[15] - I/O Error Table by Channel Number
FSIOET EQU $0140 ;Bottom of BASIC Stack Area
;fscntr - File Counter
FSCNTR EQU $0150 ;Byte Following Error Table
;fsbufr - Buffer for String Concatenation
FSBUFR EQU $0200 ;BASIC Line Editor Input Buffer
;Error Code Conversion Tables
;FSCSST DC FSSSPE,FSSSFE,FSSSRO,FSSSCM,FSSSDM,FSSSBD
FSCSTT DC FSSTTO,FSSTSB,FSSTLB,FSSTRE,FSSTCE ;STATUS to Error Code
;String Constants
FSCMDI DC "I",0 ;Command - Initialize Drive
FSWSFX DC ",S,W",0 ;Filename Suffix for Write
;fsbcmd(command) - Build Disk Command String
;Args: A = Disk Command (Single Letter Abbreviation)
;Uses: FSBUFR = Command String
; TEMP2 = Mode/Option Byte
FSBCMD: STA FSBUFR ;Store Command in FSBUFR[0]
JSR FSDSKN ;Get Disk Number
STA FSBUFR+1 ;and Store in FSBUFR[1]
LDA #58 ;Load ':'
STA FSBUFR+2 ;and Store in FSBUFR[2]
LDA #0 ;Load String Terminator
STA FSBUFR+3 ;and Store in FSBUFR[3]
RTS
;fsdskn() - Get Disk Number
;Uses: TEMP2 = Mode/Option Byte
;Returns: A = Disk Number "0" or "1"
FSDSKN: LDA TEMP2 ;Get Option Byte
AND #$01 ;Isolate Drive Number
ORA #$30 ;Convert to ASCII
RTS
;fschan(chan) - Find Channel Info
;Args: A = Logical File Number
;Uses: $0259 = LAT File number table
; $0263 = FAT Device number table
; $026D = SAT Secondary address table
;Returns: A = Device Number
; Y = Secondary Address
; X = Index into File Tables
; $FF if Channel Not Open
FSCHAN: JSR FSFLFA ;Find File Table Index
BMI FSCHAX ;If Found
LDA $026D,X ;Load Secondary Address into Y
TAY
LDA $0263,X ;Load Device Number into X
FSCHAX: RTS
;fsinit(device) - Initialize Disk Drive
;Args: A = Device Number
; Y,X = Pointer to Command String
;Uses: FSBUFR - String Concatenation Buffer
;Sets: TEMP2 = Number of Bytes Read from Drive
;Returns: A = Drive Status Code
; Y = Kernal or I/O Error
FSINIT: LDX #<FSCMDI ;Load Pointer to Command String
LDY #>FSCMDI ;and Fall Trhough to FSDCMD
;fsdcmd(device) - Send Command to Drive
;Args: A = Device Number
; Y,X = Pointer to Command String
;Uses: FSBUFR - String Concatenation Buffer
;Sets: TEMP2 = Number of Bytes Read from Drive
;Returns: A = Drive Status Code
; Y = Kernal or I/O Error
FSDCMD: JSR SETSRC ;Save Command String Pointer
JSR FSOCMD ;Open Command Channel
BEQ FSCHAX ;If Not Open, Return
ORA #$80 ;Set flag to Emit C/R
JSR FPUTSA ;Call fputs() - Alternate Entry Point
BCC FSDSTR ;If No Error, Get Disk Status
RTS ;Else Return
;fscste(status) - Convert STATUS byte into Error Code
FSCSTE: LDY #5 ;Set Index to Table Size
FSCSTL: AND FSCSTT-1,Y ;Mask Bits Against Table Entry
BNE FSCSTS ;If Bits Not Set
DEY ; Decrement Index
BNE FSCSTL ; and Loop if Not Zero
FSCSTS: TYA ;Copy Index to Accumulator
BEQ FSCSTX ;If Not Zero
ORA #$10 ; Convert from $0x to $1x
FSCSTX: RTS
;fscdst(status) - Convert Drive Status
;Args: A = Drive Status Code
;Returns: Y = Converted Error Code
;fsdsts(device) - Get Drive Status
;Args: A = Device Number
;Uses: FSBUFR - String Concatenation Buffer
;Returns: A = Drive Status Code
; Y = Kernal or I/O Error
FSDSTS: JSR FSOCMD ;Open Command Channel
BCS FSCHAX ;If Error, Return
FSDSTR: JSR FSRCMD ;Read Command Channel
BEQ FSDSTX ;If Bytes Read
JSR FSGBFR ; Get Buffer Address
JSR ATOC ; Convert Error# to Byte
LDY #0 ; Set Error to 0
FSDSTX: RTS ;and Return
;fscbfr() - Copy Source String to String Buffer
;Args: C = Mode
;Uses: SRCLO,SRCHI = Pointer to Source String
FSCBFR: JSR FSGBFR ;Get String Buffer Address
JSR SETDST ;Set Buffer as Destination
LDY #0 ;Initialize Index
BCS FSCBFS ;If Carry Clear
JMP STRCPL ; Copy String
FSCBFS: JMP STRCAL ;Else Concatenate String
;fsgbfr() - Get String Buffer Address
FSGBFR: LDX #<FSBUFR ;Load LSB into X
LDY #>FSBUFR ;Load MSB into Y
RTS
;fsocmd(device) - Open Command Channel
;Args: A = Device Number
;Returns: A = Logical File Number
FSOCMD: ORA #$10 ;Set LFN to Device# + 16
JSR FSFLFA ;Find File Table Index
BPL FSCHAX ;If Already Open, Return
TAX ;Copy Device Number to X
FSOCMX: LDA #0 ;Set Filename to None
JSR $FFBD ;Call Kernal SETNAM Routine
FSET15: LDA #15 ;Set LFN to 15
BNE FSOPEY ;Copy to SA and Open Channel
;fsname(&s) - Set Filename for Load, Save
;Args: Y,X = Pointer to string containing filename
FSNAME: JSR STRLEN ;Get Length of String
JSR GETSRC ;Retrieve String Address
JMP $FFBD ;Execute Kernal SETNAM Routine
;fsonam(&s) - Set Filename for Open
;Args: Y,X = Pointer to string containing filename
FSONAM: LDA TEMP1 ;Get Device Number
AND TEMP2 ;AND with Mode/Option
AND #$08 ;Check Disk + Write Bit
BEQ FSNAME ;Execute FSNAME/FSWNAM
;fswnam(&s) - Set Filename for Write to Disk
;Args: Y,X = Pointer to string containing filename
FSWNAM: JSR SETSRC ;Set Filename as Source
CLC ;Set Flag to Copy
JSR FSCBFR ;and Copy to String Buffer
LDX #<FSWSFX
LDY #>FSWSFX
JSR STRCAT ;Append Write Suffix
JSR FSGBFR ;Get String Buffer Address
JMP $FFBD ;Execute Kernal SETNAM Routine
;fsldsv() - Setup for Load and Save
;Args: A = Logical File Number
; Y = Mode
; X = Device Number
;Returns: Y,X = Destination Address (DSTHI,DSTLO)
FSLDSV: PHA ;Save LFN
TYA ;Copy Mode to Accumulator
LSR ;Rotate Bit 3 to Bit 1
LSR
LSR
TAY ;Use as Secondary Address
PLA ;Restore LFN
JSR $FFBA ;Call Kernal SETLFS Routine
JMP GETDST ;Get Load/End Address into X,Y
;fsopts() - Parse Load/Save/Open Options Byte
;Args: A = Combined Options Byte
; Bits 0-3 = Device Number
; Bits 4-7 = Mode/Option
;Sets: TEMP0 = Combined Option
; TEMP1 = Device
; TEMP2 = Mode/Option
; Bit 1 = Disk Number
; Bits 1-2 = File Type
; Bit 3 = Mode (0=Read/1=Write)
;Returns: A = Mode/Option
FSOPTS: STA TEMP0 ;Save Argument
AND #$0F ;Isolate Device Number
STA TEMP1 ;and Save it
LDA TEMP0 ;Restore Argument
LSR ;Shift to Low Nybble
LSR
LSR
LSR
STA TEMP2 ;and Save it
RTS
;fsopen(chan, mode, device) - Open Channel to Device
;Requires prior call to FSNAME
;Args: A = Logical File Number
; Y = Mode: 0=Read, !0= Write
; X = Device 0=Keyboard, 1=Cassette, 2=RS232, 3=Screen
; 4-7=Printers, 8-15=Disks, 31=All Devices
;Returns: A,X = Channel Number (0=Error)
; Y = Error Number (0=None)
FSOPEN: CPX #1
BNE FSOPEY ;If Device is Cassette
CPY #0
BEQ FSOPEZ ; If Mode is Not Zero
LDY #2 ; Set Secondary Address to 2
BNE FSOPEZ ;Else
FSOPEY: TAY ; Copy LFN to Secondary Address
FSOPEZ: JSR $FFBA ;Call Kernal SETLFS Routine
JSR $FFC0 ;Call Kernal OPEN Routine
BCS FSERRV ;If Error Return A=0, Y=Error#
BCC FSOPED ;** Skip Drive Check for now; **
LDA FSDVNO ;Get Current Device Number
CMP #8 ;Check Device Number
BCC FSOPED ;If Disk Drive
JSR FSDSTS ; Get Drive Status
BCS FSERRV ; If Error Return A=0, Y=Error#
FSOPED: LDA #0 ;Set Error Code to 0
STA FSIOET ;Clear General Error Entry
LDX FSLFNO ;Get LFN
STA FSIOET,X ;Clear Error Table Entry
TAY ;Clear Error Code
TXA ;Return LFN
RTS
;fsload(chan, mode, device) - Load File from Device
;Requires: DSTLO,DSTHI = Load Address
; Prior call to FSNAME
;Args: A = Logical File Number
; Y = Mode: 0=Read, !0= Write
; X = Device 1=Cassette, 8-15=Disks
;Returns: A = Error Number (0=None)
; Y,X = Address at Last Byte Loaded
FSLOAD: JSR FSLDSV ;Set up for Load/Save
LDA TEMP3 ;Get Load/Verify Flag
FSLOAK: JSR $FFD5 ;Call Kernal LOAD Routine
BCC FSZERO ;If No Error, Return 0
RTS
;fssave(chan, mode, device) - Save File to Device
;Requires: DSTLO,DSTHI = Load Address
; Prior call to FSNAME
;Args: A = Logical File Number
; Y = Mode: 0=Read, !0= Write
; X = Device 1=Cassette, 8-15=Disks
;Returns: A = Error Number (0=None)
; Y,X = Address at Last Byte Loaded
FSSAVE: JSR FSLDSV ;Set up for Load/Save
LDA #FSSVLO ;Load Start Address Pointer
JSR $FFD8 ;Call Kernal SAVE Routine
BCC FSZERO ;If No Error, Return 0
RTS
;fsrdst() - Read I/O Status Byte
;Replaces Kernal READST Routine, fixing RS-232 bug,
;bypassing Kernal messages, and preserving Accumulator
;Affects: X
;Returns: Carry Set if Error
; Overflow Set if EOF
; Y = I/O Status
; Bit Cassette Read Serial Bus I/O Tape Load/Verify
; $01 Write Timeout
; $02 Read Timeout
; $04 Short Block Short Block
; $08 Long Block Long Block
; $10 Read Error Any Mismatch
; $20 Checksum Err Checksum Err
; $40 End of File EOI Line
; $80 End of Tape Device Not Present End of Tape
FSRDST: TAX ;Save Accumulator
CLV ;Clear Overflow Flag
LDY $BA ;Get Current Device Number
CPY #$02 ;Check Device Number
BNE FSRDSS ;If Serial Port
LDA $0297 ; Read RS-232 Status Word
LDY #0 ; then
STY $0297 ; Clear It
BEQ FSRDSX ;Else
FSRDSS: LDA FSIOST ; Load I/O Status Byte
BIT FSIOST ; EOF Bit into Overflow Flag
BEQ FSRDSX ; If Error
BVS FSRDSX ; And Not EOF
JSR FSCSTE ; Convert ST into Error
FSRDSX: LDY FSLFNO ;Get Logical File Number
STA FSIOET,Y ;Save Error in Table
BVC FSRDSY ;If EOF
AND #$BF ; Clear EOF Flag
FSRDSY: CMP #1 ;Set Carry if Error
TAY ;Copy Error Code to Y
TXA ;Restore Accumulator
RTS
;fsunch() - Find Unused Channel Number
;Affects: X,Y
;Returns: A = Channel Number
; 0=No Channel Available
FSUNCH: LDY #2 ;Start with Channel 2
FSUNCL: TYA ;Copy Channel to Accumulator`
JSR FSFLFA ;Find File Table Index
BMI FSUNCX ;If Channel Allocated
INY ; Increment Channel
CPY #15 ; If less than 15
BCC FSUNCL ; Loop
LDY #0 ; Else Return 0
FSUNCX: TYA ;Copy Channel to Set Flags
RTS
;fscdrv() - Check if Device is Disk Drive
;Uses: TEMP1 = Device Number
;Returns: A = Device Number
; 0 if Not a Disk Drive
; Y = Error Code
; 0 = None
FSCDRV: LDA TEMP1 ;Get Device Number
FSCDRA: CMP #8 ;If >=8
BCS FSRTS ; Return
;fserr7() - Return General Error 7
FSERR7: LDA #7 ;Set Error to Illegal Device Number
DC $2C ;BIT - Skip Next Instruction
;fserr2() - Return General Error 2
FSERR2: LDA #2 ;Set Error to 2
;fserrv(error) - Write General Error Entry
FSERRV: LDX #0 ;Set No Logical File Number
DC $2C ;BIT - Skip Next Instruction
;fserrw() - Write Error To Table and Return in Y
FSERRW: LDX FSLFNO ;Get Logical File Number
FSERRX: STA FSIOET,X ;Save Error To Table
FSERRY: TAY ;Move Error Code to Y
FSZERO: LDA #0 ;Return 0
FSRTS: RTS
;fload(args, &name) - Load File
;Args: A = Mode + Device #
; Y,X = Pointer to File Name
;Returns: A = Error Number (0=None)
; Y,X = Address at Last Byte Loaded
FLOAD: JSR FSOPTS ;Parse Options Argument
LDA #0 ;Set Flag to LOAD
FLOADA: STA TEMP3 ;and Save It
JSR FSNAME ;Set Filename for Open
JSR FSUNCH ;Find Unused Channel Number
BEQ FSERR2 ;If None Available, Return Error
JSR RESRXY ;Load Device, Mode into X, Y
JMP FSLOAD ;and Load File
;fsave(args, &name) - Save File
;Requires: SRCLO,SRCHI = Start Address
; DSTLO,DSTHI = End Address
;Args: A = Mode + Device #
; Y,X = Pointer to File Name
;Returns: A = Error Number (0=None)
; Y,X = Address at Last Byte Loaded
FSAVE: JSR SAVREG ;Save Arguments
JSR GETSRC ;Get Start Address
STX FSSVLO ;and Store It
STY FSSVHI
JSR RESREG ;Restore Arguments
JSR FSOPTS ;Parse Options Argument
JSR FSNAME ;Set Filename for Open
JSR FSUNCH ;Find Unused Channel Number
BEQ FSERR2 ;If None Available, Return 0
JSR RESRXY ;Load Device, Mode into X, Y
JMP FSSAVE ;and Load File
;fvrfy(args, &name) - Verify File
;Args: A = Mode + Device #
; Y,X = Pointer to File Name
;Returns: A = Error Number (0=None)
; Y,X = Address at Last Byte Loaded
FVRFY: JSR FSOPTS ;Parse Options Argument
LDA #1 ;Set Flag to VERIFY
BNE FLOADA ;Execute FLOAD Alternate Entry Point
;fopen(args, &name) - Open File
;Args: A = Mode + Device #
; Y,X = Pointer to File Name
;Returns: A = File Channel (0=File Not Opened)
; Y = File Error (0=None)
FOPEN: JSR FSOPTS ;Parse Options Argument
FOPENA: JSR FSONAM ;Set Filename for Open
JSR FSUNCH ;Find Unused Channel Number
BEQ FSERR2 ;If None Available, Return Error 2
JSR RESRXY ;Load Device, Mode into X, Y
JMP FSOPEN ;and Open File
;fsccmd() - Close Command Channel
;Args: A = Device Number
;Returns: A = Logical File Number
FSCCMD: ORA #$10 ;Set LFN to Device# + 16
;fclose(chan) - Close File
;Args: A = Channel Number (0=Close All)
FCLOSE: ORA #0 ;Check File Number
BEQ FCLOSS ;If Not 0
JMP $FFC3 ; Execute Kernal Routine CLOSE
FCLOSS: JMP $FFE7 ;Else Execute Kernal Routine CLALL
;feof(lfn) - Check for End of File
;Args: A = Logical file number
;Affects: A,X
;Returns: A = $FF If End of File
; $00 Otherwise
FEOF: JSR FERROR ;Get Error Code
AND #$40 ;Mask off EOF Bit
BEQ FEOFX ;If Not 0
FSTRUE: LDA #$FF ; Return TRUE
FEOFX: RTS ;Return from Subroutine
;ferror(lfn) - Get Error on Channel`
;Args: A = Channel Number (0=None)
;Returns: A = Error Code
; 1 = Terminated by the STOP key
; 2 = Too many open files
; 3 = File Not Open
; 4 = File not found
; 5 = Device not present
; 6 = Not an input file
; 7 = Not an output file
; 8 = File name is missing
; 9 = Illegal device number
FERROR: TAX ;Copy LFN to X
LDA FSIOET,X ;Load I/O Status for LFN
RTS
;fflush() - Flush file buffer
;Args: A = Logical File Number
FFLUSH: RTS ;No Logic Needed
;fgetc(lfn) - Read character from file
;Args: A = Logical file number
;Affects: X
;Returns: A = Character
; Y = Error Code (0=None)
FGETC: TAX ;Move logical file number to X register
JSR $FFC6 ;Call Kernal Routine CHKIN
FGETCW: BCS FSERRW ;If Error, Write to Table and Return in Y
JSR $FFCF ;Call Kernal Routine CHRIN
TAY ;Save Character
FGETCC: JSR $FFCC ;Call Kernal Routine CLRCHN
TYA ;Restore Character
JSR FSRDST ;Read Status Byte
BVS FSORA0 ;If Not EOF
BCS FSZERO ;and Error, Return NUL
FSORA0: ORA #0 ;Else Set Flags Based on Character
RTS
;fsrcmd() - Read Command Channel
FSRCMD: LDA #15 ;Set LFN to 15
JSR FSGBFR ;Get Buffer Address
;fgets(lfn, &s) - Read string from file
;Args: A = Logical file number
; Y,X = Pointer to String
;Affects: X
;Returns: A = Number of bytes read
; Y = Error Code
FGETS: JSR SETDST ;Save string address
TAX ;Move logical file number to X register
JSR $FFC6 ;Call Kernal Routine CHKIN
BCS FGETCW ;If Error, Write to Table and Return in Y
LDY #0 ;Initialize Index
FGETSL: STY TEMP3 ;and Save It
JSR $FFCF ;Call Kernal Routine CHRIN
LDY TEMP3 ;Restore Index
CMP #$0D ;If Not C/R (Real or from Error)
BEQ FGETSX
STA (DSTLO),Y ;Store Character in String
INY ;Increment Pointer
BPL FGETSL ;and Loop if Less Than 128
FGETSX: LDA #0 ;Store NUL Terminator
STA (DSTLO),Y ;at End of String
JSR $FFCC ;Call Kernal Routine CLRCHN
TYA ;Copy Length of String to Acuumulator
JSR FSRDST ;Get I/O Status in Y Register
ORA #0 ;Set Flags based on Accumulator
FGETSR: RTS
;fread(lfn, count) - Read bytes from file
;Requires: DSTLO, DSTHI - Pointer to destination string
;Args: A = Logical file number
; Y = Number of Bytes to Read
;Sets: TEMP1 = Number of Bytes to Read
; TEMP2 = 0 (Read Mode)
; TEMP3 = Number of Bytes Read
;Affects: X
;Returns: A = Number of bytes read
; Y = Error Code (0=None)
; Carry Set if Error, Clear if None
FREAD: LDX #0 ;Mode = READ
FREADA: STX TEMP2 ;Save Mode
STY TEMP1 ;Save Number of Bytes
TAX ;Move logical file number to X register
JSR $FFC6 ;Call Kernal Routine CHKIN
FREADE: BCS FGETCW ;If Error, Write to Table and Return in Y
LDY #0 ;Initialize Index
STY TEMP3 ;and Save It
FREADL: JSR $FFCF ;Call Kernal Routine CHRIN
JSR FSRDST ;Get I/O Status in Y Register
BCS FREADX ;If No Error
LDY TEMP3 ; Retrieve Index
LDX TEMP2 ; Get Mode
BNE FREADN ; If READ
STA (DSTLO),Y ; Store Character in String
FREADN: INY ; Increment Pointer
STY TEMP3 ; and Save It
BVS FREADS ; If Not EOF
CPY TEMP1 ; Compare against Count
BNE FREADL ; and Loop if Less
FREADS: LDY #0 ; Set Error to None
FREADX: JSR $FFCC ;Call Kernal Routine CLRCHN
CLC ;Clear Carry
TYA ;Copy Error Code to Accumulator
ADC #$FF ;Set Carry if Error
LDA TEMP3 ;Return Length of String
RTS
;fputc(lfn, chr) - Write character from file
;Args: A = Logical file number
; Y = Character to Write
;Returns: A = Character (0 if Error)
; Y = Error Code (0=None)
FPUTC: TAX ;Move LFN to X register
JSR $FFC9 ;Call Kernal Routine CHKOUT
BCS FREADE ;If Error, Write to Table and Return in Y
TYA ;Copy Character to Accumulator
FPUTCO: JSR $FFD2 ;Call Kernal Routine CHROUT
JMP FGETCC ;Clear Channel and Check STATUS
;fputln(lfn, &s) - Write Line to File
;Args: A = Logical file number
; Y,X = Pointer to String
;Sets: SRCLO,SRCHI = Pointer to String
;Affects: X,Y
;Returns: A = Number of bytes written
; Y = Error Code (0=None)
FPUTLN: ORA #$80 ;Set High Bit and Fall Through
;fputs(lfn, &s) - Write String to File
;Args: A = Logical file number
; Y,X = Pointer to String
;Sets: SRCLO,SRCHI = Pointer to String
;Affects: X,Y
;Returns: A = Number of bytes written
; Y = Error Code (0=None)
FPUTS: JSR SETSRC ;Save string address & initialize pointer
FPUTSA: STA TEMP2 ;Save LFN Argument
AND #$7F ;Strip High Bit
TAX ;Copy LFN to X Register
JSR $FFC9 ;Call Kernal Routine CHKOUT
BCS FREADE ;If Error, Write to Table and Return in Y
LDY #0 ;Initialize Index
STY TEMP3 ;and Save It
FPUTSL: LDA (SRCLO),Y ;Load next character
BEQ FPUTSX ;If NUL, Finish Up
JSR $FFD2 ;Call Kernal Routine CHROUT
STY TEMP3 ;Save Index
JSR FSRDST ;Read I/O Status
BCS FREADX ;If Error, Return in Y
LDY TEMP3 ;Restore Index
INY ;Increment Index
BPL FPUTSL ;Loop if Less than 128
BMI FREADS ;Else Finish Up
FPUTSX: LDA TEMP2 ;Retrieve LFN Argument
BPL FREADS ;Finish Up if High Bit Not Set
INY ;Else Increment Count
LDA #$0D ;Load Carriage Return
BNE FPUTCO ;and Write It
FSKIP: LDX #$FF ;Set Mode to Skip
BNE FREADA ;and Execute FREAD
;fwrite(lfn, count) - Write bytes from file
;Requires: SRCLO, SRCHI - Pointer to destination string
;Args: A = Logical File Number
; Y = Number of Bytes to Write
;Affects: X
;Returns: A = Number of bytes read
; Y = Error Code (0=None)
FWRITE: STY TEMP1 ;Save Number of Bytes
TAX ;Move logical file number to X register
JSR $FFC9 ;Call Kernal Routine CHKOUT
BCS FREADE ;If Error, Return in Y (FSERRY)
LDY #0 ;Initialize Index
STY TEMP3 ;and Save It
FWRITL: LDA (SRCLO),Y ;Load next character
JSR $FFD2 ;Call Kernal Routine CHROUT
JSR FSRDST ;Read I/O Status
BCS FREADX ;If Error, Return In Y
INC TEMP3 ;Increment Index
LDY TEMP3 ;and Load it Index
CPY TEMP1 ;Compare against Count
BNE FWRITL ;and Loop if Less
BEQ FREADS ;Else Return No Error
;fgetw(lfn) - Read Word from File
;Args: A = Logical file number
;Sets: TEMP0 = Logical File Number
; TEMP1 = LSB
; TEMP2 = MSB
;Returns: A = Error Code (0=None)
; Y,X = Word (MSB, LSB)
FGETW: STA TEMP0 ;Save LFN
FGETWA: LDA TEMP0 ;Load LFN (Alternate Entry Point)
JSR FGETC ;Read LSB
BCS FGETWX ;If No Error
STA TEMP1 ; Save in TEMP1
LDA TEMP1 ; Restore LFN
JSR FGETC ; Read MSB
STA TEMP2 ; Save in TEMP2
FGETWX: TYA ;Copy Error to A
JSR RESRXY ;Load Word into Y,X
ORA #0 ;Set Flags
RTS