Search code examples
command-line-argumentsinstance-variablesglibvala

How to do OptionContext parsing on an instance?


I'm trying to get options parsing using OptionContext to work.

My code so far:

public class Options : GLib.Object {

    public string option_output = "";

    public Options () {
    }

    public void parse (string args[]) throws OptionError {

        // string option_output;

        const OptionEntry[] options = {
            { "output", 'o', 0, OptionArg.FILENAME, 
        ref option_output, "file name for encoded output (required);", 
        "FILE" },
        {null}
        };
        var opt_context = new OptionContext ("- vpng2theora");
        opt_context.set_help_enabled (true);
        opt_context.add_main_entries (options, null);
        unowned string[] temp_args = args;
        foreach (var arg in temp_args) {
            print ("arg: %s\n", arg);
        }
        opt_context.parse (ref temp_args);
        print (option_output);
    }

}


int main (string[] args) {
    Options opts = new Options ();
    opts.parse (args);
    return 0;
}

As it stands this doesn't compile because:

error: Value must be constant

If I remove the const altogether:

OptionEntry[] options = {
    { "output", 'o', 0, OptionArg.FILENAME, 
    ref option_output, "file name for encoded output (required);", 
    "FILE" },
    {null}
};

The error is:

error: Expected array element, got array initializer list

The only way I can get around this problem is declaring the option_output as a static class field, but that defeats the purpose of instantiation.

Is there any way to have the OptionContext parsing work on an instance instead of a static class?


Solution

  • The following will work:

    public class Options : GLib.Object {
    
        public string option_output = "";
    
        public bool parse (ref unowned string[] args) {
            var options = new OptionEntry[2];
            options[0] = { "output", 'o', 0, OptionArg.FILENAME, 
            ref option_output, "file name for encoded output (required);", 
            "FILE" };
            options[1] = {null};
    
            var opt_context = new OptionContext ("- vpng2theora");
            opt_context.set_help_enabled (true);
            opt_context.add_main_entries (options, null);
            foreach (var arg in args) {
                print ("arg: %s\n", arg);
            }
            bool result= true;
            try {
                opt_context.parse (ref args);
                print( option_output );
            } catch {
                result = false;
            }
            return result;
        }
    
    }
    
    int main (string[] args) {
        Options opts = new Options ();
        if (!opts.parse (ref args)) { return -1; }
        return 0;
    }
    

    The options parsing will remove the optional arguments and then you can parse the required ones, such as the filenames to process. That's why I've kept the original args passed to the parse function. So you will get a cleaned set of args back, that you can then parse again for the required arguments. I found "CLI design: Putting flags to good use" a useful read.

    options is an array of structs. I don't understand well enough why setting the size of the array is necessary, but it works for me.