How to make command-line options mandatory with GLib?
I use GLib to parse some command-line options. The problem is that I want to make two of those options mandatory so that the program terminates with the help screen if the user omits them.
My code looks like this:
static gint line = -1;
static gint column = -1;
static GOptionEntry options[] =
{
{"line", 'l', 0, G_OPTION_ARG_INT, &line, "The line", "L"},
{"column", 'c', 0, G_OPTION_ARG_INT, &column, "The column", "C"},
{NULL}
};
...
int main(int argc, char** argv)
{
GError *error = NULL;
GOptionContext *context;
context = g_option_context_new ("- test");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error))
{
usage(error->message, context);
}
...
return 0;
}
If I omit one of those parameters or both on the command-line g开发者_运维问答_option_context_parse() still succeeds and the values in question (line and or column) are still -1. How can I tell GLib to fail parsing if the user doesn't pass both options on the command-line? Maybe I'm just blind but I couldn't find a flag I can put into my GOptionEntry data structure to tell it to make those fields mandatory.
Of course I could check if one of those variables is still -1 but then the user could just have passed this value on the command-line and I want to print a separate error message if the values are out of range.
It's up to you to check argument sanity (beyond parsing), that goes for getopt
as well. The problem is, when making things 'mandatory', you will often run into cases where 'mandatory' applies only in the absence of other arguments.
For instance, ./program --help
should require no additional arguments, likewise for ./program --version
. Putting the logic of "require --foo and --bar unless --version OR --help" in the parser itself would border on bloat and overcomplexity.
You simply must check the value of line
and column
after arguments are parsed to ensure that they were set to something. It's entirely possible to put all of that logic into a function (e.g. check_sanity()
) if you are worried about clutter in main()
.
In summary, the behavior that you are seeing is by design, I don't think it's likely to change. If either variable remains as it was initialized after the parser runs, the user forgot to specify the respective option.
It is impossible to achieve with GLib, I checked documentation and source code. You may want to submit a feature request, and/or live with your proposed workaround despite the mentioned drawback.
I've run into a similar problem recently, and I think (don't know yet for sure but looks doable) it's doable with 2 callbacks.
The arg processing callback would do whatever you want to indicate that the arg being parsed has been entered (bitmask?, ...). It would also store the parsed value (see gotcha below.) Set up this callback as a GOptionArgFunc
and point to it in your GOptionEntry
array using the G_OPTION_ARG_CALLBACK
flag.
The post parsing callback would check to see whether all requireds had been entered. Set up this callback as a GOptionParseFunc
and point to it using g_option_group_set_parse_hooks
.
If you use g_option_group_new
you can pass it user_data
(address to your bitmask?, ...) to use in both callbacks. Use g_option_group_add_entries
and g_option_context_set_main_group
instead of g_option_context_add_main_entries
to get the group's entries associated with the GOptionContext
.
The only gotcha I see so far is that you have to set up your own pointer-to-entry array to use to actually set your entries' parsed values, since the GOptionEntry
arg_data
field would be used to point to the arg callback function.
精彩评论