limb 0.2.0

2024-01-09

loadopt(3)
limb manual
loadopt(3)

NAME

loadopt - parse options from command-line and (optionally) configuration file

SYNOPSIS

#include <limb/loadopt.h>
int loadopt(stralloc *sa, int argc, const char **argv, const struct option *options,
            int dirfd, const char *confdir, unsigned int poflags, struct loadopt *ctx)

const char *LO_ARG(struct loadopt *ctx)
size_t *LO_OFF*(struct loadopt *ctx)
u16 *LO_CUR*(struct loadopt *ctx)
int *LO_IDX*(struct loadopt *ctx)
int *LO_FROMFILE*(struct loadopt *ctx)

DESCRIPTION

The loadopt() function parses command-line arguments. Then, if confdir is not NULL, it will try to load any options that hasn't been set yet nor marked OPT_SKIP from the configuration directory confdir. If confdir describes a relative path, it is relative to the directory associated with the file descriptor dirfd, which may be AT_FDCWD to use the current working directory.

After that it ensures any option marked as required (via OPT_REQ) has been set, then may check for non-options arguments.

The actual parsing of options is done through parseopt(3), as such many of the arguments to loadopt() are the same as to parseopt(3), namely argc, argv, options and flags. Refer to parseopt(3) for more on those.

It is important to note, however, that the member flags of struct option is relevant here : it allows to define option-specific flags. Specifically, its value is constructed as a bitwise-inclusive OR of the following :

OPT_SKIP

To indicate this option shall not be set from configuration directory, i.e. can only be used from command-line.

OPT_REQ

To indicate this option is required, i.e. error out if after having parsed all command-line options (and, optionally, options set in configuration directory), the option has not been set. Mostly useful with options that require an argument.

OPT_SA

The value of the option's argument will be appended into the stralloc sa, and available through the macro LO_OFF(), indicating the offset at which it begins. When used, the macro LO_ARG() will always return NULL. This can be useful if the argument's value must be kept after option parsing, even when the option is set from configuration directory. Additionally, in case some pre-processing is applied, see below.

OPT_ESC

Implies OPT_SA. If the option's argument is within double-quotes (") then it will be un-escaped (as described in esc_scan(3)) before being placed into sa, thus ensuring the available value is always ready for use.

OPT_PATH

Implies OPT_ESC. Ensures that the (possibly unescaped) value does not contain any NUL byte, and is thusly a valid path name.

OPT_FILE

Implies OPT_PATH. Ensures that the (possibly unescaped) value does not contain any slashes (/), and is thusly a valid file name only.

OPT_RPT

Can only be used for the last-defined argument, not options. It indicates that this argument can be "repeated", i.e. from this position (in argv) on, any and all further arguments are processed as this one.

The last argument ctx is an opaque structure that should be initialized to LOADOPT_ZERO.

The stralloc pointed by sa is required when confdir is not NULL, as it will be used as temporary space to read files as needed. If at also required if at least one element of options has its OPT_SA flag set.

Accessing information is done through macros LO_ARG(), LO_IDX() and LO_CUR(), which are similar to their parseopt(3) counterparts PO_ARG(), PO_IDX() and PO_CUR() respectively.

Additionally, macro LO_OFF() must be used when OPT_SA was set, as described above, and macro LO_FROMFILE() will return 1 when the current option came from configuration directory, zero otherwise (i.e. from command-line).

Configuration Directory

When called, loadopt() will first defer to parseopt(3) to handle parsing of command-line arguments. Once done, if confdir was specified (i.e. is not NULL) and the corresponding directory exists, it will be read and options loaded from it.

That is, for every option that hasn't been set nor marked via OPT_SKIP it will try and read the first line of a file whose name is that of the full long option name (member longopt). Anything after the first newline (\n) is ignored (can be thought of as comments).

The content of the first line, if any, is treated as is as the option's argument (no trimming is performed, though the actual newline byte is obviously not included), and process happens just as it would for an option specified on command-line.

Hint

You can use LO_FROMFILE() to know whether an option was specified on command-line or from configuration directory

Note that when an option was specified on configuration directory, its argument, if any, will not be preserved/remain valid once parsing the option is done. Thus, if its value is needed for later use it needs to be copied. An easy way to achieve this is using the OPT_SA flag, to have it placed into the stralloc sa automatically (whether or not it comes from configuration directory).

Command-line Arguments

Lastly, loadopt() can perform some (minimal) checking for post-options arguments on the command line once parsing of all options has been successful, which includes making sure all options marked required were indeed found (either from file or on command-line).

For this to happen, you need to specify a special element in the array options by the macro LOADOPT_ARGUMENTS. Every element after it will be handled as referring to an argument instead of an option. Note that LOADOPT_ARGUMENTS can be the first element of the array, if there are no options.

For elements referring to arguments, member shortopt is ignored. The longopt member is only used in warnings to the user, to refer to said argument.

The important member is arg which is treated as defining whether the argument is required (ARG_REQ) or optional (ARG_OPT). If required and no argument was given on command-line, an error occurs. If optional and not specified, loadopt() successfully ends, returning 0.

To define them, you can use the following convenience macros :

ARGUMENT_OPT(name, flags, id)

To define argument arg as optional

ARGUMENT_REQ(name, flags, id)

To define argument arg as required

The actual parsing/handling of arguments is no different than of options, loadopt() will return the corresponding id (which must be valid as described above for options, with the exception that OPTID_SHORTOPT cannot be used), the same macros are to be used.

Flags can also be used, so it is possible to have arguments' values be copied into the stralloc sa automatically, unescaped if needed and checked. Note however that OPT_SKIP and OPT_REQ cannot be used here.

Finally, after all such argument definitions in the array options, you must terminate it with either one of the macros LOADOPT_DONE or LOADOPT_STOP.

If the later was specified, loadopt() ends successfully regardless of whether more arguments were specified on command-line or not. With the former however, any more arguments will result in an error for "too many arguments".

Note

LOADOPT_DONE is actually the same as OPTION_DONE as described from parseopt(3).

Note that either of those can be specified even without any actual arguments, i.e. as last element right after all the options, but must always be specified as last element.

Argument Repeating

It is possible, instead of using one of LOADOPT_DONE or LOADOPT_STOP, to set the flag OPT_RPT in the last argument. In which case any more argument specified on command-line will be processed as such an argument, over & over until all command-line has been parsed.

RETURN VALUE

If an option was successfully found, loadopt() returns the option's id if non-zero, else its shortopt. When all options, and, optionally, arguments, have been successfully parsed it returns 0.

If an error occurs, loadopt() returns -1 and sets errno to indicate the error.

Information

Warnings may be emitted on error unless PARSEOPT_SILENT was set in flags. Refer to parseopt(3) for more.

ERRORS

The loadopt() function may fail if :

ENOMEM

Not enough memory to read from configuration directory.

ENOKEY

A required option was missing/not specified.

ENODATA

A required argument was missing/not specified.

ETOOMANYREFS

Too many arguments were specified.

The loadopt() function may also fail for any of the errors specified for parseopt(3), readdir(3) and readopt(3), save for ENOBUFS.

SEE ALSO

autoopt(3), readopt(3)

limb 0.1.0
2023-07-24
loadopt(3)