I've used getopt() many times, even implemented its functionality for fun, and parsing commandline arguments has never been something I thought was particularly difficult or complex.
Of course, this is also the biggest fault, I would think. You rarely have the luxury of understanding to this level all of the parts of your program. And something like command line parsing probably is not the bottleneck in any way of your program.
* parse the call arguments and split them into options and arguments
* perform a very basic validation, i.e. handle the options which take a value and those who don't
Granted, mow.cli is much more complex. But it also does much more:
* Generate contextual help message
* Enforce arbitrarily complex validation rules (see the cp example) in your stead, meaning less code (and bugs) for you to write
* Does the routing, i.e. you don't need to have multi-level switch/case and if/else blocks to select and execute the correct code path based on the input arguments.
I talked about this in a previous article [1].
And finally, the library user doesn't have to deal with all this complexity: this is an implementation detail which I thought would interest technical readers, hence blogging about it.
You as a user only use the much easier to grasp exposed API [2]
[1] https://jawher.me/2015/01/13/parsing-command-line-arguments-...
http://blog.typeobject.com/thinking-out-loud-file-copy-tool-...
It turns out the arguments to CP are really tough to reason about if you just naively dive into it. The approach in this article is much better than mine. It feels like I was fumbling around in the dark.
If you're interested in seeing my implementation (it's buggy, but handles most cases), it can be found at:
https://github.com/hpc/dcp/blob/master/src/handle_args.c
The entry point to handle_args.c is DCOPY_parse_path_args, which is called by the main() in:
As you say, it's option parsing makes up the bulk of the cp.c code, with utils.c doing most of the actual file copying. It turns out it's pretty tough to offer a lot of options with some of them being mutually exclusive. Obvious in hindsight but interesting to me at the time I was reading through it.
http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/bin/...
http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/bin/...
Contrast how it is done now:
[-R [-H | -L | -P]] [-fi | -n] [-apvX] SRC... DST
With a parser combinator based approach: and(
optional(and('-R', or('-H', '-L', '-P'))),
optional(or(
'-fi',
'-n'
)
),
optional('-apvX'),
repeatable('SRC'),
'DST')
And this didn't even handle the fact that options order is not important.