NOTE: While most of the concepts expressed in this post are still valid, the new version (called cli) is leaner and simple to use. Please have a l...
For further actions, you may consider blocking this person and/or reporting abuse
Yes, long-option support is a must, especially for programs that have lots of options (for example, my own wrap). While I personally always have a short-option equivalent for every long option, eventually you end up with collisions and have to use letters that aren't mnemonic — which is why having a long option helps the user. Additionally, all programs should accept the
--helpand--versionoptions.This may fall into personal taste, but when the user errs (e.g., forgets a required argument for an option), it's best to print an error message only about that and not a full dump of the complete usage leaving the user to have to scan a large output looking for the relevant portion of the usage for just that option.
Ideally, a robust CLI library should also have mechanisms for:
--help, you may not specify any other option or program arguments).-vfor "verbose" output, but-vvfor more verbose output. (Though you probably can support this now by having your handler code increment a counter.)But I do agree that GNU's
getopt_long()leaves a lot to be desired.Thanks for your comment! I'll think about long args.
Validation (including dependency between options) seems more complicated to add while keeping the current level of simplicity.
For example passing a
checkfunctionvrgarg? SOmething like:vrgarg("-x\tXmas",check)?It may be possible (paraphrasing Alan Kay) to have simple CLIs be simple, but complex CLIs be possible. I think it would be a neat trick if you could manage to do it all via a header-only library, but I think it's unlikely.
The GNU
struct optionideally needs more fields. As forvrgarg, a_Bool check(char const*)function would be a start. You could have the library provide a few built-in checkers likevrgarg_check_int,vrgard_check_double, etc., but the user would be free to supply their own. The check function should be responsible for printing any error message since only it knows what the correct format is. The_Boolreturn value would only indicate to the library that afalsevalue means "stop processing" andexit(EX_USAGE).As you (and Alan Kay) said, It should be possible :)
It was just a dozen of lines of code, so I added the ability to specify a custom validator for each argument (possibly using additional parameters).
Have a look at the code on Github, or, if you feel inclined to do so, join the Discord server I just created to talk about
vrg.With this custom validators it should be quite easy to implement a logic of mutual exclusion between flags.
I'm not sure that providing pre-made validators would be useful, they would probably ending up being too simple and generic (and if this is what is needed, the users might write the validator themself).
IMHO, it's a bad idea to put full-blown function definitions into a header file, even if they are declared
static.It's also not clear why you're using
charwhere_Boolis more appropriate. Similarly, forvrg_def_s:: hasarg, you're assumingcharis signed — which it's not guaranteed to be. IMHO, you should use anenum, but if you insist on using signed integers, at least usesigned char.In general, the varargs stuff and the specific use-case for CLI arguments are too intertwined. If you want to make a varargs library, fine; if you want to make a CLI library, fine; but don't conflate them.
Thanks for reminding me about the
charsignedness. I completely forgot.I did not include
<stdbool.h>as this would force anyone including "vrg.h" to have symbols liketruedefined even if they do not want to.Yes, I might enforce that anyone should abide at least to the C99 standard but I can't see a benefit for me to put such a restriction.
Considering that the CLI functions will only be used where
main()is, I thought it would be more convenient to ask the user to define a symbol before including "vrg.h" rather than having both to include "vrg.h" and link against a "vrg.o" object file. I might considering providing options for both usage. I need to think about it.As for "mixing" things, I do see the topic of handling varidic "arguments" for functions and parsing arguments for CLI very related. But maybe it's just me, I'd love to hear from others. In any case, since I want to provide a flexible interface, I would need to define the variadic function piece anyway.
Thanks for your comments, I'm now adding the long options as you suggested and I will probably add a way to specify a full "usage string" because I recognize that the automatically information generated by
vrgusage()might be not enough. Imagine you want to provide the help In other languages than English ...I'm going to add the possibility of translating the various generated messages so to allow the creation of CLI in languages other than English.
I really don't like translated CLI (and I'm not a native English speaker) but I understand this might be a need for certain types of tools.
What do you think?
UPDATE:
Just pushed a new version with support for long options and modified the article accordingly.
Thanks for your feedback. I'll be happy to hear any comment you may have.
I'm abolutely loving it. Thank you so much. 😃
UPDATE: vrg now allows the configuration the user messages. An example for Japanese has been added to the code on GH