; Handle the MuSampler Commands

                GET             hdr.Common

                AREA            |$Commands|, PIC, CODE

                EXPORT          Commands
                IMPORT          StopAllAudio
                IMPORT          AudioBufferSizeInLBA
                IMPORT          AudioBufferSize
                IMPORT          AudioLBAsToRead
                IMPORT          AudioBytesToRead

; R0 ==> Command string = filename
; R1 ==> Count of commands

Commands        =               "CDFaker_Mount", 0
                &               Mount
                =               1, 0, 2, 0
                &               MountSyntax
                &               MountHelp

                =               "CDFaker_Dismount", 0
                &               Dismount
                =               1, 0, 1, 0
                &               DismountSyntax
                &               DismountHelp

                =               "CDFaker_Drives", 0
                &               DrivesCmd
                =               1, 0, 1, 0
                &               DrivesSyntax
                &               DrivesHelp

                =               "CDFaker_LoadEmulation", 0
                &               LoadEm
                =               2, 0, 2, 0
                &               LoadEmSyntax
                &               LoadEmHelp

                =               "CDFaker_NoEmulation", 0
                &               NoEm
                =               1, 0, 1, 0
                &               NoEmSyntax
                &               NoEmHelp

                =               "CDFakerAudioBuffer", 0
                &               ConfAudioBuffer
                =               1, 0, 1, 64
                &               ConfAudioBufferSyntax
                &               ConfAudioBufferHelp

                =               "CDFakerAudioReadAhead", 0
                &               ConfAudioReadAhead
                =               1, 0, 1, 64
                &               ConfAudioReadAheadSyntax
                &               ConfAudioReadAheadHelp

                &               0

                ALIGN

MountHelp       =               "*CDFaker_Mount mounts a new CD image file to the "
                =               "specified drive. If no file is specified the current "
                =               "image is remounted and CDFS will think that the disc "
                =               "has changed. If a CDPM (CD Performance Map) file is "
                =               "named it will be loaded for the specified drive", 13
MountSyntax     =               "Syntax: *CDFaker_Mount <fake drive> [<image file>]", 0

DismountHelp    =               "*CDFaker_Dismount dismounts the specified drive. CDFS "
                =               "will think that the drive is empty.", 13
DismountSyntax  =               "Syntax: *CDFaker_Dismount <fake drive>", 0

DrivesHelp      =               "*CDFaker_Drives sets the number of fake drives which "
                =               "CDFaker will report to CDFS. This command may not be used "
                =               "after CDFS has scanned for valid drives, and will return "
                =               "an error.", 13
DrivesSyntax    =               "Syntax: *CDFaker_Drives <drives>", 0

LoadEmHelp      =               "*CDFaker_LoadEmulation loads an emulation file for the "
                =               "specified fake drive.", 13
LoadEmSyntax    =               "Syntax: *CDFaker_LoadEmulation <fake drive> <emulation spec>", 0

NoEmHelp        =               "*CDFaker_NoEmulation disables emulation for the specified "
                =               "fake drive.", 13
NoEmSyntax      =               "Syntax: *CDFaker_NoEmulation <fake drive>", 0

ConfAudioBufferHelp
                =               "*Configure CDFakerAudioBuffer sets the size of buffer used to "
                =               "pre-cache CD-Audio in sectors (2352 bytes/sector "
                =               "75 sectors/second)", 13
ConfAudioBufferSyntax
                =               "Syntax: *Configure "
ConfAudioBufferSyntax2
                =               "CDFakerAudioBuffer",9,"<sectors>", 0

ConfAudioReadAheadHelp
                =               "*Configure CDFakerReadAhead sets the number of sectors (2352 "
                =               "bytes/sector 75 sectors/second) to read when enough space is "
                =               "free in the audio buffer.  A lower value will read from disc "
                =               "more often.", 13
ConfAudioReadAheadSyntax
                =               "Syntax: *Configure "
ConfAudioReadAheadSyntax2
                =               "CDFakerReadAhead",9,"<sectors>", 0

ConfAudioBuffer_Str
                =               "CDFakerAudioBuffer ", 0

ConfAudioReadAhead_Str
                =               "CDFakerAudioReadAhead ", 0


ConfAudioBuffer SAVE            "r0-r2"
                TEQ             r0, #0               ;print syntax?
                BEQ             ConfAudioBuffer_PrintSyntax
                TEQ             r0, #1               ;print value?
                BEQ             ConfAudioBuffer_PrintValue

                LDR             ws, [ws]
                MOV             r2, #1024            ;max value
                BL              ReadUnsigned
                BVS             ConfAudioBuffer_exit

                BL              StopAllAudio
                ADRL            r1, AudioBufferSizeInLBA
                STR             r2, [r1]
                MOV             r0, #2352
                MUL             r0, r2, r0
                ADRL            r1, AudioBufferSize
                STR             r0, [r1]
                SUBS            r0, r0, r0

ConfAudioBuffer_exit
                RETURN_ERR

ConfAudioBuffer_PrintSyntax
                ADRL            r0, ConfAudioBufferSyntax2
                SWI             XOS_Write0
                SWI             XOS_NewLine
                RETURN

ConfAudioBuffer_PrintValue
                ADR             r0, ConfAudioBuffer_Str
                SWI             XOS_Write0

                ADRL            r1, AudioBufferSizeInLBA
                LDR             r0, [r1]
                BL              DisplayValue
                RETURN


ConfAudioReadAhead SAVE            "r0-r2"
                TEQ             r0, #0               ;print syntax?
                BEQ             ConfAudioReadAhead_PrintSyntax
                TEQ             r0, #1               ;print value?
                BEQ             ConfAudioReadAhead_PrintValue

                LDR             ws, [ws]
                MOV             r2, #1024            ;max value
                BL              ReadUnsigned
                BVS             ConfAudioReadAhead_exit

                ADRL            r1, AudioBufferSizeInLBA
                LDR             r0, [r1]
                CMP             r2, r0               ;check its <= Buffer size
                BHI             ReadAheadInvalid

                BL              StopAllAudio
                ADRL            r1, AudioLBAsToRead
                STR             r2, [r1]
                MOV             r0, #2352
                MUL             r0, r2, r0
                ADRL            r1, AudioBytesToRead
                STR             r0, [r1]
                SUBS            r0, r0, r0           ;clear V

ConfAudioReadAhead_exit
                RETURN_ERR

ReadAheadInvalid
                MOV             r0, #&80000000
                ADDS            r0, r0, r0           ;set V
                MOV             r0, #2
                RETURN_ERR

ConfAudioReadAhead_PrintSyntax
                ADRL            r0, ConfAudioReadAheadSyntax2
                SWI             XOS_Write0
                SWI             XOS_NewLine
                RETURN

ConfAudioReadAhead_PrintValue
                ADRL            r0, ConfAudioReadAhead_Str
                SWI             XOS_Write0

                ADRL            r1, AudioLBAsToRead
                LDR             r0, [r1]
                BL              DisplayValue
                RETURN


ReadUnsigned    SAVE
                MOV             r1, r0
                MOV             r0, #10              ;base 10
                SWI             XOS_ReadUnsigned
                RETURN


DisplayValue    SAVE
                SUB             r13, r13, #8
                MOV             r1, r13
                MOV             r2, #8
                SWI             XOS_ConvertInteger2
                SWI             XOS_Write0
                ADD             r13, r13, #8
                SWI             XOS_NewLine
                RETURN


; Get a decimal number in the range 0..R2
;
; R0 ==> Command string
; R1 ==> Argument count
;
; On exit
;
; R0 ==> Updated
; R1 ==> Updated
; R2 ==> Number

GetDecimal      SAVE            "r3"
                MOV             r3, #0

GetDecimal1     LDRB            r4, [r0]
                TEQ             r4, #" "
                ADDEQ           r0, r0, #1
                BEQ             GetDecimal1

                CMP             r4, #"0"
                RSBHSS          lr, r4, #"9"

GetDecimal2     BGE             GetDecimal3
                RESTORE
                MOV             r0, #1 << 31         ;set V
                ADDS            r0, r0, r0
                ADR             r0, BadNumberMsg
                MOV             pc, lr

GetDecimal3     LDRB            r4, [r0], #1
                CMP             r4, #"0"
                RSBHSS          lr, r4, #"9"
                BLT             GetDecimal4

                SUB             r4, r4, #"0"
                ADD             r3, r3, r3, LSL #2
                ADD             r3, r4, r3, LSL #1
                B               GetDecimal3

GetDecimal4     CMP             r2, r3
                BLT             GetDecimal2
                MOV             r2, r3
                SUBS            r1, r1, #1
                RETURN

BadNumberMsg    MKERR           BadNumber

; R0  ==> Command tail
; R1  ==> Argument count
;
; On exit
;
; R10 ==> Drive block

GetDrive        SAVE            "r2"
                MOV             r2, #MaxDrive
                BL              GetDecimal
                MOVVC           lr,     #Drive_Size :AND: &00FF
                ORRVC           lr, lr, #Drive_Size :AND: &FF00
                ADRVC           r10, DriveBlock
                MLAVC           r10, r2, lr, r10
                RETURN_ERR

Drive_Block_Size DCD Drive_Size

; CDFaker_Mount <drive> [<filename>]

Mount           SAVE            "r0-r6, r10, ws"
                LDR             ws, [ws]
                BL              GetDrive
                BVS             MountX

                LDR             r2, [r10, #Drive_Flags]
                ORR             r2, r2, #Drive_DiscChanged
                STR             r2, [r10, #Drive_Flags]
                CMP             r1, #0
                BLE             MountX

; Clear track info
                ADD             r2, r10, #Drive_Tracks
                MOV             r1, #100
                MOV             r3, #0
ClearTrack_Info_L1
                STR             r3, [r2, #TrackInfo_DataType]
                ADD             r2, r2, #TrackInfo_Size
                SUBS            r1, r1, #1
                BNE             ClearTrack_Info_L1

                STR             r3, [r10, #Drive_ImageType]

; Get filename
Mount1          LDRB            r2, [r0]
                TEQ             r2, #" "
                ADDEQ           r0, r0, #1
                BEQ             Mount1

; Check the type and existance of the file
                MOV             r1, r0
CUEread
                MOV             r0, #17
                SWI             XOS_File
                BVS             MountX
                TEQ             r0, #1                ;problem?
                MOVNE           r2, r0
                MOVNE           r0, #19
                SWINE           XOS_File              ;YES, generate error
                BVS             MountX                ; |+  and exit
                BIC             r2, r2, #&FF

                LDR             r3, [r10, #Drive_ImageType]
                TEQ             r3, #0
                BNE             CUEloaded
                LDR             r3, =&FFFA7900        ;CUE file?
                TEQ             r2, r3
                BEQ             ReadCUEfile

                LDR             r3, =&FFFDF600
                TEQ             r2, r3
                RESTORE         NE
                MOVNE           r0, #1 << 31         ;set V
                ADDNES          r0, r0, r0
                ADRVS           r0, BadTypeMsg
                MOVVS           pc, lr
CUEloaded
                MOV             r5, r1        ; Save name ptr for later
                MOV             r6, r4        ; and length

; Open the new file

                MOV             r0, #&43
                SWI             XOS_Find
                BVS             MountX

; Check for CDPM file

                MOV             r1, r0
                SUB             sp, sp, #4

                MOV             r0, #4
                MOV             r2, sp
                MOV             r3, #4
                SWI             XOS_GBPB
                LDR             r0, [sp], #4
                BVS             MountX

                LDR             r2, CDPM
                TEQ             r0, r2
                BNE             Mount2

; It's a CDPM file, so close it and load it (R4 is still its length)

                MOV             r0, #0
                SWI             XOS_Find
                BVS             MountX

; Allocate space for new block

                MOV             r0, #6
                MOV             r3, r6
                DBF             "XOS_Module %0w, %3w\n"
                SWI             XOS_Module
                MOVVC           r0, #16
                MOVVC           r1, r5      ; File name
                MOVVC           r3, #0
                MOVVC           r6, r2      ; Save address
                DBF             "XOS_File %0w, %1s, %2w, %3w (r10 = %r10w)\n", VC
                SWIVC           XOS_File    ; load it

                LDRVC           r2, [r10, #Drive_Emulation]
                STRVC           r6, [r10, #Drive_Emulation]
                BVS             MountX
                
                TEQ             r2, #0
                MOVNE           r0, #7
                SWINE           XOS_Module                                

                B               MountX

; New image being opened

Mount2          MOV             r0, #0
                MOV             r2, r1          ; File handle of new file
                LDR             r1, [r10, #Drive_Handle]
                TEQ             r1, #0
                SWINE           XOS_Find        ; Don't error
                BL              Force_CD_rescan
                STR             r2, [r10, #Drive_Handle]

                DBF             "Drive at %r10w, handle is %2w\n"

; Keep a copy of the name
                ADD             r2, r10, #Drive_FileName
Mount3          LDRB            r3, [r5], #1
                CMP             r3, #" "
                MOVLE           r3, #0
                STRB            r3, [r2], #1
                BGT             Mount3

MountX          RETURN_ERR

; Identify all CD's, so we can allocate a SCSI ID to our drives.

Force_CD_rescan SAVE            "r0-r3,r7"
                MOV             r3, #2_11111111
                SUB             sp, sp, #20
                MOV             r0, #0
                STR             r0, [sp, #12]
                STR             r0, [sp, #16]
                MOV             r7, sp
Force_CD_rescan_L1
                AND             r0, r3, #2_111
                STR             r0, [sp, #0]
                MOV             r0, r3, LSR #3
                AND             r0, r0, #2_11
                STR             r0, [sp, #4]
                MOV             r0, r3, LSR #5
                AND             r0, r0, #2_111
                STR             r0, [sp, #8]
                SWI             XCD_Identify
                SUBS            r3, r3, #1
                BNE             Force_CD_rescan_L1
                ADD             sp, sp, #20
                RETURN

CDPM            =               "CDPM"

BadTypeMsg      MKERR           BadType

Dismount        SAVE            "r0-r1, r10, ws"
                LDR             ws, [ws]
                BL              GetDrive
                BVS             DismountX
                MOV             r0, #0
                LDR             r1, [r10, #Drive_Handle]
                TEQ             r1, #0
                SWINE           XOS_Find
                MOV             r1, #0
                STR             r1, [r10, #Drive_Handle]
DismountX       RETURN_ERR

DrivesCmd       SAVE            "r0-r2, ws"
                LDR             ws, [ws]

                LDR             r2, Flags
                TST             r2, #CDFSSeen
                RESTORE         NE
                MOVNE           r0, #1 << 31         ;set V
                ADDNES          r0, r0, r0
                ADRVS           r0, CantChDrMsg
                MOVVS           pc, lr

                MOV             r2, #MaxDrive
                BL              GetDecimal
                STRVC           r2, Drives
                RETURN_ERR

CantChDrMsg     MKERR           CantChDr

LoadEm
NoEm            MOV             pc, lr

; JJA CUE file support
;Entry:
; r1    = CUE filename
; stack = r0-r6, r10, ws
;
;Exit:
; r1    = BIN filename

ReadCUEfile                                          ;parse CUE file
                STMFD           sp!, {r1, r7-r9}

                MOV             r0, #&43             ;open file, no path
                SWI             XOS_Find
                TEQ             r0, #0               ;did an error occur
                BEQ             CUEfileError
                MOV             r9, r0               ;r9=file handle

                MOV             r0, #6
                MOV             r3, #256
                SWI             XOS_Module           ;claim some temp space
                BVS             CUEfileErrorExit
                MOV             r8, r2               ;r8=temp space address

                ADD             r7, r10, #Drive_Tracks
                                                     ;r7=track info table
                MOV             r6, #0               ;r6=last track#
ReadCUEfile_L1
                BL              FileReadLine
                MOV             r1, r8
                ADR             r0, strFILE
                BL              strCMP
                BEQ             CUE_FILE

                ADR             r0, strTRACK
                BL              strCMP
                BEQ             CUE_TRACK

                ADR             r0, strINDEX
                BL              strCMP
                BEQ             CUE_INDEX

                LDRB            r0, [r8, #0]
                TEQ             r0, #0
                BNE             ReadCUEfile_L1

                MOV             r0, #7
                MOV             r2, r8
                SWI             XOS_Module

                MOV             r0, #0
                MOV             r1, r9
                SWI             XOS_Find             ;close file

                LDMFD           sp!, {r1, r7-r9}
                ADD             r1, r10, #Drive_FileName
                B               CUEread


FILE_TOO_LONGerror
                ADR             r1, FilePathMsg
                B               CUEfileError2
FILETYPEerror
                ADR             r1, FILETYPEMsg
                B               CUEfileError2
TRACKTYPEerror
                ADR             r1, TRACKTYPEMsg
                B               CUEfileError2
CUEfileError
                ADR             r0, MountErrMsg
CUEfileError2
                MOV             r0, #1<<31
                ADDS            r0, r0, r0           ;set V
                MOV             r0, r1
CUEfileErrorExit
                LDMFD           sp!, {r1, r7-r9}
                B               MountX


MountErrMsg     MKERR MountErr
TRACKTYPEMsg    MKERR TRACKTYPEErr
FILETYPEMsg     MKERR FILETYPEErr
FilePathMsg     MKERR FilePathErr
strFILE         = "FILE", 0
strTRACK        = "TRACK", 0
strINDEX        = "INDEX", 0
                ALIGN


;Entry:
; stack - r1
CUE_FILE
                ADD             r1, r8, #4
                BL              skipSPACES

                LDR             r5, [r13]            ;get CUE file from stack
                ADD             r2, r10, #Drive_FileName

                MOV             r3, r2
                ADD             r4, r2, #Drive_Tracks-Drive_FileName-1
CUE_FILE_L1     LDRB            r0, [r5], #1
                STRB            r0, [r2], #1
                TEQ             r2, r4               ;file/path too long?
                BEQ             FILE_TOO_LONGerror
                TEQ             r0, #0               ;find end of filename
                TEQNE           r0, #13
                BNE             CUE_FILE_L1

CUE_FILE_L2     LDRB            r0, [r2, #-1]!       ;find filename
                TEQ             r2, r3               ;hit start?
                BEQ             CUE_FILENAME_FOUND
                TEQ             r0, #"."             ;directory?
                TEQNE           r0, #":"             ;path?
                BNE             CUE_FILE_L2          ;NO
                ADD             r2, r2, #1
                                                     ;max file length
CUE_FILENAME_FOUND                                   ;r2=start of filename
                LDRB            r0, [r1], #1
                TEQ             r0, #34              ;is it quoted?
                BEQ             CUE_FILE_QUOTED_L1

CUE_FILE_L3     CMP             r2, r4               ;hit end of buffer?
                BEQ             FILE_TOO_LONGerror
                TEQ             r0, #"."             ;replace . with /
                MOVEQ           r0, #"/"
                STRB            r0, [r2], #1
                TEQ             r0, #" "             ;end of filename
                TEQNE           r2, #0               ;handle syntax errors
                LDRNEB          r0, [r1], #1
                BNE             CUE_FILE_L3
                B               CUE_FILE_DONE

CUE_FILE_QUOTED_L1
                CMP             r2, r4               ;hit end of buffer?
                BEQ             FILE_TOO_LONGerror
                LDRB            r0, [r1], #1
                TEQ             r0, #"."             ;replace . with /
                MOVEQ           r0, #"/"
                TEQ             r0, #34              ;have we hit ending quote?
                TEQNE           r0, #0               ;handle syntax errors
                STRNEB          r0, [r2], #1
                BNE             CUE_FILE_QUOTED_L1

CUE_FILE_DONE   MOV             r0, #0
                STRB            r0, [r2]             ;terminate filename

                BL              skipSPACES

                ADR             r0, strBINARY
                BL              strCMP               
                MOVEQ           r3, #Type_BINARY
                BEQ             CUE_TYPE_found

                ADR             r0, strMOTOROLA
                BL              strCMP               
                MOVEQ           r3, #Type_MOTOROLA
                BEQ             CUE_TYPE_found

                ADR             r0, strAIF
                BL              strCMP               
                MOVEQ           r3, #Type_AIF
                BEQ             CUE_TYPE_found

                ADR             r0, strWAV
                BL              strCMP               
                MOVEQ           r3, #Type_WAV
                BEQ             CUE_TYPE_found

                ADR             r0, strMP3
                BL              strCMP               
                MOVEQ           r3, #Type_MP3
                BEQ             CUE_TYPE_found

                B               FILETYPEerror

CUE_TYPE_found  STR             r3, [r10, #Drive_ImageType]
                B               ReadCUEfile_L1

strBINARY       = "BINARY", 0
strMOTOROLA     = "MOTOROLA", 0
strAIF          = "AIF", 0
strWAV          = "WAV", 0
strMP3          = "MP3", 0
                ALIGN



CUE_TRACK
                MOV             r3, #256             ;r3=format
                MOV             r4, #0               ;r4=framesize

                ADD             r1, r8, #5
                BL              readVAL              ;r2=track#
                SUB             r2, r2, #1           ;correct track#
                CMP             r2, #99              ;is track# valid
                BCS             ReadCUEfile_L1       ;NO
                MOV             r6, r2               ;r6=track#
                BL              skipSPACES
                                                     ;get track type
                ADR             r0, strAUDIO
                BL              strCMP               
                MOVEQ           r3, #Type_AUDIO
                BEQ             CUE_TRACK_found

                ADR             r0, strCDG
                BL              strCMP               
                MOVEQ           r3, #Type_CDG
                BEQ             CUE_TRACK_found

                ADR             r0, strMODE1_2048
                BL              strCMP               
                MOVEQ           r3, #Type_MODE1_2048
                BEQ             CUE_TRACK_found

                ADR             r0, strMODE1_2352
                BL              strCMP               
                MOVEQ           r3, #Type_MODE1_2352
                BEQ             CUE_TRACK_found

                ADR             r0, strMODE2_2336
                BL              strCMP               
                MOVEQ           r3, #Type_MODE2_2336
                BEQ             CUE_TRACK_found

                ADR             r0, strMODE2_2352
                BL              strCMP               
                MOVEQ           r3, #Type_MODE2_2352
                BEQ             CUE_TRACK_found

                ADR             r0, strCDI_2336
                BL              strCMP               
                MOVEQ           r3, #Type_CDI_2336
                BEQ             CUE_TRACK_found

                ADR             r0, strCDI_2352
                BL              strCMP               
                MOVEQ           r3, #Type_CDI_2352
                BEQ             CUE_TRACK_found

                B               TRACKTYPEerror


CUE_TRACK_found
                ADD             r1, r7, r6, LSL #4   ;16 bytes per track
                STR             r3, [r1, #TrackInfo_DataType]    ;data type
                B               ReadCUEfile_L1


strAUDIO        = "AUDIO", 0
strCDG          = "CDG", 0
strMODE1_2048   = "MODE1/2048", 0
strMODE1_2352   = "MODE1/2352", 0
strMODE2_2336   = "MODE2/2336", 0
strMODE2_2352   = "MODE2/2352", 0
strCDI_2336     = "CDI/2336", 0
strCDI_2352     = "CDI/2352", 0
                ALIGN

CUE_INDEX
                TEQ             r6, #0               ;do we know the track?
                BEQ             ReadCUEfile_L1       ;NO, ignore

                ADD             r1, r8, #5
                BL              readVAL              ;r2=index
                CMP             r2, #1               ;subindex
                BNE             ReadCUEfile_L1       ;YES, ignore

                BL              skipSPACES
                BL              readVAL
                MOV             r4, #&1100
                ADD             r4, r4, #&94         ;75*60
                MUL             r3, r4, r2           ;r3=index in frames

                ADD             r1, r1, #1           ;skip ":"

                BL              readVAL
                MOV             r4, #75
                MLA             r3, r4, r2, r3

                ADD             r1, r1, #1

                BL              readVAL
                ADD             r3, r3, r2

                ADD             r1, r7, r6, LSL #4
                STR             r3, [r1, #TrackInfo_Offset]
                B               ReadCUEfile_L1


;Entry:
; r1 = string pointer
;
;Exit:
; r1 = updated string pointer
; r2 = value

readVAL         SAVE "r0, r3"
                MOV             r0, #10
                SWI             XOS_ReadUnsigned
                RETURN

;Entry:
; r1 = string pointer
;
;Exit:
; r1 = updated string pointer

skipSPACES      SAVE "r0"
skipSPACES_L1   LDRB            r0, [r1], #1
                TEQ             r0, #32              ;skip SPACES
                BEQ             skipSPACES_L1
                SUB             r1, r1, #1
                RETURN


;Entry:
; r0 = string1
; r1 = string2
;
;Exit:
; EQ - strings are the same
; NE - strings are different

strCMP          SAVE "r0-r3"
strCMP_L1
                LDRB            r2, [r0], #1
                LDRB            r3, [r1], #1
                CMP             r2, #33
                CMPCC           r3, #33
                BCC             strCMPEQ

                CMP             r2, r3
                BEQ             strCMP_L1
                RETURN
strCMPEQ        CMP             r2, r2
                RETURN

;Entry:
; r9 = file handle
; r8 = 256 byte temp buffer
FileReadLine    SAVE "r1-r3"
                MOV             r1, r8               ;r1=string ptr
FileReadLine_L1
                BL              FileBGET
                TEQ             r0, #0               ;EOF?
                BEQ             FileReadLineExit     ;YES
                CMP             r0, #32              ;strip off spaces
                BLE             FileReadLine_L1

                BIC             r0, r0, #32          ;convert to uppercase
                STRB            r0, [r1], #1
FileReadLine_L2
                BL              FileBGET
                CMP             r0, #65
                BICCS           r0, r0, #32          ;convert to uppercase
                CMP             r0, #32
                STRCSB          r0, [r1], #1
                BCS             FileReadLine_L2

FileReadLineExit
                MOV             r0, #0               ;terminate string
                STRB            r0, [r1], #1
                RETURN

FileBGET        MOV             r0, #0
                SAVE "r0-r3"
                MOV             r0, #4               ;read from current ptr
                MOV             r1, r9
                MOV             r2, sp
                MOV             r3, #1
                SWI             XOS_GBPB
                RETURN
; ---

                END
