2.7 Parsing Suboptions

Sometimes you may want to have an option which takes suboptions as arguments. You can do this through the subopts field of the MU_OPT structure. The subopts field is a list of MU_OPTs, terminated by a suboption with all fields equal to 0. Suboptions are in every way like regular options, except that they may not have suboptions of their own and they must use the subopt_name field instead of short_opt or long_opt. See Option Structure.

Suboptions may also specify the env_var field for an equivalent environment variables as well. Environment variables may also take suboptions as a value. See Parsing the Environment.

Note: even though environment variables may be specified for suboptions, you may not have a suboption which only specifies an environment variable. I.e., you may not have a suboption which has no subopt_name field (such an option will be considered as a terminator for the suboption list). If you want to do this, use a regular option instead.

Options which take suboptions as arguments may use the callback_subopt field as a callback (see Option Callbacks). If a callback is used and the option is found on the command line (or in the environment for an environment variable), the callback for that option is guaranteed to be called before any callbacks for the suboptions themselves. Note, however, that if a suboption has an equivalent environment variable (using the env_var field), the callback for the option which takes that suboption as an argument will not be called at all (though the callback for the suboption will be called). Indeed, it is impossible to call the callback for the option which takes the suboption as an argument, because two different options with different callbacks may take the same suboptions as arguments. Nor would it make any sense, because the option never actually appeared on the command line (or environment).

Suboptions are specified as a comma-separated list, with ‘=’ used to specify arguments. The commas must not contain spaces around them, and arguments cannot be specified any other way than with ‘=’.

Suboptions, like long options, may be abbreviated as long as they are not ambiguous. Note that this is in contrast to getsubopt, which does not allow abbreviation (see (libc)Suboptions).

Like regular options, suboptions should use the help field, which will be used in the help message (see Formatting Help and Option Structure). Suboptions may also use the arg_help field if they take arguments (see Option Arguments).

Normally, suboptions are parsed by mu_parse_opts from an argument to a regular option, using the subopts field. However, you may also parse suboptions in a user-specified string as well. Doing so is not too dissimilar from parsing regular options.

Data Type: MU_SUBOPT_CONTEXT

This is an opaque context for parsing suboptions. It is allocated using mu_subopt_context_new and freed using mu_opt_context_free.

Function: MU_SUBOPT_CONTEXT * mu_subopt_context_new (const char *prog_name, const char *suboptstr,

const MU_OPT *subopts)

Allocate and return a new suboption parsing context. The name the program was invoked as should be passed in prog_name (normally argv[0]), and is used for error reporting.

The suboptions will be parsed in suboptstr. A copy of suboptstr will be made, so you need not worry about it going out of scope or being modified (this copy will be freed by mu_subopt_context_free). The suboptions are specified in subopts.

Function: int mu_subopt_context_free (MU_SUBOPT_CONTEXT *context)

Free the suboption context, context. Callback data is freed as for mu_opt_context_free (see Parsing Options and Environment). Like mu_opt_context_free, mu_subopt_context_free will return nonzero if any of the destructors returned nonzero, or zero if all destructors returned zero. Also like mu_opt_context_free, all destructors are called even if one or more of them return nonzero.

Function: int mu_parse_subopts (MU_SUBOPT_CONTEXT *context)

Parse the suboptions given in context. Use mu_subopt_context_new (see above) to create the context. Zero is returned on success, or an error code on error (see Option Parsing Errors).

Note that you may not call this function more than once. To do so is an error and will be diagnosed.

The following example illustrates the use of suboptions:

#include <stdio.h>
#include <mu/options.h>
#include <mu/safe.h>            /* For mu_opt_context_x* */

int subopt_none(void *data, char *err) {
  puts("suboption found: none");
  return 0;
}

int subopt_opt(int has_arg, const char *arg,
               void *data, char *err) {
  puts("suboption found: opt");
  if (has_arg)
    printf("argument: %s\n", arg);
  return 0;
}

int subopt_req(int has_arg, const char *arg,
               void *data, char *err) {
  printf("suboption found: req\nargument: %s\n", arg);
  return 0;
}

int main(int argc, char **argv) {
  int ret;
  /* These are the suboptions that can be passed to the `-o'
     option. They are specified just like regular options, except
     that `subopt_name' is used instead of `long_opt' or
     `short_opt', and they may not have suboptions of their
     own. */
  const MU_OPT suboptions[] = {
    {
     .subopt_name     = "none",
     .has_arg         = MU_OPT_NONE,
     .callback_none   = subopt_none,
     .help            = "a suboption taking no arguments"
    },
    {
     .subopt_name     = "opt",
     .has_arg         = MU_OPT_OPTIONAL,
     .arg_type        = MU_OPT_STRING,
     .callback_string = subopt_opt,
     .help            = "a suboption taking an optional argument"
    },
    {
     .subopt_name     = "req",
     .has_arg         = MU_OPT_REQUIRED,
     .arg_type        = MU_OPT_STRING,
     .callback_string = subopt_req,
     .help            = "a suboption taking a required argument"
    },
    { 0 }
  };
  const MU_OPT options[] = {
    {
     .short_opt = "o",
     .long_opt  = "options",
     .has_arg   = MU_OPT_REQUIRED,
     .arg_type  = MU_OPT_SUBOPT,
     .subopts   = suboptions,
     .help      = "a regular option which takes suboptions"
    },
    { 0 }
  };
  MU_OPT_CONTEXT *context;

  context = mu_opt_context_xnew(argc, argv, options, MU_OPT_PERMUTE);

  /* Add the help option. */
  mu_opt_context_add_help(context, NULL, NULL, "Parse suboptions.",
                          NULL, "1", NULL, NULL, NULL);
  mu_opt_context_xadd_help_options(context, MU_HELP_BOTH);

  /* Parse the options. */
  ret = mu_parse_opts(context);
  mu_opt_context_xfree(context);
  if (MU_OPT_ERR(ret))
    return 1;

  return 0;
}

And here is the output of the example program (note, the COLUMNS environment variable is set to 65 so that the help message will look good in this manual):

$ COLUMNS=65
$ export COLUMNS
$ ./subopts -o none,opt=foo
-| suboption found: none
-| suboption found: opt
-| argument: foo
$ ./subopts -o req
error→ ./subopts: 'req': suboption requires argument
$ ./subopts --help
-| Usage: ./subopts [OPTION]...
-| Parse suboptions.
-|  
-| Mandatory arguments to long options are mandatory for short options too.
-|   -o, --options=SUBOPTS   a regular option which takes suboptions
-|   -h, --help[=plain|man]  print this help in plain text format if 'plain', or as a man(1) page if
-|                             'man'; if the argument is omitted, it will default to 'plain'.
-|  
-| Suboptions for -o, --options:
-|   none                    a suboption taking no arguments
-|   opt[=STRING]            a suboption taking an optional argument
-|   req=STRING              a suboption taking a required argument