author | Olivier Brunel
<jjk@jjacky.com> 2023-04-05 17:59:59 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-05-20 18:06:35 UTC |
parent | 6167454bfb52608a73da7edde8af11b89533257b |
src/doc/autoopt.h.0.md | +40 | -0 |
src/doc/autoopt.h/autoopt_parse_buffer_dest.3.md | +56 | -0 |
src/doc/autoopt.h/autoopt_quiet.3.md | +81 | -0 |
src/doc/loadopt.h/loadopt.3.md | +4 | -0 |
src/doc/parseopt.h/parseopt.3.md | +4 | -0 |
src/include/autoopt.h | +17 | -0 |
src/liblimb/autoopt.h/autoopt_debug.c | +15 | -0 |
src/liblimb/autoopt.h/autoopt_log.c | +11 | -0 |
src/liblimb/autoopt.h/autoopt_parse_buffer_dest.c | +28 | -0 |
src/liblimb/autoopt.h/autoopt_quiet.c | +14 | -0 |
src/liblimb/autoopt.h/autoopt_verbose.c | +14 | -0 |
src/liblimb/autoopt.h/logdbg.c | +20 | -0 |
src/liblimb/autoopt.h/parse_buffer_dest.c | +37 | -0 |
src/liblimb/include/limb/autoopt.h | +25 | -0 |
diff --git a/src/doc/autoopt.h.0.md b/src/doc/autoopt.h.0.md new file mode 100644 index 0000000..b929b66 --- /dev/null +++ b/src/doc/autoopt.h.0.md @@ -0,0 +1,40 @@ +% limb manual +% autoopt.h(0) + +# NAME + +autoopt.h - automatic handling/parsing of options + +# SYNOPSIS + + #include <limb/autoopt.h> + +# DESCRIPTION + +This header defines functions to handle options automatically. + +## Macros + +The following macros are defined : + +: *AUTOOPT_QUIET*, *AUTOOPT_VERBOSE*, *AUTOOPT_LOG*, *AUTOOPT_DEBUG* +:: Macros to define options that can be handled via functions below. + +## Functions + +The following functions are defined : + +: [autoopt_quiet](3) +:: To handle option to bump output level down. + +: [autoopt_verbose](3) +:: To handle option to raise output level up. + +: [autoopt_log](3) +:: To handle option to set up a log output. + +: [autoopt_debug](3) +:: To handle option to raise output to debug level, or set up a debug output. + +: [autoopt_parse_buffer_dest](3) +:: To parse the destination for an output buffer. diff --git a/src/doc/autoopt.h/autoopt_parse_buffer_dest.3.md b/src/doc/autoopt.h/autoopt_parse_buffer_dest.3.md new file mode 100644 index 0000000..10ee8e5 --- /dev/null +++ b/src/doc/autoopt.h/autoopt_parse_buffer_dest.3.md @@ -0,0 +1,56 @@ +% limb manual +% autoopt_parse_buffer_dest(3) + +# NAME + +autoopt\_parse\_buffer\_dest - parse destination for an output buffer + +# SYNOPSIS + + #include <limb/autoopt.h> + +```pre hl +int autoopt_parse_buffer_dest(const struct option *<em>option</em>, const char *<em>arg</em>, u8 *<em>lvl</em>) +``` + +# DESCRIPTION + +The `autoopt_parse_buffer_dest`() function parses `arg` to be the destination +for an output buffer. That is, it is expected to be either a file descriptor or +the name of a file that will be opened in append mode, parsed according to +[open_parsed_name](3). + +Additionally, it may be prefixed with an at-sign (`@`) followed by an output +level (as described in [obuffer_parse_level](3)) and a colon (`:`), in order to +set the output level to specified level. + +It is also possible not to specify a level (i.e. use `@:` as prefix) in order to +have the default level bumped (e.g. from *OLVL_NORMAL* to *OLVL_VERBOSE*). + +To specify a file whose name begins with an at-sign, simply use two at-signs at +the beginning of the file. + +The `option` argument is only used in case of an error, to include the option's +name in the emitted warning. + +The `lvl` argument is expected to point to the default level of the output +buffer, and might be changed according to the parsed `arg`, or set to -1 in case +of error. + +# RETURN VALUE + +The function return the file descriptor to be used for the output buffer on +success. It can either be the specified file descriptor on `arg`, or - in case +of a file name - the file descriptor of the file opened in append mode. +Otherwise, it returns -1 and sets `errno` to indicate the error. + +# ERRORS + +The function may fail if : + +: *EINVAL* +:: Invalid output level specified, in which case the value pointed by `lvl` is +:: set to -1 + +It may also fail for the errors described for [open_parsed_name](3) and +[open_append](3). diff --git a/src/doc/autoopt.h/autoopt_quiet.3.md b/src/doc/autoopt.h/autoopt_quiet.3.md new file mode 100644 index 0000000..5ed02ee --- /dev/null +++ b/src/doc/autoopt.h/autoopt_quiet.3.md @@ -0,0 +1,81 @@ +% limb manual +% autoopt_quiet(3) + +# NAME + +autoopt\_quiet, autoopt\_verbose, autoopt\_log, autoopt\_debug - automatic +handling of some options + +# SYNOPSIS + + #include <limb/autoopt.h> + +```pre hl +AUTOOPT_QUIET(<em>shortopt</em>, <em>longopt</em>, <em>flags</em>, <em>id</em>) +AUTOOPT_VERBOSE(<em>shortopt</em>, <em>longopt</em>, <em>flags</em>, <em>id</em>) +AUTOOPT_LOG(<em>shortopt</em>, <em>longopt</em>, <em>flags</em>, <em>id</em>) +AUTOOPT_DEBUG(<em>shortopt</em>, <em>longopt</em>, <em>flags</em>, <em>id</em>) + +int autoopt_quiet(const struct option *<em>option</em>, const char *<em>arg</em>) +int autoopt_verbose(const struct option *<em>option</em>, const char *<em>arg</em>) +int autoopt_log(const struct option *<em>option</em>, const char *<em>arg</em>) +int autoopt_debug(const struct option *<em>option</em>, const char *<em>arg</em>) +``` + +# DESCRIPTION + +All of those functions share the same signature, even though they may not be +used. They are intended to be used during parsing of command-line options via +[parseopt](3) (or [loadopt](3)). + +As such, the `option` argument is expected to point to the option that is being +parsed/processed. It is used in case of an error (e.g. invalid argument) in +order to mention the option's name in the emitted warning. + +All the functions also expected to have been defined through their corresponding +macros, notably if they take a required argument, their argument `arg` is +expected to point to a NULL-terminated string without checking (unlike with an +optional argument). + +The *AUTOOPT_QUIET*(), *AUTOOPT_VERBOSE*(), *AUTOOPT_LOG*() and +*AUTOOPT_DEBUG*() macros can be used when defining an array of *struct option* +to be passed to [parseopt](3) or [loadopt](3). + +The `autoopt_quiet`() function will bump the output level (of `obuffer_1`, for +*stdout*) down by one level. If already at *OLVL_SILENT* then nothing is done. + +The `autoopt_verbose`() function will raise the output level (of `obuffer_1`, +for *stdout*) up by one level. If already at *OLVL_MAXIMUM* then nothing is +done. + +! INFO: +! The `obuffer_1` output buffer is used by [out_putmsg](3) and all the macros +! based on it, as can be found in [output.h](0). + +The `autoopt_log`() function parses `arg` as the destination to set up the log +output buffer via [obuffers_addlog_full](3). Said parsing is done through +[autoopt_parse_buffer_dest](3). + +The `autoopt_debug`() function raises the output level (of `obuffer_1`) to +*OLVL_DEBUG* if no argument was specified. Else, it parses `arg` as the +destination to set up the debug output buffer via [obuffers_adddbg_full](3). +Said parsing is done through [autoopt_parse_buffer_dest](3). + +# RETURN VALUE + +The `autoopt_quiet`() and `autoopt_verbose`() functions always returns 1. + +The `autoopt_log`() and `autoopt_debug`() functions return 1 on success. +Otherwise they return 0 and set `errno` to indicate the error. A warning is +also emitted (through the [warn](3) family of functions) describing the error. + +# ERRORS + +The `autoopt_log`() function may fail for the errors described in +[obuffers_addlog_full](3). + +The `autoopt_dbg`() function may fail for the errors described in +[obuffers_adddbg_full](3). + +The `autoopt_log`() and `autoopt_debug`() functions may also fail for the errors +described for [autoopt_parse_buffer_dest](3). diff --git a/src/doc/loadopt.h/loadopt.3.md b/src/doc/loadopt.h/loadopt.3.md index 2e8ede5..1324e38 100644 --- a/src/doc/loadopt.h/loadopt.3.md +++ b/src/doc/loadopt.h/loadopt.3.md @@ -157,3 +157,7 @@ The `loadopt`() function may fail if : The `loadopt`() function may also fail for any of the errors specified for [parseopt](3), [openslurpclose](3) save for *ENOENT*. + +# SEE ALSO + +[autoopt](3) diff --git a/src/doc/parseopt.h/parseopt.3.md b/src/doc/parseopt.h/parseopt.3.md index 8f2b916..942621e 100644 --- a/src/doc/parseopt.h/parseopt.3.md +++ b/src/doc/parseopt.h/parseopt.3.md @@ -168,3 +168,7 @@ The `parseopt`() function may fail if : : *ENOMSG* :: An option requiring an argument was found, but no argument was specified. + +# SEE ALSO + +[autoopt](3) diff --git a/src/include/autoopt.h b/src/include/autoopt.h new file mode 100644 index 0000000..02d1414 --- /dev/null +++ b/src/include/autoopt.h @@ -0,0 +1,17 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LIMB_LIMB_AUTOOPT_H +#define LIMB_LIMB_AUTOOPT_H + +#include <stddef.h> /* size_t */ +#include <limb/autoopt.h> +#include <limb/gccattributes.h> + +typedef int (*obufadd) (int fd, u8 deflvl); + +int logdbg(const struct option *option, const char *arg, u8 deflvl, obufadd obufadd) gccattr_hidden; + +int parse_buffer_dest(u8 *lvl, const char ** const arg, size_t len) gccattr_hidden; + +#endif /* LIMB_LIMB_AUTOOPT_H */ diff --git a/src/liblimb/autoopt.h/autoopt_debug.c b/src/liblimb/autoopt.h/autoopt_debug.c new file mode 100644 index 0000000..46085e9 --- /dev/null +++ b/src/liblimb/autoopt.h/autoopt_debug.c @@ -0,0 +1,15 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <limb/obuffers.h> +#include "autoopt.h" + +int +autoopt_debug(const struct option *option, const char *arg) +{ + if (arg) + return logdbg(option, arg, OLVL_DEBUG, obuffers_adddbg_full); + + obuffer_1->lvl = OLVL_DEBUG; + return 1; +} diff --git a/src/liblimb/autoopt.h/autoopt_log.c b/src/liblimb/autoopt.h/autoopt_log.c new file mode 100644 index 0000000..e7b6f6e --- /dev/null +++ b/src/liblimb/autoopt.h/autoopt_log.c @@ -0,0 +1,11 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <limb/obuffers.h> +#include "autoopt.h" + +int +autoopt_log(const struct option *option, const char *arg) +{ + return logdbg(option, arg, OLVL_NORMAL, obuffers_addlog_full); +} diff --git a/src/liblimb/autoopt.h/autoopt_parse_buffer_dest.c b/src/liblimb/autoopt.h/autoopt_parse_buffer_dest.c new file mode 100644 index 0000000..735458a --- /dev/null +++ b/src/liblimb/autoopt.h/autoopt_parse_buffer_dest.c @@ -0,0 +1,28 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <errno.h> +#include <limb/output.h> +#include "autoopt.h" + +int +autoopt_parse_buffer_dest(const struct option *option, const char *arg, u8 *lvl) +{ + int fd = parse_buffer_dest(lvl, &arg, strlen(arg)); + if (fd < 0) { + char buf[2] = { option->shortopt, 0 }; + if (*lvl == (u8) -1) + warn("invalid output level via --", option->longopt, + (*buf) ? "/-" : "", buf, ": ", arg); + else if (errno == EINVAL || errno == ERANGE) + warn("invalid file descriptor via --", option->longopt, + (*buf) ? "/-" : "", buf, ": ", arg); + else + warnusys("open ", ESC, arg, ESC, " via --", option->longopt, + (*buf) ? "/-" : "", buf); + + return -1; + } + + return fd; +} diff --git a/src/liblimb/autoopt.h/autoopt_quiet.c b/src/liblimb/autoopt.h/autoopt_quiet.c new file mode 100644 index 0000000..da88726 --- /dev/null +++ b/src/liblimb/autoopt.h/autoopt_quiet.c @@ -0,0 +1,14 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <skalibs/gccattributes.h> +#include <limb/autoopt.h> +#include <limb/obuffers.h> + +int +autoopt_quiet(const struct option *option gccattr_unused, const char *arg gccattr_unused) +{ + if (obuffer_1->lvl > OLVL_SILENT) + obuffer_1->lvl -= 50; + return 1; +} diff --git a/src/liblimb/autoopt.h/autoopt_verbose.c b/src/liblimb/autoopt.h/autoopt_verbose.c new file mode 100644 index 0000000..30566b1 --- /dev/null +++ b/src/liblimb/autoopt.h/autoopt_verbose.c @@ -0,0 +1,14 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <skalibs/gccattributes.h> +#include <limb/autoopt.h> +#include <limb/obuffers.h> + +int +autoopt_verbose(const struct option *option gccattr_unused, const char *arg gccattr_unused) +{ + if (obuffer_1->lvl < OLVL_MAXIMUM) + obuffer_1->lvl += 50; + return 1; +} diff --git a/src/liblimb/autoopt.h/logdbg.c b/src/liblimb/autoopt.h/logdbg.c new file mode 100644 index 0000000..10bd9dc --- /dev/null +++ b/src/liblimb/autoopt.h/logdbg.c @@ -0,0 +1,20 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <limb/djbunix.h> +#include "autoopt.h" + +int +logdbg(const struct option *option, const char *arg, u8 deflvl, obufadd obufadd) +{ + u8 lvl = deflvl; + int fd = autoopt_parse_buffer_dest(option, arg, &lvl); + if (fd < 0) return 0; + + if (!obufadd(fd, lvl)) { + fd_close(fd); + return 0; + } + + return 1; +} diff --git a/src/liblimb/autoopt.h/parse_buffer_dest.c b/src/liblimb/autoopt.h/parse_buffer_dest.c new file mode 100644 index 0000000..85b3e9e --- /dev/null +++ b/src/liblimb/autoopt.h/parse_buffer_dest.c @@ -0,0 +1,37 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <errno.h> +#include <limb/bytestr.h> +#include <limb/djbunix.h> +#include <limb/obuffer.h> +#include "autoopt.h" + +int +parse_buffer_dest(u8 *lvl, const char ** const arg, size_t len) +{ + /* is there a level specified via @[level]: */ + if (**arg == '@') { + ++*arg; + --len; + /* another '@' would mean file name starts with a '@' */ + if (**arg != '@') { + /* until the ':' we have the level */ + size_t end = byte_chr(*arg, len, ':'); + if (end == len) + return (errno = EINVAL, *lvl = (u8) -1, -1); + if (end == 0) { + /* @: w/out level means bumping it from its default value */ + if (*lvl < OLVL_MAXIMUM) + *lvl += 50; + } else { + *lvl = obuffer_parse_level(*arg, end); + if (*lvl == (u8) -1) + return (errno = EINVAL, -1); + } + *arg += end + 1; + } + } + + return open_parsed_name(*arg, open_append); +} diff --git a/src/liblimb/include/limb/autoopt.h b/src/liblimb/include/limb/autoopt.h new file mode 100644 index 0000000..cd49956 --- /dev/null +++ b/src/liblimb/include/limb/autoopt.h @@ -0,0 +1,25 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LIMB_AUTOOPT_H +#define LIMB_AUTOOPT_H + +#include <limb/parseopt.h> + +/* bump output level down to silent */ +#define AUTOOPT_QUIET(s,l,f,i) OPTION_ARG_NONE(s, l, f, i) +/* raise output level up to maximum */ +#define AUTOOPT_VERBOSE(s,l,f,i) OPTION_ARG_NONE(s, l, f, i) +/* set up log output to specified fd/file */ +#define AUTOOPT_LOG(s,l,f,i) OPTION_ARG_REQ( s, l, f, i) +/* set up debut output to specified fd/file */ +#define AUTOOPT_DEBUG(s,l,f,i) OPTION_ARG_OPT( s, l, f, i) + +extern int autoopt_quiet(const struct option *option, const char *arg); +extern int autoopt_verbose(const struct option *option, const char *arg); +extern int autoopt_log(const struct option *option, const char *arg); +extern int autoopt_debug(const struct option *option, const char *arg); + +extern int autoopt_parse_buffer_dest(const struct option *option, const char *arg, u8 *lvl); + +#endif /* LIMB_AUTOOPT_H */