Welcome to little lamb

Code » limb » master » tree

[master] / src / doc / loadopt.h / loadopt.3.md

% limb manual
% loadopt(3)
% limb 0.1.0
% 2023-07-24

# NAME

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

# SYNOPSIS

    #include <limb/loadopt.h>

```pre hl
int loadopt(stralloc *<em>sa</em>, int <em>argc</em>, const char **<em>argv</em>, const struct option *<em>options</em>,
            int dirfd, const char *<em>confdir</em>, unsigned int <em>poflags</em>, struct loadopt *<em>ctx</em>)

const char *LO_ARG(struct loadopt *<em>ctx</em>)
size_t *LO_OFF*(struct loadopt *<em>ctx</em>)
u16 *LO_CUR*(struct loadopt *<em>ctx</em>)
int *LO_IDX*(struct loadopt *<em>ctx</em>)
int *LO_FROMFILE*(struct loadopt *<em>ctx</em>)
```

# 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.

! INFO:
! 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)