cgetopt

Using getopt in C to handle colon-separated options like FFmpeg


I'm trying to implement an option handling similar to FFmpeg. Specifically, I want to support two types of palette options:

Similar to how FFmpeg handles codec options:

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


Currently, my code uses getopt:

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

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] == ':') {
                    // This doesn't work as intended - optarg becomes ":c"
                    load_palette_from_config(optarg + 2);
                } else {
                    parse_numeric_palette(optarg);
                }
                break;
        }
    }
}

The problem is that when using -p:c blackwhite, getopt treats :c as the argument to -p, causing the palette loading to fail. Is there a way to achieve this FFmpeg-like option handling using getopt?


Solution

  • getopt is intended to parse simple single character command line options. If you examine the code for binaries that use more complex options, such as ffmpeg, you will see that they parse the command line without the use of getopt.

    You can still use getopt for your case example. When you use "p:h" then you must expect that "cmd -p:c foobar" will cause ':c' to be returned as optarg. In that case then YOU must peel the next value off the arglist by examining argv[optind] and if appropriate incrementing optind before the next iteration. Your 'if' section should look something like ....

        if (optarg[0] == ':' && optarg[1] == 'c') {
            if (!(optind < argc )) panic(BAD_ARGV);
            if (! valid_color(argv[optind])) panic(BAD_ARGV);
            load_palette_from_config(argv[optind]);
            optind++;
        } else { ...