* AUXMEM.OSCLI.S
* (c) BOBBI 2021 GPLv3
*
* Handle OSCLI system calls

* 22-Aug-2021 Uses dispatch table
*             Prepares parameters and hands on to API call
* 24-Aug-2021 Combined *LOAD and *SAVE, full address parsing.
* 02-Sep-2021 *LOAD/*SAVE now uses GSTRANS.
* 12-Sep-2021 *HELP uses subject lookup, *HELP MOS, *HELP HOSTFS.


* COMMAND TABLE
***************
* Table structure is: { string, byte OR $80, destword-1 } $00
* fsc commands
CMDTABLE    ASC   'CAT'              ; Must be first command so matches '*.'
            DB    $85
            DW    STARFSC-1          ; CAT    -> FSC 5, XY=>params
            ASC   'RUN'
            DB    $84
            DW    STARFSC-1          ; RUN    -> FSC 4, XY=>params
            ASC   'EX'
            DB    $89
            DW    STARFSC-1          ; EX     -> FSC 9, XY=>params
            ASC   'INFO'
            DB    $8A
            DW    STARFSC-1          ; INFO   -> FSC 10, XY=>params
            ASC   'RENAME'
            DB    $8C
            DW    STARFSC-1          ; RENAME -> FSC 12, XY=>params
* osfile commands
            ASC   'LOAD'
            DB    $FF
            DW    STARLOAD-1         ; LOAD   -> OSFILE FF, CBLK=>filename
            ASC   'SAVE'
            DB    $FF
            DW    STARSAVE-1         ; SAVE   -> OSFILE 00, CBLK=>filename
            ASC   'DELETE'
            DB    $86
            DW    STARFILE-1         ; DELETE -> OSFILE 06, CBLK=>filename
            ASC   'MKDIR'
            DB    $88
            DW    STARFILE-1         ; MKDIR  -> OSFILE 08, CBLK=>filename
            ASC   'CDIR'
            DB    $88
            DW    STARFILE-1         ; CDIR   -> OSFILE 08, CBLK=>filename
* osbyte commands
            ASC   'FX'
            DB    $80
            DW    STARFX-1           ; FX     -> OSBYTE A,X,Y    (LPTR)=>params
            ASC   'OPT'
            DB    $8B
            DW    STARBYTE-1         ; OPT    -> OSBYTE &8B,X,Y  XY=>params
* others
            ASC   'COPY'
            DB    $FF
            DW    COPY-1             ; COPY   -> XY=>params
            ASC   'QUIT'
            DB    $80
            DW    STARQUIT-1         ; QUIT   -> (LPTR)=>params
            ASC   'HELP'
            DB    $FF
            DW    STARHELP-1         ; HELP   -> XY=>params
            ASC   'BASIC'
            DB    $80
            DW    STARBASIC-1        ; BASIC  -> (LPTR)=>params
            ASC   'KEY'
            DB    $80
            DW    STARKEY-1          ; KEY    -> (LPTR)=>params
            ASC   'ECHO'
            DB    $80
            DW    ECHO-1             ; ECHO   -> (LPTR)=>params
* DUMP <file>
* TYPE <file>
* BUILD <file>
* terminator
            DB    $FF

* *HELP TABLE
*************
HLPTABLE    ASC   'MOS'
            DB    $80
            DW    HELPMOS-1          ; *HELP MOS
            ASC   'HOSTFS'
            DB    $80
            DW    HELPHOSTFS-1       ; *HELP HOSTFS
            DB    $FF


* Command table lookup
* On entry, (OSLPTR)=>command string
*           XY=>command table
* On exit,  A=0  done, command called
*           A<>0 no match
*
* Search command table
CLILOOKUP   STX   OSTEXT+0           ; Start of command table
            STY   OSTEXT+1
            LDX   #0                 ; (ZP,X)=>command table
CLILP4      LDY   #0                 ; Start of command line
CLILP5      LDA   (OSTEXT,X)
            BMI   CLIMATCH           ; End of table string
            EOR   (OSLPTR),Y
            AND   #$DF               ; Force upper case match
            BNE   CLINOMATCH
            JSR   CLISTEP            ; Step to next table char
            INY                      ; Step to next command char
            BNE   CLILP5             ; Loop to check

CLINOMATCH  LDA   (OSLPTR),Y
            CMP   #'.'               ; Abbreviation?
            BEQ   CLIDOT
CLINEXT     JSR   CLISTEP            ; No match, step to next entry
            BPL   CLINEXT
CLINEXT2    JSR   CLISTEP            ; Step past byte, address
            JSR   CLISTEP
            JSR   CLISTEP
            BPL   CLILP4             ; Loop to check next
            RTS                      ; Exit, A>$7F

CLIDOT      LDA   (OSTEXT,X)
            BMI   CLINEXT2           ; Dot after full word, no match
CLIDOT2     JSR   CLISTEP            ; Step to command address
            BPL   CLIDOT2
            INY                      ; Step past dot
            BNE   CLIMATCH2          ; Jump to this command

CLIMATCH    LDA   (OSLPTR),Y
            CMP   #'.'
            BEQ   CLINEXT            ; Longer abbreviation, eg 'CAT.'
            CMP   #'A'
            BCS   CLINEXT            ; More letters, eg 'HELPER'
CLIMATCH2   JSR   CLIMATCH3          ; Call the routine
            LDA   #0
            RTS                      ; Return A=0 to claim

CLIMATCH3   JSR   SKIPSPC            ; (OSLPTR),Y=>parameters
            LDA   (OSTEXT,X)         ; Command byte
            PHA
            JSR   CLISTEP            ; Address low byte
            STA   OSTEMP
            JSR   CLISTEP            ; Address high byte
            PLX                      ; Get command byte
            PHA                      ; Push address high
            LDA   OSTEMP
            PHA                      ; Push address low
            TXA                      ; Command byte
            PHA
            ASL   A                  ; Drop bit 7
            BEQ   CLICALL            ; If $80 don't convert LPTR
            JSR   LPTRtoXY           ; XY=>parameters
CLICALL     PLA                      ; A=command parameter
            RTS                      ; Call command routine

CLISTEP     INC   OSTEXT+0,X         ; Point to next table byte
            BNE   CLISTEP2
            INC   OSTEXT+1,X
CLISTEP2    LDA   (OSTEXT,X)         ; Get next byte
            RTS


* OSCLI HANDLER
* On entry, XY=>command string
* On exit,  AXY corrupted or error generated
*
CLIHND      JSR   XYtoLPTR           ; LPTR=>command line
CLILP1      LDA   (OSLPTR),Y
            CMP   #$0D
            BEQ   CLI2
            INY
            BNE   CLILP1
CLIEXIT1    RTS                      ; No terminating <cr>
CLI2        LDY   #$FF
CLILP2      JSR   SKIPSPC1           ; Skip leading spaces
            CMP   #'*'               ; Skip leading stars
            BEQ   CLILP2
            CMP   #$0D
            BEQ   CLIEXIT1           ; Null string
            CMP   #'|'
            BEQ   CLIEXIT1           ; Comment
            CMP   #'/'
            BEQ   CLISLASH
            JSR   LPTRtoXY           ; Add Y to LPTR
            JSR   XYtoLPTR           ; LPTR=>start of actual command
            LDX   #<CMDTABLE         ; XY=>command table
            LDY   #>CMDTABLE
            JSR   CLILOOKUP          ; Look for command
            BNE   CLIUNKNOWN         ; No match
CLIDONE     RTS

CLISLASH    JSR   SKIPSPC1
            BEQ   CLIDONE            ; */<cr>
            LDA   #$02
            BNE   STARFSC2           ; FSC 2 = */filename

CLIUNKNOWN  LDA   #$04
            JSR   SERVICE            ; Offer to sideways ROM(s)
            BEQ   CLIDONE            ; Claimed
            LDA   #$03               ; FSC 3 = unknown command
STARFSC2    PHA
            JSR   LPTRtoXY           ; XY=>command
            PLA
STARFSC     AND   #$7F               ; A=command, XY=>parameters
            JSR   CALLFSCV           ; Hand on to filing system
            TAX
            BEQ   CLIDONE            ; A=0, FSC call implemented
ERRBADCMD   BRK
            DB    $FE
            ASC   'Bad command'
ERRBADNUM   BRK
            DB    $FC
            ASC   'Bad number'
ERRBADADD   BRK
            DB    $FC
            ASC   'Bad address'
            BRK


* *FX num(,num(,num))
*********************
STARFX      JSR   SCANDEC
            BRA   STARBYTE1

* Commands passed to OSBYTE
***************************
STARBYTE    JSR   XYtoLPTR
STARBYTE1   STA   OSAREG             ; Save OSBYTE number
            LDA   #$00               ; Default X and Y
            STA   OSXREG
            STA   OSYREG
            JSR   SKIPCOMMA          ; Step past any comma/spaces
            BEQ   STARBYTE2          ; End of line, do it
            JSR   SCANDEC            ; Scan for X param
            STA   OSXREG             ; Store it
            JSR   SKIPCOMMA          ; Step past any comma/spaces
            BEQ   STARBYTE2          ; End of line, do it
            JSR   SCANDEC            ; Scan for Y param
            STA   OSYREG             ; Store it
            JSR   SKIPSPC
            BNE   ERRBADCMD          ; More params, error
STARBYTE2   LDY   OSYREG
            LDX   OSXREG
            LDA   OSAREG
            JSR   OSBYTE
            BVS   ERRBADCMD
            RTS

* Scan decimal number
SCANDEC     JSR   SKIPSPC
            JSR   SCANDIGIT          ; Check first digit
            BCS   ERRBADNUM          ; Doesn't start with a digit
SCANDECLP   STA   OSTEMP             ; Store as current number
            JSR   SCANDIGIT          ; Check next digit
            BCS   SCANDECOK          ; No more digits   
            PHA
            LDA   OSTEMP
            CMP   #26
            BCS   ERRBADNUM          ; num>25, num*25>255
            ASL   A                  ; num*2
            ASL   A                  ; num*4
            ADC   OSTEMP             ; num*4+num = num*5
            ASL   A                  ; num*10
            STA   OSTEMP
            PLA
            ADC   OSTEMP             ; num=num*10+digit
            BCC   SCANDECLP
            BCS   ERRBADNUM          ; Overflowed

SCANDECOK   LDA   OSTEMP             ; Return A=number
SCANDIG2    SEC
            RTS

SCANDIGIT   LDA   (OSLPTR),Y
            CMP   #'0'
            BCC   SCANDIG2           ; <'0'
            CMP   #'9'+1
            BCS   SCANDIG2           ; >'9'
            INY
            AND   #$0F
            RTS

HEXDIGIT    JSR   SCANDIGIT
            BCC   HEXDIGIT2          ; Decimal digit
            AND   #$DF
            CMP   #'A'
            BCC   SCANDIG2           ; Bad hex character
            CMP   #'G'
            BCS   HEXDIGIT2          ; Bad hex character
            SBC   #$36               ; Convert 'A'-'F' to $0A-$0F
            INY
            CLC
HEXDIGIT2   RTS

* Scan hex address
* (OSLPTR),Y=>first character
* $200,X    = 4-byte accumulator 
SCANHEX     JSR   HEXDIGIT           ; Get first digit
            BCS   ERRBADADD1         ; Not a hex character
            STA   $200,X             ; Store first digit
            LDA   #0
            STA   $201,X             ; Clear rest of accumulator
            STA   $202,X
            STA   $203,X
SCANHEXLP1  JSR   HEXDIGIT           ; Get next digit
            BCS   SKIPSPC            ; Done, exit by skipping spaces
            STY   OSTEMP
            LDY   #4                 ; Four bits to rotate
SCANHEXLP2  ASL   $200,X             ; Multiple accumulator by 16
            ROL   $201,X
            ROL   $202,X
            ROL   $203,X
            BCS   ERRBADADD1         ; Overflowed
            DEY
            BNE   SCANHEXLP2         ; Loop for four bits
            ORA   $200,X             ; Add in current digit
            STA   $200,X
            LDY   OSTEMP             ; Get Y back
            BNE   SCANHEXLP1
ERRBADADD1  JMP   ERRBADADD

SKIPCOMMA   LDA   (OSLPTR),Y
            CMP   #$2C
            BNE   SKIPSPC            ; Drop through
*
* Skip spaces
SKIPSPC1    INY                      ; Step past a character
SKIPSPC     LDA   (OSLPTR),Y
            CMP   #' '
            BEQ   SKIPSPC1
            CMP   #$0D               ; Return EQ=<cr>
            RTS

* Skip a string
SKIPWORD    CLC
            JSR   GSINIT
SKIPWORDLP  JSR   GSREAD
            BCC   SKIPWORDLP
            RTS

* Convert (LPTR),Y to XY
LPTRtoXY    CLC
            TYA
            ADC   OSLPTR+0
            TAX
            LDA   #0
            ADC   OSLPTR+1
            TAY
            RTS

* Convert XY to (LPTR),Y
XYtoLPTR    STX   OSLPTR+0
            STY   OSLPTR+1
            LDY   #0
            RTS

* Print *HELP text
STARHELP    JSR   XYtoLPTR           ; (OSLPTR),Y=>parameters
            JSR   PRHELLO            ; Unify version message
            LDX   #<HLPTABLE         ; XY=>command table
            LDY   #>HLPTABLE
            JSR   CLILOOKUP          ; Look for *HELP subject
            LDA   $8006              ; Does ROM have service entry?
            BMI   STARHELP6          ; Yes, send service call
            JSR   OSNEWL
            LDA   #$09               ; Language name
            LDY   #$80               ; *TO DO* make this and BYTE8E
            JSR   PRSTR              ;  use same code
            JSR   OSNEWL
STARHELP6   LDY   #0                 ; (OSLPTR),Y=>parameters
            LDA   #9
            JMP   SERVICE            ; Pass to sideways ROM(s)


HELPHOSTFS  LDX   #<FSCCOMMAND       ; *HELP HOSTFS
            LDY   #>FSCCOMMAND
            BNE   HELPLIST
HELPMOS     LDX   #<CMDTABLE         ; *HELP MOS
            LDY   #>CMDTABLE

HELPLIST    STX   OSTEXT+0           ; Start of command table
            STY   OSTEXT+1
            LDX   #0
HELPLP1     LDA   #32
            JSR   OSWRCH
            JSR   OSWRCH
HELPLP2     LDY   #10
HELPLP3     LDA   (OSTEXT,X)
            BMI   HELPLP4
            JSR   OSWRCH
            DEY
            JSR   CLISTEP
            BPL   HELPLP3
HELPLP4     LDA   #32
            JSR   OSWRCH
            DEY
            BNE   HELPLP4
            JSR   CLISTEP
            JSR   CLISTEP
            JSR   CLISTEP
            BPL   HELPLP2
STARHELP4   LDA   #$08
            JSR   OSWRCH
            JSR   OSWRCH
            JMP   FORCENL


* Handle *QUIT command
STARQUIT    >>>   XF2MAIN,QUIT


STARSAVE    LDA   #$00               ; Set A=0 - SAVE
STARLOAD    PHA                      ; Entered with A=$FF - LOAD
            JSR   XYtoLPTR           ; OSLPTR=>filename
            JSR   SKIPWORD           ; Step past filename
            BNE   STARLDSV3          ; filename followed by addr
*
* filename followed by no address, must be *LOAD name
STARLDSV1   LDA   #$FF               ; $FF=load to file's address
STARLOAD2   STA   OSFILECB+6
            PLA
            BEQ   ERRBADADD2         ; *save name <no addr>
            LDA   #$7F               ; Will become A=$FF
            JMP   STARLDSVGO         ; Do the load

* At least one address specified
STARLDSV3   LDX   #OSFILECB+2-$200   ; X=>load
            JSR   SCANHEX
            BNE   STARSAVE3          ; Another address
            LDA   #$00               ; $00=load to supplied address
            BEQ   STARLOAD2          ; Only one address, must be *LOAD

* More than one address, must be *SAVE
STARSAVE3   PLA
            BNE   ERRBADADD2         ; Can't be *LOAD
            LDX   #3
STARSAVE4   LDA   OSFILECB+2,X       ; Get load
            STA   OSFILECB+6,X       ; copy to exec
            STA   OSFILECB+10,X      ; and to start
            DEX
            BPL   STARSAVE4
            LDA   (OSLPTR),Y
            CMP   #'+'
            PHP
            BNE   STARSAVE5          ; Not start+length
            JSR   SKIPSPC1           ; Step past '+' and spaces
STARSAVE5   LDX   #OSFILECB+14-$200
            JSR   SCANHEX            ; Get end or length
            PLP
            BNE   STARSAVE7          ; Not +length
            LDX   #0
            CLC
STARSAVE6   LDA   OSFILECB+10,X      ; end=start+length
            ADC   OSFILECB+14,X
            STA   OSFILECB+14,X
            INX
            TXA
            AND   #3
            BNE   STARSAVE6
* load =start
* exec =start
* start=start
* end  =end or start+length
STARSAVE7   JSR   SKIPSPC
            BEQ   STARSAVE10         ; No more, do it
            LDX   #OSFILECB+6-$200
            JSR   SCANHEX            ; Get exec
            BEQ   STARSAVE10         ; No more, do it
            LDX   #OSFILECB+2-$200
            JSR   SCANHEX            ; Get load
            BEQ   STARSAVE10         ; No more, do it
ERRBADADD2  JMP   ERRBADADD          ; Too many parameters

STARSAVE10  LDA   #$80               ; Will become $00 - SAVE
STARLDSVGO  LDX   OSLPTR+0
            LDY   OSLPTR+1           ; Continue through...
*

* Commands passed to OSFILE
***************************
STARFILE    EOR   #$80
            STX   OSFILECB+0
            STY   OSFILECB+1
            LDX   #<OSFILECB
            LDY   #>OSFILECB
            JSR   OSFILE
            TAX
            BNE   STARDONE
            JMP   ERRNOTFND

STARBASIC
STARKEY
STARDONE    RTS


* *ECHO <GSTRANS string>
************************
ECHO
*             PHY
*             CLC
*             JSR   ECHO0
*             PLY
            SEC
ECHO0       JSR   GSINIT
*             PHP
*             PLA
*             JSR   OUTHEX
ECHOLP1     JSR   GSREAD
            BCS   STARDONE
*             BCS   ECHO3
*             CMP   #$20
*             BCC   ECHO2
*             CMP   #$7F
*             BCS   ECHO2
            JSR   OSWRCH
            JMP   ECHOLP1
*ECHO2        PHA
*             LDA   #'<'
*             JSR   OSWRCH
*             PLA
*             JSR   OUTHEX
*             LDA   #'>'
*             JSR   OSWRCH
*             JMP   ECHOLP1
*ECHO3
*             PHP
*             PLA
*             JSR   OUTHEX
*             JMP   OSNEWL


