;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
;@                                                                            @
 
;@                 S Y M B O S   S Y S T E M   L I B R A R Y                  @
 
;@                    - SYMSHELL TEXT TERMINAL FUNCTIONS -                    @
 
;@                                                                            @
 
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 
 
;Author     Prodatron / Symbiosis
 
;Date       28.03.2015
 
 
 
;SymShell provides a program environment with a text terminal. The input and
 
;output can be redirected from and to different sources and destinations.
 
;This library supports you in using the SymShell functions.
 
 
 
;The existance of
 
;- "App_PrcID" (a byte, where the ID of the applications process is stored)
 
;- "App_MsgBuf" (the message buffer, 14 bytes, which are placed in the transfer
 
;  ram area)
 
;- "App_BnkNum" (a byte, where the number of the applications' ram bank (0-15)
 
;  is stored)
 
;- "App_BegCode" (the first byte/word of the header/code area, which also
 
;  includes the total length of the code area)
 
;is required.
 
 
 
 
 
;### SUMMARY ##################################################################
 
 
 
;;   SyShell_PARALL              ;Fetches parameters/switches from command line
 
;;   SyShell_PARSHL              ;Parses SymShell info switch
 
;use_SyShell_PARFLG      equ 0   ;Validates present switches
 
;use_SyShell_CHRINP      equ 0   ;Reads a char from the input source
 
;use_SyShell_STRINP      equ 0   ;Reads a string from the input source
 
;use_SyShell_CHROUT      equ 0   ;Sends a char to the output destination
 
;use_SyShell_STROUT      equ 0   ;Sends a string to the output destination
 
;use_SyShell_PTHADD      equ 0   ;...
 
;;   SyShell_EXIT                ;Informs SymShell about an exit event
 
 
 
 
 
;### GLOBAL VARIABLES #########################################################
 
 
 
SyShell_CmdParas   ds 8*3   ;command line parameters (1W address, 1B length)
 
SyShell_CmdSwtch   ds 8*3   ;command line switches
 
SyShell_PrcID      db 0     ;shell process ID
 
SyShell_TermX      db 0     ;x length in chars of the text terminal window
 
SyShell_TermY      db 0     ;y length in chars of the text terminal window
 
SyShell_Vers       db 0     ;SymShell version (e.g. 21 decimal for 2.1)
 
 
 
 
 
;### MAIN FUNCTIONS ###########################################################
 
 
 
SyShell_PARALL
 
;******************************************************************************
 
;*** Name           SymShell_Parameters_All
 
;*** Input          -
 
;*** Output         (SyShell_CmdParas) = list of parameters; 3 bytes/entry
 
;***                                     Byte0,1 = pointer
 
;***                                     Byte2   = length
 
;***                (SyShell_CmdSwtch) = list of switches (see above; a switch
 
;***                                     is recognized with a % at the
 
;***                                     beginning, which is skipped in this
 
;***                                     list)
 
;***                D                  = number of parameters
 
;***                E                  = number of switches
 
;***                ZF                 = if 1, no parameters and switches
 
;*** Destroyed      AF,BC,HL,IX,IY
 
;*** Description    This function fetches all parameters and switches from the
 
;***                command line and generates two pointer tables. A switch is
 
;***                recognized with a leading "%" char. A pointer to a switch
 
;***                links to the first char behind the %. All parameters and
 
;***                switches are zero terminated.
 
;*** Example        A\>EXAMPLE.COM filename.ext %x %all hello123
 
;***                This will generate two entries in the parameter table:
 
;***                - pointer to "filename.ext", length=12
 
;***                - pointer to "hello123", length=8
 
;***                And two entries in the switch table:
 
;***                - pointer to "x", length=1
 
;***                - pointer to "all", length=3
 
;***                Please note, that SymShell itself will add an own switch to
 
;***                the command line (see "SymShell_Parameters_Shell").
 
;******************************************************************************
 
        ld hl,(App_BegCode)
 
        ld de,App_BegCode
 
        dec h
 
        add hl,de                   ;HL = CodeEnd = Command line
 
        ld ix,SyShell_CmdParas      ;IX = Parameter List
 
        ld iy,SyShell_CmdSwtch      ;IY = Switch    List
 
        ld bc,8*256+8       ;B=8-number of parameters, C=8-number of switches
 
SyHPAl1 push bc
 
        call SyHPAl2
 
        pop bc
 
        jr z,SyHPAl7
 
        ld a,(hl)
 
        cp "%"
 
        jr z,SyHPAl6
 
        ld (ix+0),l         ;Parameter
 
        ld (ix+1),h
 
        push hl
 
        call SyHPAl4
 
        pop hl
 
        ld (ix+2),e
 
        ld de,3
 
        add ix,de
 
        dec b
 
        jr nz,SyHPAl1
 
        jr SyHPAl7
 
SyHPAl6 inc hl              ;Switch
 
        ld (iy+0),l
 
        ld (iy+1),h
 
        push hl
 
        call SyHPAl4
 
        pop hl
 
        ld (iy+2),e
 
        ld de,3
 
        add iy,de
 
        dec c
 
        jr nz,SyHPAl1
 
SyHPAl7 ld a,8
 
        sub c
 
        ld e,a
 
        ld a,8
 
        sub b
 
        ld d,a
 
        or e
 
        ret
 
;HL=position inside the string -> jump to next string -> HL=next string, ZF=1 end reached
 
SyHPAl2 ld a,(hl)
 
        inc hl
 
        or a
 
        ret z
 
        cp " "
 
        jr nz,SyHPAl2
 
        dec hl
 
        ld (hl),0
 
SyHPAl3 inc hl
 
        ld a,(hl)
 
        cp " "
 
        jr z,SyHPAl3
 
        ld a,1
 
        or a
 
        ret
 
;HL=position inside the string -> E=length until the end
 
SyHPAl4 ld e,0
 
SyHPAl5 ld a,(hl)
 
        or a
 
        ret z
 
        cp " "
 
        ret z
 
        inc e
 
        inc hl
 
        jr SyHPAl5
 
 
 
SyShell_PARSHL
 
;******************************************************************************
 
;*** Name           SymShell_Parameters_Shell
 
;*** Input          (SyShell_CmdSwtch) = list of switches
 
;***                E                  = number of switches
 
;*** Output         CF     = error state (0 = ok, 1 = no valid shell parameters
 
;***                         found; application should quit itself at once)
 
;***                (SyShell_PrcID) = shell process ID
 
;***                (SyShell_TermX) = width in chars of the terminal window
 
;***                (SyShell_TermY) = height in chars of the terminal window
 
;***                (SyShell_Vers)  = shell version (e.g. 21 decimal for 2.1)
 
;*** Destroyed      AF,BC,DE,HL,IX
 
;*** Description    This function parses the SymShell info switch from the
 
;***                command line. The info switch is built like this:
 
;***                %spPPXXYYVV
 
;***                PP is the process ID of SymShell itself, XX and YY is the
 
;***                size of the text terminal window and VV is the version of
 
;***                SymShell. If VV is not present, it is a version below 2.0
 
;***                and (SyShell_Vers) will stay 0.
 
;***                Every SymShell-based application has to parse this switch
 
;***                with the help of this function, as at least the process ID
 
;***                is required for any communication with SymShell. You have
 
;***                to call SyShell_PARALL first before you call this function,
 
;***                as the switch table already has to be present.
 
;***                For additional information see also "Symshell Command Line
 
;***                Information" in the chapter "SymShell Text Terminal" of the
 
;***                Symbos Developer Documentation.
 
;******************************************************************************
 
        ld a,e
 
        or a
 
        jr z,SyHPSh6            ;no switches -> error
 
        ld ix,SyShell_CmdSwtch
 
        ld bc,3
 
SyHPSh1 ld l,(ix+0)
 
        ld h,(ix+1)
 
        ld a,(hl)
 
        cp "s"
 
        jr nz,SyHPSh2
 
        inc hl
 
        ld a,(hl)
 
        cp "p"
 
        jr  z,SyHPSh3
 
SyHPSh2 add ix,bc
 
        dec e
 
        jr nz,SyHPSh1
 
SyHPSh6 scf                     ;no Shell-Data -> error
 
        ret
 
SyHPSh3 inc hl
 
        call SyHPSh4
 
        ld (SyShell_PrcID),a
 
        call SyHPSh4
 
        ld (SyShell_TermX),a
 
        call SyHPSh4
 
        ld (SyShell_TermY),a
 
        ld a,(hl)
 
        or a
 
        ret z
 
        call SyHPSh4
 
        ld (SyShell_Vers),a
 
        or a
 
        ret
 
;(HL)=2digit number -> A=number, HL=HL+2
 
SyHPSh4 call SyHPSh5
 
        add a
 
        ld d,a
 
        add a:add a
 
        add d
 
        ld d,a
 
        call SyHPSh5
 
        add d
 
        ret
 
SyHPSh5 ld a,(hl)
 
        sub "0"
 
        cp 10
 
        inc hl
 
        ret c
 
        pop hl      ;clear stack
 
        pop hl
 
        scf         ;wrong number -> error
 
        ret
 
 
 
if use_SyShell_PARFLG=1
 
SyShell_PARFLG
 
;******************************************************************************
 
;*** Name           SymShell_Parameters_Switches
 
;*** Input          (SyShell_CmdSwtch) = list of switches
 
;***                E                  = number of present switches
 
;***                IY                 = list with allowed switches
 
;***                                     word 0 = points to valid switch string
 
;***                                              (terminated by 0 or colon)
 
;***                                     word 1 = will be filled with pointer
 
;***                                              behind colon, if found
 
;***                                     list is terminated by a 0-word
 
;*** Output         CF = 0 -> all switches are valid; HL = bitfield of detected
 
;***                          switches
 
;***                CF = 1 -> invalid switch found; HL points to invalid switch
 
;***                          string (including the % char)
 
;*** Destroyed      AF,BC,DE,HL,IX,IY
 
;*** Description    This function validates the present switches with a list of
 
;***                allowed switches. Switches can have a parameter attached
 
;***                which is separated by a colon from the switch. If such a
 
;***                switch is found, the function will insert the pointer to
 
;***                its parameter into the validation list. If only valid
 
;***                switches have been found the function returns with a
 
;***                bitfield in HL of the present switches (bit0=1 -> first
 
;***                switch in the validation list is present), therefore the
 
;***                maximum amount of switches is 16.
 
;***                The function returns with an error, if an invalid switch
 
;***                has been found.
 
;******************************************************************************
 
        ld hl,0
 
        ld (SyHPFlb),hl
 
        ld a,e
 
        or a
 
        ret z
 
        ld b,e              ;b=number of present switches
 
        ld ix,SyShell_CmdSwtch
 
SyHPFl1 push iy         ;** present switch loop
 
        ld c,0              ;iy=validation list, c=number of valid switch
 
SyHPFl2 ld l,(iy+0)     ;** valid switch loop
 
        ld h,(iy+1)         ;hl=next valid switch
 
        ld e,(ix+0)         ;de=next present switch
 
        ld d,(ix+1)
 
        ld a,l
 
        or h
 
        jr nz,SyHPFl3
 
        pop hl
 
        dec de              ;switch not found in validation switch -> error
 
        ex de,hl
 
        scf
 
        ret
 
SyHPFl3 ld a,(de)           ;test, if shell switch
 
        cp "s"
 
        jr nz,SyHPFl9
 
        inc de
 
        ld a,(de)
 
        dec de
 
        cp "p"
 
        jr z,SyHPFla        ;yes -> ignore
 
SyHPFl8 ld a,(de)           ;compare switches
 
SyHPFl9 cp "A"
 
        jr c,SyHPFlc
 
        cp "Z"+1
 
        jr nc,SyHPFlc
 
        add "a"-"A"
 
SyHPFlc cp (hl)
 
        jr nz,SyHPFl7       ;not equal, compare with next valid
 
        inc hl
 
        inc de
 
        or a
 
        jr z,SyHPFl4
 
        cp ":"
 
        jr nz,SyHPFl8
 
        ld (iy+2),e         ;switch contains colon -> set pointer to parameter
 
        ld (iy+3),d
 
SyHPFl4 ld hl,1             ;switch found -> set bit
 
        inc c
 
SyHPFl5 dec c
 
        jr z,SyHPFl6
 
        add hl,hl
 
        jr SyHPFl5
 
SyHPFl6 ld de,(SyHPFlb)
 
        add hl,de
 
        ld (SyHPFlb),hl
 
SyHPFla ld de,3
 
        add ix,de
 
        pop iy
 
        djnz SyHPFl1
 
        ld hl,(SyHPFlb)
 
        ret                 ;all present switches are valid -> CF=0, HL=switch-bitfield
 
SyHPFl7 ld de,4             ;continue with next valid
 
        add iy,de
 
        inc c
 
        jr SyHPFl2
 
 
 
SyHPFlb dw 0                ;recognized switches
 
endif
 
 
 
if use_SyShell_CHRINP=1
 
SyShell_CHRINP0 ld e,0
 
SyShell_CHRINP
 
;******************************************************************************
 
;*** Name           SymShell_CharInput_Command
 
;*** Input          E  = Channel (0=Standard, 1=Keyboard)
 
;*** Output         CF = Error state (0 = ok, 1 = error; A = error code)
 
;***                - If error status is 0
 
;***                ZF = EOF status (0=EOF)
 
;***                - If error status is 0 and there is no EOF:
 
;***                A  = Char
 
;*** Destroyed      F,BC,DE,HL,IX,IY
 
;*** Description    Reads a char from an input source. The input source can be
 
;***                the standard channel or the console keyboard. Usually the
 
;***                standard channel is the console keyboard, too, but it can also
 
;***                be a textfile or another source, if redirection or piping is
 
;***                active.
 
;***                If the keyboard is used, this function won't return as long as
 
;***                no key is pressed. If the user pressed Control+C or if the end
 
;***                of the file (EOF) has been reached, the EOF flag will be set.
 
;******************************************************************************
 
        ld bc,MSR_SHL_CHRINP*256+MSC_SHL_CHRINP
 
        call SyShell_DoCommand
 
        ret c
 
        ld a,(iy+2)
 
        ret
 
endif
 
 
 
if use_SyShell_STRINP=1
 
SyShell_STRINP0 ld e,0
 
SyShell_STRINP
 
;******************************************************************************
 
;*** Name           SymShell_StringInput_Command
 
;*** Input          E  = Channel (0=Standard, 1=Keyboard)
 
;***                HL = String buffer address (must have a size of 256 bytes)
 
;*** Output         CF = Error state (0 = ok, 1 = error; A = error code)
 
;***                - If error status is 0
 
;***                ZF = EOF status (0=EOF)
 
;***                - If error status is 0 and there is no EOF, the string
 
;***                  buffer contains the read line.
 
;*** Destroyed      F,BC,DE,HL,IX,IY
 
;*** Description    Reads a string from an input source. The input source can be
 
;***                the standard channel or the console keyboard. Usually the
 
;***                standard channel is the console keyboard, too, but it can also
 
;***                be a textfile or another source, if redirection or piping is
 
;***                active.
 
;***                The maximum lenght of a string is 255 chars, so the buffer must
 
;***                have a size of 256 bytes (255 + terminator). A string is always
 
;***                terminated by 0.
 
;***                If the keyboard is used, this function won't return until the
 
;***                user typed in a text line and pressed the Return key. If the
 
;***                user pressed Control+C or if the end of the file (EOF) has been
 
;***                reached, the EOF flag will be set.
 
;******************************************************************************
 
        ld bc,MSR_SHL_STRINP*256+MSC_SHL_STRINP
 
        ld a,(App_BnkNum)
 
        ld d,a
 
        jp SyShell_DoCommand
 
endif
 
 
 
if use_SyShell_CHROUT=1
 
SyShell_CHROUT0 ld e,0
 
SyShell_CHROUT
 
;******************************************************************************
 
;*** Name           SymShell_CharOutput_Command
 
;*** Input          E  = Channel (0=Standard, 1=Screen)
 
;***                D  = Char
 
;*** Output         CF = Error state (0 = ok, 1 = error; A = error code)
 
;*** Destroyed      F,BC,DE,HL,IX,IY
 
;*** Description    Sends a char to the output destination. The output destination
 
;***                can be the standard channel or the console text screen. Usually
 
;***                the standard channel is the console text screen, too, but it
 
;***                can also be a textfile or another destination, if redirection
 
;***                or piping is active.
 
;******************************************************************************
 
        ld bc,MSR_SHL_CHROUT*256+MSC_SHL_CHROUT
 
        jp SyShell_DoCommand
 
endif
 
 
 
if use_SyShell_STROUT=1
 
SyShell_STROUT0 ld e,0
 
SyShell_STROUT
 
;******************************************************************************
 
;*** Name           SymShell_StringOutput_Command
 
;*** Input          E  = Channel (0=Standard, 1=Screen)
 
;***                HL = String address (terminated by 0)
 
;*** Output         CF = Error state (0 = ok, 1 = error; A = error code)
 
;*** Destroyed      F,BC,DE,HL,IX,IY
 
;*** Description    Sends a string to the output destination. The output
 
;***                destination can be the standard channel or the console text
 
;***                screen. Usually the standard channel is the console text
 
;***                screen, too, but it can also be a textfile or another
 
;***                destination, if redirection or piping is active.
 
;***                A string has always to be terminated by 0.
 
;******************************************************************************
 
        ld a,(App_BnkNum)
 
        ld d,a
 
        push hl
 
        xor a
 
        ld bc,255
 
        cpir
 
        ld a,254
 
        sub c       ;A=string length
 
        pop hl
 
        ret z
 
        ld bc,MSR_SHL_STROUT*256+MSC_SHL_STROUT
 
        jp SyShell_DoCommand
 
endif
 
 
 
if use_SyShell_PTHADD=1
 
SyShell_PTHADD
 
;******************************************************************************
 
;*** Name           SymShell_PathAdd_Command
 
;*** Input          DE = address of base path (0=actual shell path)
 
;***                HL = address of additional path component
 
;***                BC = buffer address for new full path
 
;***                     (must have a size of 256 bytes)
 
;*** Output         DE = position behind last char in new path
 
;***                HL = position behind last / in new path
 
;***                A  = Bit[0]=1 -> new path ends with /
 
;***                     Bit[1]=1 -> new path contains wildcards
 
;*** Destroyed      F,BC,IX,IY
 
;*** Description    ...
 
;******************************************************************************
 
        ld a,(App_BnkNum)
 
        ld (App_MsgBuf+7),a
 
        ld a,b
 
        ld (App_MsgBuf+6),a
 
        ld b,c
 
        ld c,MSC_SHL_PTHADD
 
        call SyShell_SendMessage
 
SyHPtA1 call SyShell_WaitMessage
 
        cp MSR_SHL_PTHADD
 
        jr nz,SyHPtA1
 
        ld de,(App_MsgBuf+1)
 
        ld hl,(App_MsgBuf+3)
 
        ld a,(App_MsgBuf+5)
 
        ret
 
endif
 
 
 
SyShell_EXIT
 
;******************************************************************************
 
;*** Name           SymShell_Exit_Command
 
;*** Input          E  = Exit type (0 = quit, 1 = blur)
 
;*** Output         -
 
;*** Destroyed      AF,BC,DE,HL,IX,IY
 
;*** Description    The application informs SymShell about an exit event.
 
;***                If an application quits itself, SymShell has to be informed
 
;***                about that, so that it can remove the application from its
 
;***                internal management table. In this case the exit type has to be
 
;***                0 ("quit").
 
;***                If an application doesn't require the focus inside the text
 
;***                terminal anymore, it has to send exit type 1 ("blur"). The
 
;***                background is, that SymShell can run multiple applications in
 
;***                the same text terminal at the same time. User text inputs will
 
;***                only be sent to the application which has been started at first
 
;***                until it releases the focus and goes into blur mode. In this
 
;***                case the next application or the command line interpreter of
 
;***                the shell itself will receive the focus (the user can force the
 
;***                shell to get back focus at once by appending "&" at the end of
 
;***                the command line).
 
;******************************************************************************
 
        ld c,MSC_SHL_EXIT
 
        jp SyShell_SendMessage
 
 
 
 
 
;### SUB ROUTINES #############################################################
 
 
 
SyShell_SendMessage
 
;******************************************************************************
 
;*** Input          C  = Command
 
;***                DE = Parameter 1/2
 
;***                HL = Parameter 3/4
 
;***                B  = Parameter 5
 
;*** Output         -
 
;*** Destroyed      AF,BC,DE,HL,IX,IY
 
;*** Description    Sends a message to the SymShell process
 
;******************************************************************************
 
        ld iy,App_MsgBuf
 
        ld (iy+0),c
 
        ld (App_MsgBuf+1),de
 
        ld (App_MsgBuf+3),hl
 
        ld (iy+5),b
 
        ld a,(SyShell_PrcID)
 
        db #dd:ld h,a
 
        ld a,(App_PrcID)
 
        db #dd:ld l,a
 
        rst #10
 
        ret
 
 
 
SyShell_WaitMessage
 
;******************************************************************************
 
;*** Input          -
 
;*** Output         IY = message buffer
 
;***                A  = first byte in the Message buffer (IY+0)
 
;*** Destroyed      F,BC,DE,HL,IX
 
;*** Description    Waits for a response message from the SymShell process.
 
;******************************************************************************
 
        ld iy,App_MsgBuf
 
SyHWMs1 ld a,(SyShell_PrcID)
 
        db #dd:ld h,a
 
        ld a,(App_PrcID)
 
        db #dd:ld l,a
 
        rst #08             ;wait for a SymShell message
 
        db #dd:dec l
 
        jr nz,SyHWMs1
 
        ld a,(iy+0)
 
        ret
 
 
 
SyShell_DoCommand
 
;******************************************************************************
 
;*** Input          C       = Command
 
;***                DE,HL,A = additional parameters
 
;***                B       = Response type
 
;*** Output         CF      = Error state (0 = ok, 1 = error, A = error code)
 
;***                ZF      = EOF status (0=EOF) [optional]
 
;*** Destroyed      F,BC,DE,HL,IX,IY
 
;*** Description    Executes a complete SymShell command.
 
;******************************************************************************
 
        push bc
 
        ld b,a
 
        call SyShell_SendMessage
 
        pop bc
 
SyHGRs1 push bc
 
        call SyShell_WaitMessage
 
        pop bc
 
        cp b
 
        jr nz,SyHGRs2
 
        ld a,(iy+3)     ;Error state
 
        ld c,(iy+1)     ;EOF (0=no eof)
 
        cp 1
 
        ccf             ;CF=0 no error
 
        inc c
 
        dec c           ;ZF=0 EOF
 
        ret
 
SyHGRs2 push bc         ;wrong message (from another event) -> re-send
 
        ld a,(SyShell_PrcID)
 
        db #dd:ld l,a
 
        ld a,(App_PrcID)
 
        db #dd:ld h,a
 
        rst #10
 
        rst #30
 
        pop bc
 
        jr SyHGRs1