Author Topic: Parsing the Command Line  (Read 6187 times)

0 Members and 1 Guest are viewing this topic.

Offline freetrav

  • Newbie
  • Posts: 45
    • View Profile
Parsing the Command Line
« on: June 08, 2018, 10:34:14 am »
QB64 provides COMMAND$ for retrieving the parameters that a program is invoked with. However, the model that it provides is the pure positional method - that is, COMMAND$(1) is $1, COMMAND$(2) is $2 (or %1 and %2 in a DOSWIN environment), and so on.

PowerShell, on the other hand, has intelligent parameter processing. Parameters are named, the names are aliasable, the unaliased name can be used as a variable in the PowerShell script, and the order in which they are supplied is not mandated. Additionally, it allows for "Intelligent minimization", where only enough of the parameter name is required to ensure uniquely identifying the parameter.

Is there a set of routines somewhere that implements PowerShell-style parameter handling for QB64? It doesn't have to be as perfectly transparent as PowerShell, but I'd like to be able to say things like COUNT% = PARAMETER("COUNT", INTEGER), and have it parse out the command line for the string -Count or /count  (not case sensitive), or even /C if it's unique, and find and return the integer following it.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Parsing the Command Line
« Reply #1 on: June 08, 2018, 12:25:52 pm »
Hi freetrav,

Welcome to the forum!

Have you checked out the Wiki on this subject? I just did and from COMMAND$, picked up on something new to me:
_COMMANDCOUNT
http://qb64.org/wiki/COMMANDCOUNT

My first reaction is that this is a job for a custom designed function or sub. For which I can offer a nice Split procedure for parsing a string by any delimiter into array if you are interested.

Offline freetrav

  • Newbie
  • Posts: 45
    • View Profile
Re: Parsing the Command Line
« Reply #2 on: June 08, 2018, 01:00:55 pm »
Have you checked out the Wiki on this subject? I just did and from COMMAND$, picked up on something new to me:
_COMMANDCOUNT
http://qb64.org/wiki/COMMANDCOUNT

My first reaction is that this is a job for a custom designed function or sub. For which I can offer a nice Split procedure for parsing a string by any delimiter into array if you are interested.

Yes, I'd seen _COMMANDCOUNT; as it states, it's the argc to the C *argv[] represented by COMMAND$. That's still pure positional parameter management. With PowerShell, if a cmdlet foo takes the parameters -bar <string> and -quux <integer>, it doesn't matter if I invoke it as foo -bar "none" -quux 3 or foo -quux 3 -bar "none" or foo -b "none" -q 3; I still have established that (within the code of foo) $bar is "none" and $quux is 3.

What I'm hoping to find is a way to process COMMAND$ with a "standard" set of routines that will allow me that sort of flexibility, so that my code for FOO.QB64 could start with a couple of statements like

Code: QB64: [Select]
  1. BAR$ = _STRING_PARAMETER("bar")
  2. QUUX% = _INTEGER_PARAMETER("quux")
  3.  

and have it manage the parsing of COMMAND$ to offer PowerShell-style flexibility. Linux getopts offers something similar for bash scripts.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Parsing the Command Line
« Reply #3 on: June 08, 2018, 01:33:33 pm »
Yes, it sure looks like you are talking command$ = "key1 = value ~ key2 = value2 ~key3 = value3 ~  ..."

Split(command$, toArray$, "~") becomes

toArray$(0) = "key1 = value1"
toArray$(1) = "key2 = value2"
toArray$(2) = "key3 = value3"
...

Now split again to two arrays key(index) and value(index) connected by index number.

Or get the value you want according to the key you are looking for by reading through toArray$ for the value found before a 2nd delimiter.

Caveat: strings could not be enclosed by "

It's a two delimiter system, the first ( a comma is typical but since command line stuff use something unlikely like ~) divides the string into key value pairs, the 2nd (= or - whatever) separates the key from the value.



Of course now you might say "~" is not standard, and using " for a string " is standard. Oh well...
« Last Edit: June 08, 2018, 01:42:14 pm by bplus »

FellippeHeitor

  • Guest
Re: Parsing the Command Line
« Reply #4 on: June 08, 2018, 08:40:57 pm »
There:

Code: QB64: [Select]
  1.  
  2. bar$ = strParameter("bar")
  3. quux% = intParameter("quux")
  4.  
  5. PRINT "You passed:"
  6. PRINT "    1- "; bar$
  7. PRINT "    2- "; quux%
  8.  
  9.  
  10. FUNCTION strParameter$ (which$)
  11.     FOR i = 1 TO _COMMANDCOUNT - 1
  12.         IF UCASE$("-" + which$) = UCASE$(COMMAND$(i)) THEN
  13.             strParameter$ = COMMAND$(i + 1)
  14.             EXIT FUNCTION
  15.         END IF
  16.     NEXT
  17.  
  18. FUNCTION intParameter% (which$)
  19.     intParameter% = VAL(strParameter$(which$))
  20.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Parsing the Command Line
« Reply #5 on: June 08, 2018, 08:53:20 pm »
Oh heck! COMMAND$(index) already has done the parsing for us!

After studying the problem more I get this simple little thing:
Code: QB64: [Select]
  1. ' keys are oddly indexed but in any order
  2.     SELECT CASE LEFT$(COMMAND$(c), 2) 'check shortest identifiable variable key
  3.         CASE "-b": bar$ = COMMAND$(c + 1) 'the value comes right after the key
  4.         CASE "-q": quux% = VAL(COMMAND$(c + 1))
  5.             'CASE ...    'continue in this manner
  6.     END SELECT
  7.  
  8.  
  9.  
« Last Edit: June 08, 2018, 08:57:30 pm by bplus »

Offline freetrav

  • Newbie
  • Posts: 45
    • View Profile
Re: Parsing the Command Line
« Reply #6 on: June 11, 2018, 08:36:39 am »
OK, so it looks like I'm going to have to write my own routines (I want to say "library", but that seems to have a slightly different meaning wrt QB64 than I intend) to manage the parsing. I was hoping that something had already been done. Doable, and not even majorly difficult (COMMAND$( ) does some of the most important work; I just need to handle the type conversion and the "smart abbreviating"). When I cease to have too much hands on my time, I'll share on the forum.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Parsing the Command Line
« Reply #7 on: June 11, 2018, 09:16:05 am »
I don't see how "rolling your own" could be avoided. Only you know the switches you wish to use and the shortest ID key press or combo that could be allowed and still work. But COMMAND$(index) does do the heavy lifting with parsing.

What might be interesting though, write a routine that takes a given string and it takes a stab at deciding the type value the string might be representing.
eg
if it starts with numbers it is likely a number, if it has a decimal then a real number or float.
If it starts with " then must be string and if it starts with / maybe a file or path ? (for Windows or Linux, I confuse / with \ because Windows does.)

But the -keys or switches would tell "for sure!" the type that is expected, and aren't these specific to the needs of the application of the coder?

Offline freetrav

  • Newbie
  • Posts: 45
    • View Profile
Re: Parsing the Command Line
« Reply #8 on: June 12, 2018, 08:03:36 am »
I don't see how "rolling your own" could be avoided. Only you know the switches you wish to use and the shortest ID key press or combo that could be allowed and still work. But COMMAND$(index) does do the heavy lifting with parsing.

That's the idea behind the (I still want to say "library"). The switch that I'm looking for in a particular program gets passed as a parameter to the call to e.g., String_Parameter(), and then String_Parameter() scans through COMMAND$, and returns the value. The implementation of String_Parameter() handles the minimal-unique-leading-substring and any other relevant magic that would be needed for the general parsing; the handling within the specific program is program-specific - but the retrieval isn't.

In other words, String_Parameter() doesn't change; it's the same code to retrieve the -quux parameter in this program as it is to retrieve the -potrzebie parameter in that program - all that changes is the parameter passed to the call to String_Parameter().

FellippeHeitor

  • Guest
Re: Parsing the Command Line
« Reply #9 on: June 12, 2018, 08:19:31 am »
Aside from handling reduced forms, I don't see how the code I gave you doesn't do what you're asking. Did you try it?

Offline freetrav

  • Newbie
  • Posts: 45
    • View Profile
Re: Parsing the Command Line
« Reply #10 on: June 12, 2018, 09:22:48 am »
Aside from handling reduced forms, I don't see how the code I gave you doesn't do what you're asking. Did you try it?
Not yet; see "too much hands on my time" :) From inspection, though, it's a start on what I want; I'd need to add the logic for allowing "-quux" to be abbreviated to "-q" if that's sufficient to guarantee uniqueness within the program. The more I think about the problem, the more "enhancement" I'm finding I want; really, to see my ultimate aim, read up on how PowerShell handles parameters.
« Last Edit: June 12, 2018, 09:28:46 am by freetrav »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Parsing the Command Line
« Reply #11 on: June 12, 2018, 09:55:41 am »
Hi Fellippe,

I am getting the impression he wants to create variable names and values on the fly (at run time after program is compiled).

I will reread again:

Freetrav wants a function String_Parameter$(switch$) st.

Code: QB64: [Select]
  1. FUNCTION String_Parameter$ (switch$, fromLeft%)
  2.     FOR c = 1 TO _COMMANDCOUNT STEP 2
  3.         IF LEFT$(switch$, fromLeft%) = LEFT$(COMMAND$(c), fromLeft%) THEN 'check shortest identifiable variable key
  4.             String_Parameter$ = COMMAND$(c + 1)
  5.             EXIT FUNCTION
  6.         END IF
  7.     NEXT

Functions require one type or another to return but strings are easily converted to numbers if the specific program requires a number for a given switch. To use with numbers, the following converts into integer as example:

myNumber% = INT(VAL(String_Parameter$(mySwitch$)))

I suppose a 2nd parameter might be used to say how far from the left the switch word matches the command line word.

EDIT: OK since the function above turns out to be basically what Fellippe already had, I added a fromLeft% parameter for number of matches from left needed to ID the switch as the one intended for specific program.
« Last Edit: June 12, 2018, 10:23:54 am by bplus »

FellippeHeitor

  • Guest
Re: Parsing the Command Line
« Reply #12 on: June 12, 2018, 10:07:41 am »
I gave him both a string and an integer functions, he can take it and improve upon it if desired, the beauty of open source collaboration.

*flies away*

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Parsing the Command Line
« Reply #13 on: June 12, 2018, 10:15:40 am »
Dang, sorry, I did not understand what you, Fellippe, had worked out already until I worked out the same basically. The 2nd function threw me off. Well I will update mine with a fromLeft parameter.
« Last Edit: June 12, 2018, 10:21:03 am by bplus »