cargp

Argument ordering for processing with argp?


I am using argp C-library with these options:

struct argp_option options[]=
{
    {"quiet",'q',0,0,"Decrease logging, can be used multiple times (default=LOG_ERR)"},
    {"verbose",'v',0,0,"Increase logging, can be used multiple times (default=LOG_ERR)"},
    {"R0",10,"BOOL",0,"Set ALL relais on or off (true/false)"}, 
    [...]
    {0}
};

My parse_opt() function uses the usual switchstatement:

switch(key)
{
    case 'q': 
    {                               /* One loglevel quieter */
                loglevel--;
                loglevel=minmax(loglevel,0,7);
                setlogmask(LOG_UPTO (loglevel));
                break;
     }
[...] // further options to be processed
}

Is it possible to force somehow the processing of the "-q" and "-v" switches before the other options are getting processed? Even if these two might have been use multiple times (i.e. myprogram -aqqqqv)?


Solution

  • You can do this via the struct argp_state * argument passed to parse_opt(): define a state with a boolean field and set it to true or false depending on whether you want to only parse -q and -v or everything else. Then and call argp_parse() twice and switch the boolean between the two calls.

    Alternatively you can define two separate parse_opt() functions: one that only looks at -v and -q, and one that looks at everything else. Then, call argp_parse() twice: first with the first function, then with the second one.

    This second method seems simpler to me. Here's an example:

    static error_t parse_opt_verbosity(int key, char *arg, struct argp_state *state) {
        if (key == 'q' || key == 'v') {
            /* logic here */
        }
    
        return 0;
    }
    
    static error_t parse_opt_rest(int key, char *arg, struct argp_state *state) {
        switch (key) {
            case 'q':
            case 'v':
                /* ignore these, already handled */
                break;
    
            case 'a':
                /* ... */
                break;
    
            case 'b':
                /* ... */
                break;
    
            case 'c':
                /* ... */
                break;
    
            case ARGP_KEY_ARG:
                /* ... */
                break;
    
            case ARGP_KEY_END:
                /* ... */
                break;
    
            default:
                return ARGP_ERR_UNKNOWN;
        }
    
        return 0;
    }
    
    int main(int argc, char **argv) {
        struct argp argp = {
            .options = options,
            .parser = &parse_opt_verbosity
        };
    
        argp_parse(&argp, argc, argv, 0, 0, &your_args_struct);
    
        argp.parser = &parse_opt_rest;
        argp_parse(&argp, argc, argv, 0, 0, &your_args_struct);
    
        /* ... */
    
        return 0;
    }