4

I am using the following snippet to parse command line arguments and store them in a table.

var args = initTable[string, string]()
for kind, key, val in getopt():
    args.add(key,val)

However, it works only if I pass = in the command line

./mytool -i=somefile.txt

In this case, args is {i: somefile.txt}, which is what I want (a key:value pair).

But if I use ./mytool -i somefile.txt then args is {somefile.txt: , i: }, which is definitely not what I would expect (two keys and no values).

What is the proper way of parsing arguments without using =?

Here the printout of kind, key and val in the two cases:

$ ./diceof -a=ACTGCTGTGTGCACAGTGTCACGTGT -b=ACTGCTGTGTGCACAGTGTCACGTGa
kind:cmdShortOption
key :a
val :ACTGCTGTGTGCACAGTGTCACGTGT
kind:cmdShortOption
key :b
val :ACTGCTGTGTGCACAGTGTCACGTGa


$ ./diceof -a ACTGCTGTGTGCACAGTGTCACGTGT -b ACTGCTGTGTGCACAGTGTCACGTGa
kind:cmdShortOption
key :a
val :
kind:cmdArgument
key :ACTGCTGTGTGCACAGTGTCACGTGT
val :
kind:cmdShortOption
key :b
val :
kind:cmdArgument
key :ACTGCTGTGTGCACAGTGTCACGTGa
val :

Of course, I could check if val is found, if not add the next key as val of the previous one. But I am looking for a more elegant solution.

alec_djinn
  • 10,104
  • 8
  • 46
  • 71
  • 2
    You should check the `kind` as well, it's important. Print it out and you'll see. – dom96 Jul 14 '17 at 19:09
  • That is my point, why do I need to add `=` to get the parsing correct? What would be the best way to parse the arguments correctly avoiding using `=`? – alec_djinn Jul 17 '17 at 07:27
  • There isn't a way, AFAIK that's just how this parser works. You can use other packages like docopt.nim instead to achieve this probably. – dom96 Jul 18 '17 at 22:40

2 Answers2

5

argparse seems to be the only Nim package, which finally supports arguments parsing in the POSIX style and automatically forms the app help (usage) text:

$ ./example -c=settings.cfg 
Parsed opts: (config: "settings.cfg", help: false)

$ ./example -c settings.cfg 
Parsed opts: (config: "settings.cfg", help: false)

$ ./example -h
example

Usage:
  example [options] 

Options:
  -c, --config=CONFIG        Configuration file
  -h, --help                 Show this help
Parsed opts: (config: "", help: true)

The source:

import argparse

let p = newParser("example"):
  option("-c", "--config", help="Configuration file")
echo("Parsed opts: ", p.parse(commandLineParams()))
luart
  • 1,383
  • 1
  • 18
  • 25
1

Based on the documentation for parseopt2 and the discussion in commandeer's issues (see #10), parseopt2 can set values for keys only with a = or :, other than that I don't know if there is a 'proper' way to parse option values.

Commandeer works with options where the key and value are separated by a space by checking if the next token is a cmdArgument and assigning the value.

var nextToken = cliTokens.pop()
if nextToken.kind == parseopt2.cmdArgument:
  try:
    assign(nextToken.key)
  except ValueError:
    exitWithErrorMessage(getCurrentExceptionMsg())
  else:
    cliTokens.add(nextToken)