我使用GLib来解析一些命令行选项。问题是我想将其中两个选项设为强制选项,以便如果用户忽略它们,程序将在帮助屏幕上终止。
我的代码如下所示:
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;
}
如果我在命令行上省略其中一个或两个参数, g_option_context_parse() 仍然会成功,并且相关值(行和/或列)仍然是 -1。如果用户没有在命令行上传递这两个选项,我如何告诉 GLib 解析失败?也许我只是瞎了眼,但我找不到可以放入 GOptionEntry 数据结构中的标志来告诉它使这些字段成为必填字段。
当然,我可以检查其中一个变量是否仍为 -1,但用户可能只是在命令行上传递了该值,如果这些值超出范围,我想打印一条单独的错误消息。
由您来检查参数的健全性(超越解析),这也适用于
getopt
。问题是,当将事情设为“强制性”时,您经常会遇到“强制性”仅在没有其他参数的情况下适用的情况。
例如,
./program --help
不需要额外的参数,./program --version
也是如此。将“require --foo and --bar except --version OR --help”的逻辑放在解析器本身中会导致臃肿和过于复杂。
您只需在解析参数后检查
line
和 column
的值,以确保它们已设置为某个值。如果您担心 check_sanity()
中的混乱,完全可以将所有逻辑放入一个函数中(例如 main()
)。
总之,您所看到的行为是设计使然,我认为它不太可能改变。如果任一变量在解析器运行后仍保持初始化状态,则用户忘记指定相应的选项。
用GLib是不可能实现的,我查了文档和源代码。尽管存在上述缺点,您可能仍想提交功能请求和/或接受您建议的解决方法。
我最近遇到了类似的问题,我认为(还不确定,但看起来可行)可以通过 2 个回调来实现。 arg 处理回调将执行您想要的任何操作,以指示已输入正在解析的 arg(位掩码?,...)。它还会存储解析后的值(请参阅下面的陷阱。)将此回调设置为
GOptionArgFunc
并使用 GOptionEntry
标志在 G_OPTION_ARG_CALLBACK
数组中指向它。
解析后回调将检查是否已输入所有必需的内容。将此回调设置为
GOptionParseFunc
并使用 g_option_group_set_parse_hooks
指向它。
如果您使用
g_option_group_new
,您可以传递它user_data
(位掩码的地址?,...)以在两个回调中使用。使用 g_option_group_add_entries
和 g_option_context_set_main_group
而不是 g_option_context_add_main_entries
来获取与 GOptionContext
关联的组条目。
到目前为止我看到的唯一问题是您必须设置自己的条目指针数组才能用于实际设置条目的解析值,因为
GOptionEntry
arg_data
字段将用于指向arg 回调函数。
如果某个选项是强制性的,那么它就不是一个选项。或者换句话说,这应该是一个争论。