StringField() for the commandline :-)

Share your advanced PureBasic knowledge/code with the community.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

StringField() for the commandline :-)

Post by blueznl »

Process a string as if it was a command line... Duh.

This works a bit like StringField, except that it 1. uses only spaces as seperators, 2. trims excess spaces, 3. passes spaces that are enclosed between doublequotes.

Where do I use it? When I have a program that takes commandline parameters I typically read all those parameters into a linked list. Now I don't want to fill such a list by hand :-)

Code: Select all

Procedure.s commandfield(string.s,index.i,stripquotes.i=0)
  Protected l.i, field.i, inside.i, p_start.i, p.i
  ;
  ; *** returns space seperated fields, keeps double quoted sections whole
  ;
  ; in:       string.s                - string to parse
  ;           index.i                 - field to return
  ;           stripquotes.i = #true   - include encompassing quotes in return value
  ; retval:   .s                      - string matching the index number
  ;
  ; a 'command line string' contains multiple sections, of which some are enclosed in parenthesis
  ; this routine splits up and spits out :-) space seperated sections, where spaces in doublequoted
  ; parts are ignored
  ;
  l = Len(string)
  field = 0
  inside = #False
  p_start = 1
  p = 0
  While p < l And field <> index
    p = p+1
    Select Asc(Mid(string,p,1))
    Case ' '                        ; it's a space
      If Not inside                 ; but we're not inside so it counts as a seperator
        If p = p_start              ; we just started so it must be two spaces following eachother
          p_start = p+1             ; next char should be a non-space, otherwise we end up here again
        Else
          field = field+1           ; so we just passed a valid field
          If field <> index         ; if it wasn't the field we were looking for
            p_start = p+1           ; then we'll set the start pointer to the start of the next field
          EndIf
        EndIf
      EndIf
    Case '"'                        ; toggle for doublequoted sections
      inside = 1-inside
    EndSelect
  Wend
  If field <> index And p = l       ; reached the end of the string
    field = field+1
    p = p+1
  EndIf
  If field = index                                               ; we had a match
    If stripquotes <> 0 And Mid(string,p_start,1)=#DQUOTE$       ; optional stripping of doublequotes
      ProcedureReturn Trim(Mid(string,p_start+1,p-p_start-2))
    Else
      ProcedureReturn Mid(string,p_start,p-p_start)              ; no stripping
    EndIf
  Else
    ProcedureReturn ""
  EndIf
EndProcedure

Procedure.i commandcount(string.s)
  Protected l.i, field.i, inside.i, p_start.i, p.i
  ;
  ; *** returns the number of space seperated fields, keeps double quoted sections whole
  ;
  ; in:       string.s                - string to parse
  ; retval:   .s                      - string matching the index number
  ;
  ; a 'command line string' contains multiple sections, of which some are enclosed in parenthesis
  ; this routine counts how many are valid, which can be used with commandfield()
  ;
  l = Len(string)
  field = 0
  inside = #False
  p_start = 1
  p = 0
  While p < l
    p = p+1
    Select Asc(Mid(string,p,1))
    Case ' '                        ; it's a space
      If Not inside                 ; but we're not inside so it counts as a seperator
        If p = p_start              ; we just started so it must be two spaces following eachother
          p_start = p+1             ; next char should be a non-space, otherwise we end up here again
        Else
          field = field+1           ; so we just passed a valid field
          p_start = p+1           ; then we'll set the start pointer to the start of the next field
        EndIf
      EndIf
    Case '"'                        ; toggle for doublequoted sections
      inside = 1-inside
    EndSelect
  Wend
  If p+1 <> p_start
    field = field+1
  EndIf
  ProcedureReturn field
EndProcedure
Example:

Code: Select all

c.s = "one two three "+#DQUOTE$+"four five"+#DQUOTE$+" six"
Debug commandcount(c.s)
Debug commandfield(c.s,4)
Here's a part of another program that shows how I use it...

Code: Select all

...
  command_n = 0
  If #codecaddy_compilerun
    ;
    ; set up command_test.s for quick testing from withing the IDE
    ;
    ; command_string.s = "blue fade font Arial 100 text CLIENT|~host~-~ip~"
    ; command_string.s = "help"
    command_string = "help"
    ; command_string = "mark test"
    ; command_string.s = "pink mark XPS710 save nearby"
    ;
    command_n = commandcount(command_string)
    n = 0
    While n < command_n
      n = n+1
      AddElement(command())
      command.s() = commandfield(command_string,n,1)
    Wend
    ;
  EndIf
  If command_n = 0
    ;
    ; use command line parameters
    ;
    command_n = CountProgramParameters()
    n = 0
    While n < command_n
      n = n+1
      AddElement(command())
      command.s() = ProgramParameter()
    Wend
    ;
  EndIf
...
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: StringField() for the commandline :-)

Post by Thorium »

Thank you, very usefull. Writing a file converter that takes a list file with file names. With your procedures it can thread the lines in the list file like a command line. Very very usefull for storing parameters for conversion and the file name of the file to convert in the same line.
Post Reply