Jump to content
Lars Fosdal

Generic Command Line Parser for Delphi 10.3.x

Recommended Posts

I have my own parsing solution, works exactly as I need it to, but it's not as robust as I would like it to be. I will try this one as soon as I have some time!

Share this post


Link to post

Yet another one. 😉

 

I guess sooner or later everybody ends up writing his own, because the built in one is/was not up to par and none of the publicly available ones was popular enough. (When I wrote mine in 2006 I searched for an existing solution that fit my needs and found none.)

 

Here is mine:

https://osdn.net/projects/dzlib-tools/scm/svn/blobs/head/dzlib/trunk/src/u_dzCmdLineParser.pas

 

It allows to register options with and without parameters as well as parameters and can generate help for them. The latter was the feature I was missing with any existing solutions I found.

  • Like 1

Share this post


Link to post

Mine can also quite easily be extended with a short / long description per parameter. 

Share this post


Link to post
29 minutes ago, Микола Петрівський said:

I was expecting to see at least built in support for "--help" and "--version". As it is now, it is not much different to FindCmdLineSwitch.

Except for supporting multiple parameters per option, parameters with spaces, default values, as well as the implicit conversion of ints, floats and enumerated types? 

 

Help would require declaring each command-line option, and help could include short text, long text, as well as examples.

I had to stop somewhere, and since my apps mostly are services or GUI apps, documenting the command line was low on the priority list.

 

As for Version, I suppose there would be as many requirements for what to display (file version, product version, file name, product name, copyright, libs, attributions, etc,) as there are users of the code.
Also - how would you handle those for a GUI app?
 

Other extensions could be to say that an option was mandatory, and if it should be a secret parameter that should be included in the help or not.

It would be trivial to create a specific TFileNameOption that checked that a filename only contained valid characters.

How about a TDateTimeOption?  Cross-option validation?

 

All is possible, and you have the source code and permission to change and build on it.

  • Thanks 1

Share this post


Link to post

@Lars Fosdal

I tried your FDC.CommandLine but I'm not getting correct results for this example:

 

parameter:

-strings="String A, StringB,StringC, String D and E"

I only get value before first space:

 

'String'

 

when using this:

 

vCMDNew   := TCommandLine.Create;
vStrings1 := vCMDNew.AsString('strings');

 

More:

2019-12-29_20-49-25.thumb.png.9061563c601b60ebb0b51889a9b96e7b.png

Share this post


Link to post

@Mike Torrettinni

 

I updated the gist at https://gist.github.com/LarsFosdal/f8a3e2a7caa5e541e4c04f10dfdfcfff with an extra Analyze function that writes a clearer breakdown of the parsing.

and added your example and a modified version of it to the test app.

 

As far as I can tell, it works as expected?

Your example: /strings="String A, StringB,StringC, String D and E"'

is a single string param.

The test output:

 

Parse(' /strings="String A, StringB,StringC, String D and E"')
1 Switch[/] Option[strings] Flag[=] Values["String A, StringB,StringC, String D and E"]

AsString('strings'): String A, StringB,StringC, String D and E

ClientIdentifier =

 

My modification of your example: /strings=(String A, StringB,StringC, String D and E)

is an array of strings.  Note the use of parenthesis to indicate multiple arguments.

 

Parse(' /strings=(String A, StringB,StringC, String D and E)')
1 Switch[/] Option[strings] Flag[=] Values[("String A";StringB;StringC;"String D and E")]

AsString('strings'): String A

ClientIdentifier =

 

 

Share this post


Link to post

Thank you, but I should have been more clear with the details: I use Delphi 10.2.3 and I thought only inline variables needed changing. Perhaps there are other incompatibilities, even if it compiles OK.

I will try again, when I upgrade Delphi (probably 10.4).

 

And yes,  /strings="String A, StringB,StringC, String D and E"' should get a single parameter value.

 

I chose your parser to try based on simple cmd switch definition:

 CmdSwitch: TSysCharSet = ['-', '+', '/']; 

Others have this in code.

 

Will it work with '--'? Like: 

--strings="String A, StringB,StringC, String D and E"

 

Share this post


Link to post

Double (or multiple) switch chars work.

But - as mentioned: the syntax for multiple arguments to an option is (arg1, arg2, ..., arg n)

If you need the separator as part of a string, you quote the string.  (art1, "this , is in arg2", 'this has a " in it')

 

Parse(' --strings="String A, StringB,StringC, String D and E"')
1 Switch[--] Option[strings] Flag[=] Values["String A, StringB,StringC, String D and E"]

AsString('strings'): String A, StringB,StringC, String D and E

Share this post


Link to post

The parser only deals with the parsing of a basic syntax.  The interpretations of the validity of variations of switches, flags and arguments still has to be built on top of the base parser.  I decided not to write those parts, as there are so many (potentially conflicting) ways to write it.  It should be easy to add that layer yourself, though.

Share this post


Link to post
6 minutes ago, Lars Fosdal said:

Double (or multiple) switch chars work

Great, thanks! Will re-check in Delphi 10.4.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×