[Gambas-user] a command line with arguments to parsed program?

Bruce adamnt42 at gmail.com
Wed Oct 16 09:43:05 CEST 2019


Ok, lets get this sorted.

First off, the difference between OPTIONS and ARGUMENTS. I'll use 
something we all have as an example. In a virtual terminal type
	gbc3 -h
You should get something like:

Compile Gambas projects into architecture-independent bytecode.

Usage: gbc3 [options] [<project directory>]

Options:
   -g  --debug                add debugging information
   -v  --verbose              verbose output
   -a  --all                  compile all
   -w  --warnings             display warnings
   -t  --translate            output translation files and compile them 
if needed
   -p  --public-control       form controls are public
   -m  --public-module        module symbols are public by default
   -s  --swap                 swap endianness
   -r  --root <directory>     gives the gambas installation directory
   -e  --translate-errors     display translatable error messages
   -x  --exec                 executable mode (define the 'Exec' 
preprocessor constant and remove assertions)
   -V  --version              display version
   -L  --license              display license
   -h  --help                 display this help

On the "Usage" line note that the program accepts optionally both 
OPTIONS and ARGUMENTS. In fact it uses 1 ARGUMENT the <project 
directory>, which is mandatory in almost all cases..

Below that line is a list of the OPTIONS that can be used.

Why is this important? Because the native Args class provided by the 
"gb" component considers the whole command line as a space delimited 
list of ARGUMENTS (no OPTIONS handling is done and it would be up to the 
program code to decipher each token and decide what it is and how to 
work with it.

Enter the "gb.args" component.

This component provides much more sophisticated handling of OPTIONS. The 
program ARGUMENTS are still returned as a read only array.

There are two types of OPTIONS.
The first I'll call "flags". These are OPTIONS that stand alone. Their 
presence in the command line or absence signifies something by itself. 
Almost all the gbc3 OPTIONS are flags. In fact all but the -r/--root 
options are flags.
The second type I'll call "value" options.
The -r/--root option requires a <directory> value i.e. a string value. 
Other value options you may want in your program could be floats or 
integers.

So hopefully now we are clear on the difference between OPTIONS and 
ARGUMENTS.

But one final note. All the header lines in the above gbc3 -h output 
above the
	Options:
line are "usage" comments.

So, what does gb.args provide?

It exposes one class, "Args" as explained in the help page that performs 
a lot of work for your CLI projects without having to code it yourself.

Firstly the simple one - the -V/--version OPTION is automatically 
handled, just by having the gb.args component included.

Secondly the -h/--help OPTION is handled automatically and also you can 
provide very sophisticated information about you program by using the 
gb.args "algorithm" below.

In your program startup module, i.e. the Main sub, (or a routine called 
by Main (to keep things nicely compartmentalised) we need to do the 
following:
	1) Start the CLI options/arguments handler
	2) Test for the presence of each of your program OPTIONS and where 
applicable, get their values
	3) Tell the handler to stop parsing and return THE REST of the CLI 
input as a set of ARGUMENTS in a string array.

so, by way of examplle:

Private Sub ParseCLI()

	Args.Begin("This is my brilliant program")
	' This is step 1, it "starts the program argument analysis".

But it also takes a string argument that is the "usage" header printed 
when the -h option is included by the user on the command line. That is 
all you have to do to get your program to display as sophisticated a 
"usage" header as you require is to include it as a single string in the 
Args.Begin call. For example

   Dim sHeader As String = "mygbproject\n===========\n\nMy brilliant 
Gambas project\n\nUsage: mygbproject [options] "

   Args.Begin(sHeader)

would result in a -h ouput usage header like:

mygbproject
===========

My brilliant Gambas project

Usage: mygbproject <options>

Options: etc....


Now what sort of options do we want? Lets start with a simple "flag" 
that if present on the command line will cause you program to print out 
lots of debugging information as it runs. Let's say we are going to use 
-d/--debug.  The way to test whether the user wants the debug output is 
to test for this flag using the Args.Has() function. So:

	$outputDebug = Args.Has("d","debug","If present the program will output 
lots of debugging information to the terminal")

Noting that Args.Has() returns a boolean (that we will set a global 
variable so we can use it later where necessary). You also see the 
ShortName, LongName and Description parameters populated such that the 
-h output will now show :

mygbproject
===========

My brilliant Gambas project

Usage: mygbproject <options>

Options:

  -d --debug             If present the program will output lots of 
debugging information to the terminal
  -V --Version                   Display version
  -h --help                      Display this help

Let's change our mind and provide three different levels of debug 
output. This time we use an integer value option as follows:

	$debugLevel = Args.GetInteger("d", "debug", "The program will output 
lotsheaps or tins of debugging information to the terminal", "level", 1)

With this, if the user species the -d/--debug <int> pair on the command 
line the $debugLevel value will be set to that value. (if they only 
provide the option without a value then it will be set to 1 - automagically!

The -h output will now look like:

mygbproject
===========

My brilliant Gambas project

Usage: mygbproject <options>

Options:

  -d --debug <level>     The program will output lots or heaps or tons 
of debugging information to the terminal (default=1)
  -V --Version                   Display version
  -h --help                      Display this help

Hmm, we can do better than that! Is 1 equal to "lots" or "tons"?

Lets try a string value option:

	$debugLevelStr = Args.Get("d", "debug", "The program will output lots 
(L) or heaps (H) or tons (T) of debugging information to the terminal", 
"level")

If present then the $debugLevelStr value will be set to the value 
provided (NOTE! the gb.args Args.Get() function does NOT provide a 
default value!). And the -h output will look like:

mygbproject
===========

My brilliant Gambas project

Usage: mygbproject <options>

Options:

  -d --debug <level>     The program will output lots (L) or heaps (H) 
or tons (T) of debugging information to the terminal
  -V --Version                   Display version
  -h --help                      Display this help


Args.GetFloat() acts similarly to Args,GetInteger.

Now there is only one thing left, the Args.End() call. This handles the 
program ARGUMENTS exactly as specified in the help page, So,

	$myArgs = Args.End()

It would be usual to indicate the ARGUMENTS in the usage header 
indicating whether they are optional and whether multiple values are 
handled. Say we need one or more file names as ARGUMENTS. Then something 
like

mygbproject
===========

My brilliant Gambas project

Usage: mygbproject <options> [filename]...

Options:

  -d --debug <level>     The program will output lots (L) or heaps (H) 
or tons
  (T) of debugging information to the terminal
  - -- <<new>>
  -V --Version                   Display version
  -h --help                      Display this help

would be appropriate.

I think that's about the simplest I can put it.  When you consider the 
amount of code you would have to write to handle the above using the 
simple gb Args class, it's quite amazing actually.

hth
bruce


More information about the User mailing list