! fnswitches.bsi [108] - Parse command line switches
!-------------------------------------------------------------------------
!Edit History
! [108] 20-Sep-23 / jdm / Add Fn'Get'Switch'Ary()
! [107] 19-Sep-23 / jdm / strip trailing blanks from switches
! [106] 06-Sep-23 / jdm / add keywords for sosfuncidx, minor modernization
! [105] 26-Mar-20 / jdm / Increase max # args from 20 to 50, add Fn'Get'SwitchesOp()
! [104] 08-Oct-18 / jdm / minor source modernization
! [103] 10-Apr-12 / jdm / Don't quit until 2 empty switches in a row (not just 1) 
! [102] 18-Jun-11 / jdm / Convert all args to variable length and use just an array,
!                           eliminating the explicit references to the return switch args
!                           from the formal param list
! [101] 25-Nov-08 / jdm / Fix illegal subscript loophole
! [100] 06-Nov-08 / jdm / created
!---------------------------------------------------------------------
! Keywords: tokenization parsing command-line
!
! Public functions
! Fn'Get'Switches()   - Standard version
! Fn'Get'SwitchesOp() - Expanded variation with op argument
! Fn'Get'Switches'Ary() - Array version [108]
!---------------------------------------------------------------------
++ifndef MAX_GET_SWITCHES      ! avoid including more than once
  define MAX_GET_SWITCHES = 50      ! [105]
!-------------------------------------------------------------------------
! Function: 
!   Parse command line switches
!Parameters:
!   cmdlin  [s0,in]   - command line to parse (can be CMDLIN)
!   fdelims [s0,in]   - list of (single char) delimiters
!   arg     [s0,out]  - first part of passed line (prior to switches)
!   swN     [s0,out]  - switches individually returned (up to 20)
!                       [108] or could be an auto_extend array passed by ref
!Returns:
!   # of switches actually processed (up to 20)
!   <0 for error
!Notes:
!   Eg.  Passing the following line with "/" for the delimiter:
!     IMGDSX /T:title/B/E/X/A:1234 /C:SYM="A/B"
!   would return arg="IMGDSX", following by individual arguments
!   "T:title", "B", "E", "X", "A:1234 " and "C:SYM=""A/B"""
!-------------------------------------------------------------------------
![102] Function Fn'Get'Switches(cline as s80, fdelims as s80, arg as s80, &
!           s1 as s80, s2 as s80, s3 as s80, s4 as s80, s5 as s80, &
!           s6 as s80, s7 as s80, s8 as s80, s9 as s80, s10 as s80, &
!           s11 as s80, s12 as s80, s13 as s80, s14 as s80, s15 as s80, &
![102]      s16 as s80, s17 as s80, s18 as s80, s19 as s80, s20 as s80) as i2
![102] We're removing the output-only switches from the formal argument 
![102] list; we can detect how many there were from .argcnt, although
![102] even that is unnecessary here since we will explicitly tell the 
![102] caller how many switches we processed
!-------------------------------------------------------------------------
Function Fn'Get'Switches(cline as s0:inputonly, fdelims as s0:inputonly, arg as s0) as i2
    map1 locals
        map2 args,b,2,.argcnt       ! copy .argcnt to loc var (before it gets changed)
        map2 op,b,1,2               ! strtok opcode (2=recognize quoting)
        map2 rdelim,s,2,""          ! no record delimiters
        map2 i,i,2
![102]    map1 soverlay,@s1                ! overlay the virtual map1 s*,s,80 array
![102]        map2 sx(MAX_GET_SWITCHES),s,80
    map1 sx(MAX_GET_SWITCHES),s,0          ! [102]
    xcall STRTOK,op,cline,fdelims,arg,rdelim, &
        sx(1),sx(2),sx(3),sx(4),sx(5),sx(6),sx(7),sx(8),sx(9),sx(10), &
        sx(11),sx(12),sx(13),sx(14),sx(15),sx(16),sx(17),sx(18),sx(19),sx(20), &
        sx(21),sx(22),sx(23),sx(24),sx(25),sx(26),sx(27),sx(28),sx(29),sx(20), &
        sx(31),sx(32),sx(33),sx(34),sx(35),sx(36),sx(37),sx(28),sx(29),sx(30), &
        sx(41),sx(42),sx(43),sx(44),sx(45),sx(46),sx(47),sx(28),sx(29),sx(50)
    ! note that xputarg will not have any effect on args
    ! which were not passed to us, so we'll just return
    ! as many as we parsed.  if we wanted, we could use
    ! the .argcnt info to limit the return to only those
    ! args which will be processed by the caller.
    xputarg 3,strip(arg)        ! [107] 
    i = 1
    ![101] do while (i <= MAX_GET_SWITCHES) and (sx(i) # "")
    ![101] need to split up the 'and' since Basic always executes both sides
    ![101] so sx(i) would err out if i > MAX_GET_SWITCHES
    do while (i <= MAX_GET_SWITCHES)
        xputarg i+3,strip(sx(i))        ! [107]
        ! [101][102] quit after 1st null switch
        ! [103] Chg to quit after a pair of null switches
        if (sx(i) = "") and (i = MAX_GET_SWITCHES or sx(i+1) = "") exit         
        i = i + 1
    loop
    Fn'Get'Switches = i - 1
EndFunction
![105]
!-------------------------------------------------------------------------
! Function: 
!   Parse command line switches (variation)
!Parameters:
!   
!   cmdlin  [s0,in]   - command line to parse (can be CMDLIN)
!   fdelims [s0,in]   - list of (single char) delimiters
!   op      [b1,in]   - strtok opcode (default 2)
!   arg     [s0,out]  - first part of passed line (prior to switches)
!   swN     [s0,out]  - switches individually returned (up to 20)
!Returns:
!   # of switches actually processed (up to 20)
!   <0 for error
!Notes:
!   Eg.  Passing the following line with "/" for the delimiter:
!     IMGDSX /T:title/B/E/X/A:1234 /C:SYM="A/B"
!   would return arg="IMGDSX", following by individual arguments
!   "T:title", "B", "E", "X", "A:1234 " and "C:SYM=""A/B"""
!-------------------------------------------------------------------------
Function Fn'Get'SwitchesOp(cline as s0:inputonly, fdelims as s0:inputonly, &
                            op=2 as b1:inputonly, arg as s0) as i2
    map1 locals
        map2 args,b,2,.argcnt       ! copy .argcnt to loc var (before it gets changed)
        map2 rdelim,s,2,""          ! no record delimiters
        map2 i,i,2
    map1 sx(MAX_GET_SWITCHES),s,0          
    xcall STRTOK,op,cline,fdelims,arg,rdelim, &
        sx(1),sx(2),sx(3),sx(4),sx(5),sx(6),sx(7),sx(8),sx(9),sx(10), &
        sx(11),sx(12),sx(13),sx(14),sx(15),sx(16),sx(17),sx(18),sx(19),sx(20), &
        sx(21),sx(22),sx(23),sx(24),sx(25),sx(26),sx(27),sx(28),sx(29),sx(20), &
        sx(31),sx(32),sx(33),sx(34),sx(35),sx(36),sx(37),sx(28),sx(29),sx(30), &
        sx(41),sx(42),sx(43),sx(44),sx(45),sx(46),sx(47),sx(28),sx(29),sx(50)
    ! note that xputarg will not have any effect on args
    ! which were not passed to us, so we'll just return
    ! as many as we parsed.  if we wanted, we could use
    ! the .argcnt info to limit the return to only those
    ! args which will be processed by the caller.
    xputarg 4,strip(arg)                ! [107] 
    i = 1
    do while (i <= MAX_GET_SWITCHES)
        !trace.print sx(i)
        xputarg i+4,strip(sx(i))        ! [107] 
        if (sx(i) = "") and (i = MAX_GET_SWITCHES or sx(i+1) = "") exit         
        i = i + 1
    loop
    Fn'Get'SwitchesOp = i - 1
EndFunction
![108]
!-------------------------------------------------------------------------
! Function: 
!   Parse command line switches (variation using array syntax)
!Parameters:
!   
!   cmdlin  [s0,in]   - command line to parse (can be CMDLIN)
!   fdelims [s0,in]   - list of (single char) delimiters
!   op      [b1,in]   - strtok opcode (default 2)
!   arg     [s0,out]  - first part of passed line (prior to switches)
!   sw()    [s0(),out byref]  - switches array (auto_extend)
!Returns:
!   # of switches actually processed
!   <0 for error
!Notes:
!   Eg.  Passing the following line with "/" for the delimiter:
!     IMGDSX /T:title/B/E/X/A:1234 /C:SYM="A/B"
!   would return arg="IMGDSX", following by individual arguments
!   "T:title", "B", "E", "X", "A:1234 " and "C:SYM=""A/B"""
!
!   [108] This version is cleaner for the caller, but since we don't 
!   currently have a way to pass an auto_extend array byref to an internal
!   SBR, the implementation is actually messier than the standard version.
!   (But that may still be a good tradeoff for the caller.)
!-------------------------------------------------------------------------
Function Fn'Get'Switches'Ary(cline as s0:inputonly, fdelims as s0:inputonly, &
                            op=2 as b1:inputonly, arg as s0:outputonly, sw() as s0) as i2
    map1 locals
        map2 rdelim,s,2,""          ! no record delimiters
        map2 i,i,2
    map1 sx(MAX_GET_SWITCHES),s,0          
    xcall STRTOK,op,cline,fdelims,arg,rdelim, &
        sx(1),sx(2),sx(3),sx(4),sx(5),sx(6),sx(7),sx(8),sx(9),sx(10), &
        sx(11),sx(12),sx(13),sx(14),sx(15),sx(16),sx(17),sx(18),sx(19),sx(20), &
        sx(21),sx(22),sx(23),sx(24),sx(25),sx(26),sx(27),sx(28),sx(29),sx(20), &
        sx(31),sx(32),sx(33),sx(34),sx(35),sx(36),sx(37),sx(28),sx(29),sx(30), &
        sx(41),sx(42),sx(43),sx(44),sx(45),sx(46),sx(47),sx(28),sx(29),sx(50)
    arg = strip$(arg)
    xputarg @arg
    .clear sw()    
    ! [108] manually transfer the switches from the fixed array to the auto_extend version
    i = 1
    do while (i <= MAX_GET_SWITCHES)
        if (sx(i) = "") and (i = MAX_GET_SWITCHES or sx(i+1) = "") then
            exit
        else
            sw(i) = sx(i)
        endif
        i = i + 1
    loop
    ! [108] no need to pass back the switches (array was passed by ref)
    .fn = .extent(sw())
EndFunction
++endif
