Использование getopt в C для обработки опций, разделённых двоеточием, как в FFmpeg

Вопрос или проблема

Я пытаюсь реализовать обработку опций, похожую на FFmpeg. В частности, я хочу поддерживать два типа опций палитры:

  • Прямое указание палитры: -p "255,0,0 0,255,0"

  • Палитра из конфигурационного файла: -p:c blackwhite

Подобно тому, как FFmpeg обрабатывает опции кодека:

ffmpeg -i input.mp4 -c:v libx264 -c:a copy output.mp4


В настоящее время мой код использует getopt:

static struct option long_options[] = {
    {"palette", required_argument, 0, 'p'},
    // другие опции...
};

int main(int argc, char** argv) {
    while ((c = getopt_long(argc, argv, "p:h", long_options, &option_index)) != -1) {
        switch (c) {
            case 'p': 
                if (optarg[0] == 'c' && optarg[1] == ':') {
                    // Это не работает так, как задумано - optarg становится ":c"
                    load_palette_from_config(optarg + 2);
                } else {
                    parse_numeric_palette(optarg);
                }
                break;
        }
    }
}

Проблема в том, что при использовании -p:c blackwhite getopt воспринимает :c как аргумент к -p, что приводит к сбою загрузки палитры. Есть ли способ добиться подобной обработки опций, как в FFmpeg, используя getopt?

Ответ или решение

Для реализации обработки опций, аналогичной FFmpeg с использованием getopt, мы можем немного изменить подход к обработке опции -p. Когда мы используем -p:c filename, getopt воспринимает -p:c как одно целое, и это может привести к непониманию, так как опция должна содержать аргумент после символа :.

Для достижения подобного поведения, как в FFmpeg, можно воспользоваться простым обходным путем, рассчитывая длину optarg и корректно обрабатывая его. Ниже представлен пример реализации с нужной обработкой:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

void load_palette_from_config(const char *config_name) {
    printf("Загрузка палитры из конфигурации: %s\n", config_name);
    // Здесь вам нужно добавить код для обработки конфигурации.
}

void parse_numeric_palette(const char *palette) {
    printf("Обработка прямой палитры: %s\n", palette);
    // Здесь вам нужно добавить код для обработки числовой палитры.
}

static struct option long_options[] = {
    {"palette", required_argument, 0, 'p'},
    {0, 0, 0, 0}
};

int main(int argc, char** argv) {
    int c;
    int option_index = 0;

    while ((c = getopt_long(argc, argv, "p:h", long_options, &option_index)) != -1) {
        switch (c) {
            case 'p':
                // Если аргумент начинается с 'c:' и имеет длину больше 2
                if (strncmp(optarg, "c:", 2) == 0 && strlen(optarg) > 2) {
                    load_palette_from_config(optarg + 2); // Пропускаем 'c:'
                } else {
                    parse_numeric_palette(optarg); // Обработка обычной палитры
                }
                break;
            case 'h':
                // Вывод справки
                printf("Используйте: %s -p \"255,0,0 0,255,0\" или -p:c <имя_конфигурации>\n", argv[0]);
                break;
            default:
                fprintf(stderr, "Используйте -h для справки.\n");
                return EXIT_FAILURE;
        }
    }

    // Обработка иных аргументов...
    return EXIT_SUCCESS;
}

Объяснение приведенного кода:

  1. Аргументы опции:

    • При помощи getopt_long мы обрабатываем опцию -p с необходимыми аргументами.
  2. Проверка аргумента:

    • Мы используем strncmp для проверки, начинается ли аргумент с 'c:'. Если это так, то передаем управляющую строку в функцию load_palette_from_config, игнорируя первые два символа (так как они идентифицируют тип опции).
    • В противном случае вызываем parse_numeric_palette для обработки числовой палитры.
  3. Пользовательский интерфейс:

    • В случае вызова -h выводится краткая справка о доступных аргументах.

Эта структура позволяет гибко обрабатывать как прямую спецификацию палитры, так и конфигурацию из файла, аналогично тому, как это реализовано в FFmpeg. Таким образом, ваше приложение будет более устойчивым и отзывчивым к вводимым пользователем данным.

Оцените материал
Добавить комментарий

Капча загружается...