如何使用GLib强制执行命令行选项?
我使用GLib来解析一些命令行选项。问题是我想让这些选项中的两个是强制性的,以便程序在帮助屏幕终止,如果用户省略它们。如何使用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和--bar,除非--version OR --help”的逻辑放在解析器本身中将会过度膨胀和过于复杂。
您只需检查参数解析后的值line
和column
以确保它们被设置为某些值。如果您担心main()
中出现混乱,则完全可以将所有这些逻辑放入函数中(例如check_sanity()
)。
总之,你看到的行为是设计的,我不认为它可能会改变。如果任何变量在解析器运行后保持初始化状态,用户忘记指定相应的选项。
这是不可能实现与GLib,我检查文档和源代码。尽管存在上述缺陷,您可能希望提交功能请求和/或采用您的建议解决方法。
我最近碰到类似的问题,并且我认为(现在还不确定,但看起来可行),它可以通过2个回调来实现。 arg处理回调函数可以做任何你想表示被解析的参数已经被输入(位掩码?,...)。它还会存储解析的值(请参阅下面的gotcha)。将此回调设置为GOptionArgFunc
,并使用G_OPTION_ARG_CALLBACK
标志指向GOptionEntry
阵列中的回调。
后解析回调将检查是否已输入所有必需项。将此回调设置为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回调函数。
来吧,只要想一想“选项”这个词的意思。 “强制性选择”是一个矛盾。选项是可选的。你可能把它与“强制性论证”混在一起,这是一个合理的概念。您可能想要有一种“命名参数”,如Python的关键字参数。唯一的好处是可以按任意顺序传递它们,以便进行更多类型的输入(可能在脚本中使用更多的冗长是可读性的优点)。无论如何,在解析阶段之后验证它是有意义的,因为依赖关系可以是任意复杂的。无论如何,“所需选项”是一个谬误。 – 2014-06-23 11:28:23