Как сделать параметры командной строки обязательными с GLib? - PullRequest
5 голосов
/ 24 апреля 2010

Я использую 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, но тогда пользователь мог просто передать это значение в командной строке, и я хочу напечатать отдельное сообщение об ошибке, если значения выходят за пределы диапазона.

Ответы [ 3 ]

9 голосов
/ 24 апреля 2010

Вы должны проверить здравый смысл аргумента (кроме анализа), который также относится к getopt. Проблема в том, что, делая вещи «обязательными», вы часто сталкиваетесь со случаями, когда «обязательные» применяются только при отсутствии других аргументов.

Например, ./program --help не требует дополнительных аргументов, также как и для ./program --version. Размещение логики «require --foo и --bar, если только --version OR --help» в самом синтаксическом анализаторе будет граничить с раздутием и чрезмерной сложностью.

Вы просто должны проверить значения line и column после анализа аргументов, чтобы убедиться, что они были установлены на что-то. Вполне возможно поместить всю эту логику в функцию (например, check_sanity()), если вас беспокоит беспорядок в main().

Таким образом, поведение, которое вы видите, является намеренным, я не думаю, что оно может измениться. Если любая из переменных остается такой же, как она была инициализирована после запуска синтаксического анализатора, пользователь забыл указать соответствующую опцию.

2 голосов
/ 05 июля 2015

Я недавно столкнулся с подобной проблемой, и Я думаю, (пока точно не знаю, но выглядит выполнимо), это выполнимо с двумя обратными вызовами. Обратный вызов обработки arg будет делать все, что вы хотите, чтобы указать, что анализируемый arg введен (bitmask ?, ...). В нем также будет храниться проанализированное значение (см. Раздел ниже). Установите этот обратный вызов как 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.

2 голосов
/ 24 апреля 2010

Невозможно добиться с GLib, я проверил документацию и исходный код. Вы можете отправить запрос на добавление функции и / или согласиться с предложенным обходным решением, несмотря на упомянутый недостаток.

...