From eece9692d707ccb20356ec06955f8308c4e59ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 17 Dec 2023 14:18:48 +0100 Subject: New upstream version 4.19 --- doc/api.rst | 5 +- doc/changelog.rst | 28 +++++++++ doc/generator.cpp | 2 +- doc/inline_list.rst | 4 +- doc/option_parsing.rst | 167 +++++++++++++++++++++++++------------------------ doc/string_ops.rst | 2 +- 6 files changed, 120 insertions(+), 88 deletions(-) (limited to 'doc') diff --git a/doc/api.rst b/doc/api.rst index a645fdd..84feaa6 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -3,12 +3,13 @@ Function reference * R column: Recommend version number to use in ``PKG_CONFIG_CHECK`` in projects using libHX. Includes important bugfixes. -* M column: Lowest possible version with the same function signature. -* F column: Function first seen in version, possibly with different API. +* M column: Lowest possible version with the same ABI (minus cv qualification). +* F column: First version that the function name was in use. ====== ====== ====== ======================================== RMV MinVer FirstA Name ====== ====== ====== ======================================== +4.18 4.18 4.18 HX_getopt5 4.16 4.16 4.16 HX_strtoull_nsec 4.15 4.15 4.15 HX_flpr 4.15 4.15 4.15 HX_flprf diff --git a/doc/changelog.rst b/doc/changelog.rst index 2e0cf0f..8903a72 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -1,3 +1,31 @@ +v4.19 (2023-12-01) +================== + +Fixes: + +* string: fixed HX_strtoull_unit with negative fractions producing 0 + sometimes +* opt: fix HX_getopt losing argv on HXOPT_KEEP_ARGV + + +v4.18 (2023-11-27) +================== + +Enhancements: + +* opt: new HX_getopt5 API for the parser with untangled in and out variables + +Fixes: + +* string: HX_strtoull_units handles negative values now (like strtoull) +* string: HX_strtoull_units & HX_strtoull_(n)sec now set errno=ERANGE for + nonrepresentable results + +Behavioral changes: + +* string: HX_strtoull_sec rejects unitless numbers now + + v4.17 (2023-11-12) ================== diff --git a/doc/generator.cpp b/doc/generator.cpp index 6c64f80..0889cfd 100644 --- a/doc/generator.cpp +++ b/doc/generator.cpp @@ -35,7 +35,7 @@ class rdgen { fi end(void) { return fi(*this); }; }; -int main(int argc, const char **argv) +int main(int argc, char **argv) { for (auto x : rdgen(argc)) printf("%d\n", x); diff --git a/doc/inline_list.rst b/doc/inline_list.rst index e60e89f..3e4cb7c 100644 --- a/doc/inline_list.rst +++ b/doc/inline_list.rst @@ -195,7 +195,7 @@ HXdeque: .. code-block:: c - int main(int argc, const char **argv) + int main(int argc, char **argv) { struct HXdeque *dq = HXdeque_init(); while (--argc) @@ -212,7 +212,7 @@ HXdeque: char *data; }; - int main(int main, const char **argv) + int main(int main, char **argv) { HXLIST_HEAD(lh); while (--argc) { diff --git a/doc/option_parsing.rst b/doc/option_parsing.rst index 9205c2b..2dced82 100644 --- a/doc/option_parsing.rst +++ b/doc/option_parsing.rst @@ -2,22 +2,22 @@ Option parsing ============== -libHX uses a table-based approach like libpopt[#f3]. It provides for both long -and short options and the different styles associated with them, such as -absence or presence of an equals sign for long options (``--foo=bar`` and ``--foo -bar``), bundling (writing ``-abc`` for non-argument taking options ``-a -b -c``), -squashing (writing ``-fbar`` for an argument-requiring option ``-f bar``). The “lone -dash” that is often used to indicate standard input or standard output, is -correctly handled[#f4], as in ``-f -``. - -.. [#f3] The alternative would be an iterative, open-coded approach like - ``getopt``(3) requires. - -.. [#f4] popt failed to do this for a long time. - -A table-based approach allows for the parser to run as one unit, quite unlike -the open-coded ``getopt``(3) loop where the function returns for every argument -it parsed and needs to be called repeatedly. +Characteristics: + +* short options: + * bundling of argument-free options (``-a -b -c`` -> ``-abc``) + * squashing of argument-requiring options (``-a foo`` -> ``-afoo``) +* GNU long options with space or equals sign (``--foo bar``, ``--foo=bar``) +* proper recognition of the lone dash (often used to indicate stdin/stdout) +* recognition of the double dash as option list terminator +* offers POSIX strictness where the option list terminates at the first + non-option argument +* option passthrough +* the parse function is one-shot; there is no context object (like popt), + no global state (like getopt) and no ``while`` loop (either of the two others) +* exclusively uses an option table +* value storing is performed through pointers in the option table +* or user-provided callbacks can be invoked per option Synopsis @@ -37,7 +37,7 @@ Synopsis const char *help, *htyp; }; - int HX_getopt(const struct HXoption *options_table, int *argc, const char ***argv, unsigned int flags); + int HX_getopt5(const struct HXoption *options_table, char **argv, int *new_argc, char ***new_argv, unsigned int flags); The various fields of ``struct HXoption`` are: @@ -51,10 +51,10 @@ The various fields of ``struct HXoption`` are: ``type`` The type of the entry, essentially denoting the type of the target - variable. + variable (``ptr``). ``val`` - An integer value to be stored into ``*(int *)ptr`` when the option type + An integer value to be stored into ``*(int *)ptr`` if the option type is ``HXTYPE_IVAL``. ``ptr`` @@ -80,18 +80,14 @@ The various fields of ``struct HXoption`` are: String containing a keyword to aid the user in understanding the available options during dump. See examples. -Due to the amount of fields, it is advised to use C99 named initializers to -populate a struct, as they allow to omit unspecified fields, and assume no +Due to the amount of fields, it is advised to use C99/C++20 named initializers +to populate a struct, as they allow to omit unspecified fields, and assume no specific order of the members: .. code-block:: c struct HXoption e = {.sh = 'f', .help = "Force"}; -It is a sad fact that C++ has not gotten around to implement named initializers -as of C++17. It is possible to put the option parsing code into a separate C -source file that can then be compiled in C99 rather than C++ mode. - Type map ======== @@ -206,13 +202,13 @@ specified, but may be implemented on behalf of the user via a callback. Flags ===== -Flags can be combined into the type parameter by OR'ing them. It is valid to +Flags can be combined into the type parameter by OR-ing them. It is valid to not specify any flags at all, but most flags collide with one another. ``HXOPT_INC`` Perform an increment on the memory location specified by the - ``*(int *)ptr`` pointer. Make sure the referenced variable is - initialized beforehand! + ``*(int *)ptr`` pointer. The referenced variable must be + initialized. ``HXOPT_DEC`` Perform a decrement on the pointee. Same requirements as ``HXOPT_INC``. @@ -271,19 +267,22 @@ Invoking the parser .. code-block:: c - int HX_getopt(const struct HXoption *options_table, int *argc, const char ***argv, unsigned int flags);HX_getopt + int HX_getopt5(const struct HXoption *options_table, char **argv, int *new_argc, char **new_argv, unsigned int flags); + int HX_getopt(const struct HXoption *options_table, int *argc, char ***argv, unsigned int flags); -``HX_getopt`` is the actual parsing function. It takes the option table, and a -pointer to your argc and argv variables that you get from the main function. -The parser will, by default, consume all options and their arguments, similar -to Perl's ``Getopt::Long`` module. ``*argv`` is then updated to point to a new -array of strings (to be deallocated with ``HX_zvecfree``) and ``*argc`` is -updated accordingly. Additional flags can control the exact behavior of -``HX_getopt``: +``HX_getopt5`` is the central parsing function. ``options_table`` specifies +the options that the parser will recognize. ``argv`` must be a NULL-terminated +array of C strings. + +If ``new_argv`` is non-NULL, the leftover arguments will be output as a new +string vector on success. (That array can be freed with ``HX_zvecfree``). If +``new_argc`` is non-NULL, the argument count for new_argv will be output too. + +The ``flags`` argument control the general behavior of ``HX_getopt``: ``HXOPT_PTHRU`` - “Passthrough mode”. Any unknown options are not “eaten” and are instead - passed back into the resulting argv array. + “Passthrough mode”. Any unknown options are passed through into + ``new_argv``. ``HXOPT_QUIET`` Do not print any diagnostics when encountering errors in the user's @@ -302,7 +301,7 @@ updated accordingly. Additional flags can control the exact behavior of implicit when the environment variable ``POSIXLY_CORRECT`` is set. ``HXOPT_KEEP_ARGV`` - Do not modify ``argc`` and ``argv`` at all. + Do not set ``*new_argc`` and ``*new_argv`` at all. The return value can be one of the following: @@ -328,6 +327,15 @@ The return value can be one of the following: negative non-zero Failure on behalf of lower-level calls; errno. +``HX_getopt`` is an older API where ``argv`` is both used for input and output. +It recognizes additional flags/has additional behavior: + +``HXOPT_KEEP_ARGV`` + ``argc`` and ``argv`` is not updated. + +``HXOPT_DESTROY_OLD`` + Call ``HX_zvecfree`` on ``argv`` before updating it. + Pitfalls ======== @@ -341,33 +349,28 @@ The following is an example of a possible pitfall regarding ``HXTYPE_STRDQ``: static struct HXdeque *dq; - static bool get_options(int *argc, const char ***argv) + int main(int argc, char **argv) { + dq = HXdeque_init(); static const struct HXoption options_table[] = { {.sh = 'N', .type = HXTYPE_STRDQ, .ptr = dq, .help = "Add name"}, HXOPT_TABLEEND, }; - return HX_getopt(options_table, argc, argv, HXOPT_USAGEONERR) == - HXOPT_ERR_SUCCESS; - } - - int main(int argc, const char **argv) - { - dq = HXdeque_init(); - get_options(&argc, &argv); - return 0; + if (HX_getopt5(options_table, *argv, &argc, &argv, + HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS) + return EXIT_FAILURE; + /* ... */ + HX_zvecfree(argv); + return EXIT_SUCCESS; } The problem here is that ``options_table`` is, due to the static keyword, initialized at compile-time when ``dq`` is still ``NULL``. To counter this -problem and have it doing the right thing, you must remove the static qualifier -on the options table when used with ``HXTYPE_STRDQ``, so that it will be -evaluated when it is first executed. +problem and have it doing the right thing, the ``static`` qualifier on the +options table must be removed, so that the table is built when that line +executes. -It was not deemed worthwhile to have ``HXTYPE_STRDQ`` take an indirect -``HXdeque`` (``struct HXdeque **``) instead just to bypass this issue. (Live -with it.) Limitations ----------- @@ -409,7 +412,7 @@ GNU getopt sample.[#f5] #include #include - int main(int argc, const char **argv) + int main(int argc, char **argv) { int aflag = 0; int bflag = 0; @@ -423,9 +426,8 @@ GNU getopt sample.[#f5] HXOPT_TABLEEND, }; - if (HX_getopt(options_table, &argc, &argv, HXOPT_USAGEONERR) != - HXOPT_ERR_SUCCESS) - + if (HX_getopt5(options_table, argv, &argc, &argv, + HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS) return EXIT_FAILURE; printf("aflag = %d, bflag = %d, cvalue = %s\n", @@ -434,6 +436,7 @@ GNU getopt sample.[#f5] while (*++argv != NULL) printf("Non-option argument %s\n", *argv); + HX_zvecfree(argv); return EXIT_SUCCESS; } @@ -534,42 +537,43 @@ the callback function in ``cb``. {.sh = 'n', .type = HXTYPE_STRING, .cb = fixed_point_parse, .uptr = &number, .help = "Do this or that", HXOPT_TABLEEND, - }; Chained argument processing --------------------------- On the first run, only ``--cake`` and ``--fruit`` is considered, which is then -used to select the next set of accepted options. Note that -``HXOPT_DESTROY_OLD`` is used here, which causes the ``argv`` that is produced -by the first invocation of ``HX_getopt`` in the ``get_options`` function to be -freed as it gets replaced by a new argv again by ``HX_getopt`` in -``get_cakes``/``get_fruit``. ``HXOPT_DESTROY_OLD`` is however not specified in -the first invocation, because the initial argv resides on the stack and cannot -be freed. +used to select the next set of accepted options. .. code-block:: c - static bool get_cakes(int *argc, const char ***argv) + static int get_cakes(int *argc, char ***argv) { - struct HXoption option_table[] = { + struct HXoption cake_table[] = { ... }; - return HX_getopt(cake_table, argc, argv, - HXOPT_USAGEONERR | HXOPT_DESTROY_OLD) == HXOPT_ERR_SUCCESS; + if (HX_getopt5(cake_table, *argv, &argc, &argv, + HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS) + return EXIT_FAILURE; + /* ... */ + HX_zvecfree(argv); + return EXIT_SUCCESS; } - static bool get_fruit(int *argc, const char ***argv) + static int fruit_main(int argc, char **argv) { struct HXoption fruit_table[] = { ... }; - return HX_getopt(fruit_table, argc, argv, - HXOPT_USAGEONERR | HXOPT_DESTROY_OLD) == HXOPT_ERR_SUCCESS; + if (HX_getopt5(fruit_table, *argv, &argc, &argv, + HXOPT_PTHRU) != HXOPT_ERR_SUCCESS) + return EXIT_FAILURE; + /* ... */ + HX_zvecfree(argv); + return EXIT_SUCCESS; } - static bool get_options(int *argc, const char ***argv) + int main(int argc, char **argv) { int cake = 0, fruit = 0; struct HXoption option_table[] = { @@ -577,11 +581,10 @@ be freed. {.ln = "fruit", .type = HXTYPE_NONE, .ptr = &fruit}, HXOPT_TABLEEND, }; - if (HX_getopt(option_table, argc, argv, HXOPT_PTHRU) != HXOPT_ERR_SUCCESS) - return false; - if (cake) - return get_cakes(argc, argv); - else if (fruit) - return get_fruit(argc, argv); - return false; + if (HX_getopt5(option_table, *argv, &argc, &argv, + HXOPT_PTHRU) != HXOPT_ERR_SUCCESS) + return EXIT_FAILURE; + int ret = cake ? cake_main(argc, argv) : fruit_main(argc, argv); + HX_zvecfree(argv); + return EXIT_FAILURE; } diff --git a/doc/string_ops.rst b/doc/string_ops.rst index d818d2d..91da2f6 100644 --- a/doc/string_ops.rst +++ b/doc/string_ops.rst @@ -64,7 +64,7 @@ Extraction .. code-block:: c - int main(int argc, const char **argv) + int main(int argc, char **argv) { if (foo()) fprintf(stderr, "%s: Special condition occurred.\n", -- cgit v1.2.3