简体   繁体   中英

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 (eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM