命令行选项解析器

命令行选项解析器

GOption 命令行解析器旨在成为 popt 库的更简单的替代品。它支持如下例所示的短命令行选项和长命令行选项

testtreemodel -r 1 --max-size 20 --rand --display=:1.0 -vb -- file1 file2

此示例展示 GOption 命令行解析器的一些功能

  • 选项可以是单个字母,前缀为单破折号。
  • 多个短选项可以组合在单破折号之后。
  • 长选项前缀为两个连续破折号。
  • 选项可以附带一个额外参数,此参数可以是数字、字符串或文件名。对于长选项,可在选项名称后附加一个等号以及额外参数,这在额外参数以破折号开头时很有用,否则将被解释为另一个选项。
  • 非选项参数作为剩余参数返回给应用程序。
  • 仅由两个破折号组成的参数会关闭进一步解析,任何剩余参数(甚至以破折号开头的参数)都会作为剩余参数返回给应用程序。

GOption 的另一个重要功能是它可以自动生成格式良好的帮助输出。除非使用 g_option_context_set_help_enabled() 明确关闭帮助输出,否则 GOption 将识别 --help-?--help-all--help-groupname 选项(其中 groupnameGOptionGroup 的名称)并向标准输出 stdout 写入类似于以下示例中所示的文本。

Usage:
  testtreemodel [OPTION...] - test tree model performance

Help Options:
  -h, --help               Show help options
  --help-all               Show all help options
  --help-gtk               Show GTK Options

Application Options:
  -r, --repeats=N          Average over N repetitions
  -m, --max-size=M         Test up to 2^M items
  --display=DISPLAY        X display to use
  -v, --verbose            Be verbose
 -b, --beep               Beep when done
 --rand                   Randomize the data

GOption 在 GOptionGroup 中对选项进行分组,这使得轻松合并来自多个来源的选项变得更加容易。这样做的目的是让应用程序从其使用的库中收集选项组,将这些选项组添加到其 GOptionContext 中,并通过对 g_option_context_parse() 的单次调用来解析所有选项。

如果声明选项的类型为字符串或文件名,则 GOption 会负责将选项转换为正确的编码;将以 UTF-8 形式返回字符串,将以 GLib 文件名编码形式返回文件名。请注意,这仅在使用 g_option_context_parse() 之前已调用 setlocale() 的情况下才能正常工作

以下是对 GOption 进行设置以解析上述示例命令行并生成示例帮助输出的完整示例。

static gint repeats = 2;
static gint max_size = 8;
static gboolean verbose = FALSE;
static gboolean beep = FALSE;
static gboolean randomize = FALSE;

static GOptionEntry entries[] =
{
  { "repeats", 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions", "N" },
  { "max-size", 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items", "M" },
  { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },
  { "beep", 'b', 0, G_OPTION_ARG_NONE, &beep, "Beep when done", NULL },
  { "rand", 0, 0, G_OPTION_ARG_NONE, &randomize, "Randomize the data", NULL },
  G_OPTION_ENTRY_NULL
};

int
main (int argc, char *argv[])
{
  GError *error = NULL;
  GOptionContext *context;

  context = g_option_context_new ("- test tree model performance");
  g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
  g_option_context_add_group (context, gtk_get_option_group (TRUE));
  if (!g_option_context_parse (context, &argc, &argv, &error))
    {
      g_print ("option parsing failed: %s\n", error->message);
      exit (1);
    }

  ...

}

UNIX 系统上,传递给 main() 的 argv 没有特定编码,甚至其不同部分可能具有不同的编码。通常,正常参数和标志将采用当前语言环境,应将文件名视为不透明的字节字符串。因此,正确使用 G_OPTION_ARG_FILENAMEG_OPTION_ARG_STRING 是很重要的。

请注意,在 Windows 上,文件名确实有编码,但将 GOptionContext 与作为参数传递给 main() 的 argv 一起使用会导致程序只能接受来自系统代码页的字符的命令行参数。在尝试处理超出代码页范围的 Unicode 字符的文件名时,可能会导致问题。

要解决这个问题的方法是使用 g_win32_get_command_line()g_option_context_parse_strv(),后者将正确处理完整的 Unicode 文件名。如果您正在使用 GApplication,那么此操作会自动为您执行。

以下示例显示如何直接使用 GOptionContext 以正确处理 Windows 上的 Unicode 文件名

int
main (int argc, char **argv)
{
  GError *error = NULL;
  GOptionContext *context;
  gchar **args;

#ifdef G_OS_WIN32
  args = g_win32_get_command_line ();
#else
  args = g_strdupv (argv);
#endif

  // set up context

  if (!g_option_context_parse_strv (context, &args, &error))
    {
      // error happened
    }

  ...

  g_strfreev (args);

  ...
}