diff options
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/api.rst | 43 | ||||
| -rw-r--r-- | doc/changelog.rst | 58 | ||||
| -rw-r--r-- | doc/inline_clist.rst | 2 | ||||
| -rw-r--r-- | doc/inline_list.rst | 2 | ||||
| -rw-r--r-- | doc/misc_functions.rst | 2 | ||||
| -rw-r--r-- | doc/option_parsing.rst | 326 | ||||
| -rw-r--r-- | doc/string_ops.rst | 74 |
7 files changed, 312 insertions, 195 deletions
diff --git a/doc/api.rst b/doc/api.rst index 2579486..332fca9 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -4,11 +4,20 @@ 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 ABI (minus cv qualification). -* F column: First version that the function name was in use. +* F column: First version that the symbol name was in use. ====== ====== ====== ======================================== RMV MinVer FirstA Name ====== ====== ====== ======================================== +5.0 5.0 4.28 HXdeque_to_vecx +5.2 4.28 4.28 HX_getopt6 +4.28 4.28 4.28 HX_getopt6_clean +4.28 inline 4.28 HXOPT_CONST_INPUT +4.28 inline 4.28 HXOPT_ITER_OPTS +4.28 inline 4.28 HXOPT_ITER_ARGS +4.28 inline 4.28 HXOPT_ITER_OA +4.28 inline 4.28 HXOPT_DUP_ARGS +4.28 4.28 4.28 HX_strtoull8601p_sec 4.27 inline 4.27 float_cpu_to_{le,be}{32,64}p 4.27 inline 4.27 float_{le,be}{32,64}p_to_cpu 4.25 inline 4.25 HX_isascii @@ -17,7 +26,6 @@ RMV MinVer FirstA Name 4.25 inline 4.25 le{16,32,64}p_to_cpu be{16,32,64}p_to_cpu 4.25 4.25 4.25 HXSIZEOF_UNITSEC64 4.24 4.24 4.24 HX_getcwd -4.19 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 @@ -35,7 +43,6 @@ RMV MinVer FirstA Name 4.2 4.2 4.2 HX_unit_size_cu 4.2 4.2 4.2 HX_strtod_unit 4.2 4.2 4.2 HX_strtoull_unit -3.27 3.27 3.27 HXOPT_KEEP_ARGV 3.27 3.27 3.27 HXproc_top_fd 3.27 3.27 3.27 HXproc_switch_user 3.27 3.27 3.27 HXPROC_SU_SUCCESS @@ -49,10 +56,7 @@ RMV MinVer FirstA Name 3.27 3.27 3.27 HX_slurp_file 3.25 3.25 3.25 HX_split_fixed 3.25 3.25 3.25 HX_split_inplace -3.22 3.22 3.22 HXQUOTE_SQLBQUOTE 3.21 3.21 3.21 xml_getnsprop -3.19 3.19 3.19 HXQUOTE_SQLSQUOTE -3.18 3.18 3.18 HX_stpltrim 3.17 3.17 3.17 HX_LONGLONG_FMT 3.17 3.17 3.17 HX_SIZET_FMT 3.16 3.16 3.16 container_of @@ -75,7 +79,6 @@ RMV MinVer FirstA Name 3.13 3.13 3.13 HX_timeval_sub 3.12 3.12 1.10.0 HX_mkdir 3.12 3.12 3.12 HX_strndup -3.12 3.12 3.12 HX_strnlen 3.12 3.0 3.0 HXMAP_CDATA 3.12 3.0 3.0 HXMAP_CKEY 3.12 3.0 3.0 HXMAP_SCDATA @@ -87,9 +90,9 @@ RMV MinVer FirstA Name 3.12 3.12 3.12 HXOPT_ERR_SYS 3.12 3.12 3.12 HXOPTCB_BY_LONG 3.12 3.12 3.12 HXOPTCB_BY_SHORT -3.12 3.0 1.10.0 HXformat_aprintf -3.12 3.0 1.10.0 HXformat_fprintf -3.12 3.0 1.10.0 HXformat_sprintf +3.12 4.9 1.10.0 HXformat_aprintf / HXformat3_aprintf +3.12 4.9 1.10.0 HXformat_fprintf / HXformat3_fprintf +3.12 4.9 1.10.0 HXformat_sprintf / HXformat3_sprintf 3.11 3.11 3.11 HXQUOTE_BASE64 3.10 3.10 3.10 BUILD_BUG_ON_EXPR 3.10 3.10 3.10 HX_readlink @@ -216,7 +219,7 @@ RMV MinVer FirstA Name 1.28 1.28 1.28 HXTYPE_UINT32 1.28 1.28 1.28 HXTYPE_UINT64 1.28 1.28 1.28 HXTYPE_UINT8 -1.26 1.26 1.26 HX_hexdump +1.26 5.0 1.26 HX_hexdump 1.26 1.26 1.26 HX_time_compare 1.25 1.25 1.25 HX_getl 1.25 1.25 1.25 HXmc_free @@ -266,7 +269,6 @@ RMV MinVer FirstA Name 1.10.0 1.10.0 1.10.0 HXOPT_AND 1.10.0 1.10.0 1.10.0 HXOPT_AUTOHELP 1.10.0 1.10.0 1.10.0 HXOPT_DEC -1.10.0 1.10.0 1.10.0 HXOPT_DESTROY_OLD 1.10.0 1.10.0 1.10.0 HXOPT_ERR_MIS 1.10.0 1.10.0 1.10.0 HXOPT_ERR_UNKN 1.10.0 1.10.0 1.10.0 HXOPT_ERR_VOID @@ -275,7 +277,6 @@ RMV MinVer FirstA Name 1.10.0 1.10.0 1.10.0 HXOPT_NOT 1.10.0 1.10.0 1.10.0 HXOPT_OPTIONAL 1.10.0 1.10.0 1.10.0 HXOPT_OR -1.10.0 1.10.0 1.10.0 HXOPT_PTHRU 1.10.0 1.10.0 1.10.0 HXOPT_QUIET 1.10.0 1.10.0 1.10.0 HXOPT_TABLEEND 1.10.0 1.10.0 1.10.0 HXOPT_USAGEONERR @@ -307,13 +308,10 @@ RMV MinVer FirstA Name 1.10.0 1.10.0 1.10.0 HX_dlerror 1.10.0 1.10.0 1.10.0 HX_dlopen 1.10.0 1.10.0 1.10.0 HX_dlsym -1.10.0 1.10.0 1.10.0 HX_dlsym<> -1.10.0 1.10.0 1.10.0 HX_getopt 1.10.0 1.10.0 1.10.0 HX_getopt_help 1.10.0 1.10.0 1.10.0 HX_getopt_usage 1.10.0 1.10.0 1.10.0 HX_irand 1.10.0 1.10.0 1.10.0 HX_memdup -1.10.0 1.10.0 1.10.0 HX_memdup<> 1.10.0 1.10.0 1.10.0 HX_rand 1.10.0 1.10.0 1.10.0 HX_rrmdir 1.10.0 1.10.0 1.10.0 HX_shconfig_free @@ -329,7 +327,6 @@ RMV MinVer FirstA Name 1.10.0 1.10.0 1.10.0 HX_strrcspn 1.10.0 1.10.0 1.10.0 HX_strrev 1.10.0 1.10.0 1.10.0 HX_strrtrim -1.10.0 1.10.0 1.10.0 HX_strsep 1.10.0 1.10.0 1.10.0 HX_strsep2 1.10.0 1.10.0 1.10.0 HX_strupper 1.10.0 1.10.0 1.10.0 HX_zvecfree @@ -342,8 +339,7 @@ RMV MinVer FirstA Name 1.10.0 1.10.0 1.10.0 HXdeque_pop 1.10.0 1.10.0 1.10.0 HXdeque_push 1.10.0 1.10.0 1.10.0 HXdeque_shift -1.10.0 1.10.0 1.10.0 HXdeque_to_vec -1.10.0 1.10.0 1.10.0 HXdeque_to_vec<> +5.0 5.0 1.10.0 HXdeque_to_vec 1.10.0 1.10.0 1.10.0 HXdeque_unshift 1.10.0 1.10.0 1.10.0 SHCONF_ONE ====== ====== ====== ======================================== @@ -355,6 +351,7 @@ Struct reference ====== ====== ================================================ MinVer FirstA ====== ====== ================================================ +4.28 4.28 struct HXopt6_result 2.0 2.0 struct HXdeque_node.sptr 1.10.0 1.10.0 struct HXdeque_node 1.10.0 1.10.0 struct HXdeque @@ -376,6 +373,12 @@ Header reference ====== =================================== MinVer Name ====== =================================== +4.27 endian_float.h +4.25 endian.h +4.25 scope.hpp +4.18 cast.h +4.0 socket.h +3.25 intdiff.hpp 3.9 libHX/io.h 3.4 libHX/init.h 3.0 libHX/map.h @@ -384,7 +387,7 @@ MinVer Name 2.0 libHX/ctype_helper.h 1.23 libHX/misc.h 1.23 libHX/defs.h -1.22 libHX/xml_helper.h +1.22 libHX/libxml_helper.h 1.15 libHX/string.h 1.15 libHX/option.h 1.15 libHX/list.h diff --git a/doc/changelog.rst b/doc/changelog.rst index 94708fb..6d399ae 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -1,3 +1,61 @@ +v5.2 (2025-10-19) +================= + +Fixes: + +* Cure buffer overflows in HXdir_read, HX_getopt6 and a use-after-free + in conjunction with HX_getopt6's result struct. + + +v5.1 (2025-10-11) +================= + +Enhancements: + +* getopt6: ``HXTYPE_STRP`` can now be used for HXoption::type. This will + perform assignment without strdup. +* io: handle undocumented return code from FreeBSD/OpenBSD mkdir("/") + +Fixes: + +* map: resolve corruption of HXmap::items field + + +v5.0 (2025-10-01) +================= + +Enhancements: + +* getopt6: new function set ``HX_getopt6`` which allows for parsing options + with an iterative style. +* getopt6: the result set no longer forces strdup-ed results on the user. + +Changes: + +* Deleted functions ``HX_getopt``, ``HX_getopt5`` (use ``HX_getopt6`` instead), + ``HX_strnlen`` (use ``strnlen`` instead), ``HX_strsep`` (use ``strtok_r`` + instead), ``HX_stpltrim`` (no replacement). +* The struct members ``HXclist::items``, ``HXdeque::items``, ``HXmap::items`` + have changed from ``unsigned int`` to ``size_t``. The function + ``HXdeque_to_vec`` has accordingly changed the result parameter type. + + +v4.28 (2025-09-10) +================== + +Enhancements: + +* string: make HX_strtoull_sec support some ISO 8601 periods +* string: add function HX_strtoull8601p_sec +* opt: new getopt API that facilitates iterating over options and non-options + and doing away with unnecessary memory allocations + +Changes: + +* opt: the implementation for the HXOPT_PTHRU flag was deleted (its use will + now be rejected by the parser) + + v4.27 (2025-03-17) ================== diff --git a/doc/inline_clist.rst b/doc/inline_clist.rst index f7bf138..f0b7821 100644 --- a/doc/inline_clist.rst +++ b/doc/inline_clist.rst @@ -53,7 +53,7 @@ Synopsis Removes the first node in the list and returns it. ``HXclist_del`` - Deletes the node from the list. + Unlinks the node from the list. The list count in the clist head is updated whenever a modification is done on the clist through these functions. diff --git a/doc/inline_list.rst b/doc/inline_list.rst index 3e4cb7c..a9dca65 100644 --- a/doc/inline_list.rst +++ b/doc/inline_list.rst @@ -80,7 +80,7 @@ Synopsis Adds ``elem`` to the end of the list. ``HXlist_del`` - Deletes the given element from the list. + Unlinks the given element from the list. ``HXlist_empty`` Tests whether the list is empty. (Note: For clists, you could also use diff --git a/doc/misc_functions.rst b/doc/misc_functions.rst index c988f37..0d9e11e 100644 --- a/doc/misc_functions.rst +++ b/doc/misc_functions.rst @@ -36,7 +36,7 @@ Miscellaneous functions .. code-block:: c #include <libHX/io.h> - void HX_hexdump(FILE *fp, const void *ptr, unsigned int len); + void HX_hexdump(FILE *fp, const void *ptr, size_t len); ``HX_hexdump`` Outputs a nice pretty-printed hex and ASCII dump to the filedescriptor diff --git a/doc/option_parsing.rst b/doc/option_parsing.rst index fa928e0..a824559 100644 --- a/doc/option_parsing.rst +++ b/doc/option_parsing.rst @@ -12,13 +12,11 @@ Characteristics: * 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 (conceptuall only works for options taking no argument, - or when the argument is joined to a long option with a '=') -* 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 +* the parse function is one-shot; there is no state, just a result set +* value storing is possible in different ways + * using pointers with type declarators in the option table + * with user-provided callbacks invoked per option + * by specifying the ITER_OPTS flag and iterating after HX_getopt6 Synopsis @@ -38,7 +36,7 @@ Synopsis const char *help, *htyp; }; - int HX_getopt5(const struct HXoption *options_table, char **argv, int *new_argc, char ***new_argv, unsigned int flags); + int HX_getopt6(const struct HXoption *options_table, int argc, char **argv, struct HXopt6_result *result, unsigned int flags); The various fields of ``struct HXoption`` are: @@ -117,6 +115,29 @@ Type map allocation so that subsequently modifying the original argument string in any way will not falsely propagate. + HXTYPE_STRING is deprecated: When a user passes e.g. ``-S foo -S bar`` + to HX_getopt, ptr would be assigned twice before control returns back + to the HX_getopt caller, thus leaking the memory for "foo" leaks. We + cannot retroactively make the assign routine call free(ptr) inbetween, + as some code might have assigned ptr a static buffer before the call to + HX_getopt, e.g.: + + .. code-block:: c + + char *p = "foo"; // default to foo + options_table[] = { + {0,'S',HXTYPE_STRING,&p,...}, + }; + HX_getopt(...); + // p is always valid, but may point to either static or allocated + // storage. [Also assumes a program that never frees these + // strings for brevity.] + +``HXTYPE_STRP`` + The argument string pointer is stored in ``*(char **)ptr``. + No allocation occurs, but you are responsible for ensuring lifetime + adherence. + ``HXTYPE_STRDQ`` The argument string is duplicated to a new memory region and the resulting pointer is added to the given HXdeque. Note that you often @@ -268,23 +289,23 @@ Invoking the parser .. code-block:: c - 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); + struct HXopt6_result { + int nargs; + const char **uarg; + char **dup_argv; + }; -``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. + int HX_getopt6(const struct HXoption *options_table, int argc, char **argv, struct HXopt6_result *result, unsigned int flags); + void HX_getopt6_clean(struct HXopt6_result *); -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. +``HX_getopt6`` is the central parsing function. ``options_table`` specifies the +options that the parser will recognize. ``argv`` must be a vector of C strings, +and ``argc`` be the count of strings that should be processed at most. ``argc`` +may be -1, in which case argc is auto-computed from ``argv``, and in this case, +argv must be NULL-terminated. The ``flags`` argument control the general behavior of ``HX_getopt``: -``HXOPT_PTHRU`` - “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 input. @@ -299,12 +320,42 @@ The ``flags`` argument control the general behavior of ``HX_getopt``: ``HXOPT_RQ_ORDER`` Specifying this option terminates option processing when the first non-option argument in argv is encountered. This behavior is also - implicit when the environment variable ``POSIXLY_CORRECT`` is set. - -``HXOPT_KEEP_ARGV`` - Do not set ``*new_argc`` and ``*new_argv`` at all. - -The return value can be one of the following: + implicit when the environment variable ``POSIXLY_CORRECT`` is set + (and ``HXOPT_ANY_ORDER`` is not used). + +``HXOPT_ANY_ORDER`` + Specifying this option allows mixing of options and non-options, + basically the opposite of the strict POSIX order. + +``HXOPT_CONST_INPUT`` + Declaration by the user that elements in input argv must *not* be + reordered by the parser. + +``HXOPT_ITER_OPTS`` + ``result->desc`` will be filled with pointers to the definitions of the + parsed options. ``result->oarg`` will be filled with pointers to the + option argument strings (potentially %nullptr if the option did not + take anything). ``result->nopts`` will be filled with the option count. + +``HXOPT_ITER_ARGS`` + ``result->uarg`` will be filled with pointers to leftover arguments + (pointing into the memory regions of the original argv), and + ``result->nargs`` will contain the string count. uarg does *not* + contain NULL sentinel, so you cannot iterate with something like ``for + (const char **p = result.uarg; p != nullptr && *p != nullptr; ++p)`` + but must use ``for (int uidx = 0; uidx < result.nargs; ++uidx)``. + +``HXOPT_ITER_OA`` + Shortcut for ``HXOPT_ITER_OPTS | HXOPT_ITER_ARGS``. + +``HXOPT_DUP_ARGS`` + ``result->dup_argv`` will be filled with copies of leftover arguments, + and ``result->nargs`` will contain the string count. dup_argv will + include the original argv[0]. dup_argv will also include a NULL + sentinel (not counted in nargs). You can move ``dup_argv`` out of the + result struct and free it yourself with ``HX_zvecfree`. + +The return value of HX_getopt6 can be one of the following: ``HXOPT_ERR_SUCCESS`` Parsing was successful. @@ -325,17 +376,15 @@ The return value can be one of the following: ``HXOPT_ERR_AMBIG`` An abbreviation of a long option was ambiguous. +``HXOPT_ERR_FLAGS`` + HX_getopt6 was called with a ``flags`` value that contained illegal or + silly bit combinations. + 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. +Upon HXOPT_ERR_SUCCESS, ``HX_getopt6_clean`` must be called to release +resources. Pitfalls @@ -358,11 +407,12 @@ The following is an example of a possible pitfall regarding ``HXTYPE_STRDQ``: .help = "Add name"}, HXOPT_TABLEEND, }; - if (HX_getopt5(options_table, *argv, &argc, &argv, + struct HXopt6_result result; + if (HX_getopt6(options_table, -1, *argv, &result, HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS) return EXIT_FAILURE; /* ... */ - HX_zvecfree(argv); + HX_getopt6_clean(&result); return EXIT_SUCCESS; } @@ -379,38 +429,32 @@ Limitations The HX option parser has been influenced by both popt and Getopt::Long, but eventually, there are differences: -* Long options with a single dash (``-foo bar``). This unsupported - syntax clashes easily with support for option bundling or squashing. In case - of bundling, ``-foo`` might actually be ``-f -o -o``, or ``-f oo`` in case of - squashing. It also introduces redundant ways to specify options, which is not - in the spirit of the author. +* Long options with a single dash (``-foo bar``) are not supported in HXopt. + This syntax clashes easily with support for option bundling or squashing. In + case of bundling, ``-foo`` might actually be ``-f -o -o``, or ``-f oo`` in + case of squashing. It also introduces redundant ways to specify options, + which is not in the spirit of the author. -* Options using a ``+`` as a prefix, as in ``+foo``. Xterm for - example uses it as a way to negate an option. In the author's opinion, using - one character to specify options is enough — by GNU standards, a negator is - named ``--no-foo``. +* Options using a ``+`` as a prefix, as in ``+foo`` are not supported in HXopt. + Xterm for example uses it as a way to negate an option. In the author's + opinion, using one character to specify options is enough — by GNU standards, + a negator is named ``--no-foo``. -* Table nesting like implemented in popt. HXopt has no provision for nested - tables, as the need has not come up yet. It does however support chained - processing. You cannot do nested tables even with callbacks, as the new argv - array is only put in place shortly before ``HX_getopt`` returns. +* Table nesting (like in popt) is not supported in HXopt. The need + has not come up yet. It does however support some forms of chained + processing, e.g. by using the option terminator, "--". Examples ======== -Basic example -------------- - -The following code snippet should provide an equivalent of the -GNU getopt sample.[#f5] - -.. [#f5] http://www.gnu.org/software/libtool/manual/libc/Example-of-Getopt.html\#Example-of-Getopt +Storing through pointers +------------------------ .. code-block:: c #include <stdio.h> - #include <stdilb.h> + #include <stdlib.h> #include <libHX/option.h> int main(int argc, char **argv) @@ -418,7 +462,6 @@ GNU getopt sample.[#f5] int aflag = 0; int bflag = 0; char *cflag = NULL; - struct HXoption options_table[] = { {.sh = 'a', .type = HXTYPE_NONE, .ptr = &aflag}, {.sh = 'b', .type = HXTYPE_NONE, .ptr = &bflag}, @@ -427,20 +470,121 @@ GNU getopt sample.[#f5] HXOPT_TABLEEND, }; - if (HX_getopt5(options_table, argv, &argc, &argv, - HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS) + if (HX_getopt6(options_table, argc, argv, nullptr, + HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS) { + free(cflag); return EXIT_FAILURE; + } printf("aflag = %d, bflag = %d, cvalue = %s\n", - aflag, bflag, cvalue); + aflag, bflag, cflag != NULL ? cflag : "(null)"); + free(cflag); + return EXIT_SUCCESS; + } + +Note how HXTYPE_STRING in conjunction with ``.ptr=&cflag`` will allocate a +buffer that needs to be freed. + +Storing via iteration +--------------------- + + #include <stdio.h> + #include <stdlib.h> + #include <libHX/option.h> - while (*++argv != NULL) - printf("Non-option argument %s\n", *argv); + int main(int argc, char **argv) + { + int aflag = 0; + int bflag = 0; + char *cflag = NULL; + struct HXoption options_table[] = { + {.sh = 'a', .type = HXTYPE_NONE}, + {.sh = 'b', .type = HXTYPE_NONE}, + {.sh = 'c', .type = HXTYPE_STRING}, + HXOPT_AUTOHELP, + HXOPT_TABLEEND, + }; + + struct HXopt6_result result; + if (HX_getopt6(options_table, argc, argv, &result, + HXOPT_USAGEONERR | HXOPT_ITER_OPTS) != HXOPT_ERR_SUCCESS) + return EXIT_FAILURE; + for (int i = 1; i < result.nopts; ++i) { + switch (result.desc[i]->sh) { + case 'a': + aflag = 1; + break; + case 'b': + bflag = 1; + break; + case 'c': + cflag = result.oarg[i]; + break; + } + } + printf("aflag = %d, bflag = %d, cvalue = %s\n", + aflag, bflag, cflag ? cflag : "(null)"); + HX_getopt6_clean(&result); + return EXIT_SUCCESS; + } + +Note that the pointers in ``oarg`` point to the original argv and so should not +be freed. Upon success of HX_getopt6, HX_getopt6_clean must be called. + +Obtaining non-option arguments +------------------------------ + +.. code-block:: c + + #include <stdio.h> + #include <stdlib.h> + #include <libHX/option.h> + + int main(int argc, char **argv) + { + int aflag = 0; + int bflag = 0; + char *cflag = NULL; + struct HXoption options_table[] = { + {.sh = 'a', .type = HXTYPE_NONE, .ptr = &aflag}, + {.sh = 'b', .type = HXTYPE_NONE, .ptr = &bflag}, + {.sh = 'c', .type = HXTYPE_STRING, .ptr = &cflag}, + HXOPT_AUTOHELP, + HXOPT_TABLEEND, + }; - HX_zvecfree(argv); + struct HXopt6_result result; + if (HX_getopt6(options_table, argc, argv, &result, + HXOPT_USAGEONERR | HXOPT_ITER_ARGS) != HXOPT_ERR_SUCCESS) { + free(cflag); + return EXIT_FAILURE; + } + printf("aflag = %d, bflag = %d, cvalue = %s\n", + aflag, bflag, cflag); + for (int i = 1; i < result.nargs; ++i) + printf("Non-option argument %s\n", result.uarg[i]); + free(cflag); + HX_getopt6_clean(&result); return EXIT_SUCCESS; } +C++ extension +------------- + +.. code-block:: c++ + + { + struct HXopt6_auto_result result; + auto ret = HX_getopt6(&table, argc, argv, &result, + HXOPT_USAGEONERR | HXOPT_ITER_ARGS); + if (ret != HXOPT_ERR_SUCCESS) + return ret; + } + + +For C++ mode, a struct "HXopt6_auto_result" is offered with a constructor for +zero initialization and a destructor invoking HX_getopt6_clean. + Verbosity levels ---------------- @@ -504,8 +648,8 @@ Mask operations What this options table does is ``cpu_mask &= ~x`` and ``net_mask |= y``, the classic operations of clearing and setting bits. -Support for non-standard actions --------------------------------- +Callbacks +--------- Supporting additional types or custom storage formats is easy, by simply using ``HXTYPE_STRING``, ``NULL`` as the data pointer (usually by not specifying it @@ -539,53 +683,3 @@ the callback function in ``cb``. .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. - -.. code-block:: c - - static int get_cakes(int *argc, char ***argv) - { - struct HXoption cake_table[] = { - ... - }; - if (HX_getopt5(cake_table, *argv, &argc, &argv, - HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS) - return EXIT_FAILURE; - /* ... */ - HX_zvecfree(argv); - return EXIT_SUCCESS; - } - - static int fruit_main(int argc, char **argv) - { - struct HXoption fruit_table[] = { - ... - }; - if (HX_getopt5(fruit_table, *argv, &argc, &argv, - HXOPT_PTHRU) != HXOPT_ERR_SUCCESS) - return EXIT_FAILURE; - /* ... */ - HX_zvecfree(argv); - return EXIT_SUCCESS; - } - - int main(int argc, char **argv) - { - int cake = 0, fruit = 0; - struct HXoption option_table[] = { - {.ln = "cake", .type = HXTYPE_NONE, .ptr = &cake}, - {.ln = "fruit", .type = HXTYPE_NONE, .ptr = &fruit}, - HXOPT_TABLEEND, - }; - 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 aea4896..ab7f19b 100644 --- a/doc/string_ops.rst +++ b/doc/string_ops.rst @@ -102,7 +102,6 @@ In-place transformations char *HX_chomp(char *s); size_t HX_strltrim(char *s); - char *HX_stpltrim(const char *s); char *HX_strlower(char *s); char *HX_strrev(char *s); size_t HX_strrtrim(char *s); @@ -117,9 +116,6 @@ In-place transformations on the left edge of the string. Returns the number of characters that were stripped. -``HX_stpltrim`` - Returns a pointer to the first non-whitespace character in ``s``. - ``HX_strlower`` Transforms all characters in the string ``s`` into lowercase using ``tolower``(3). Returns the original argument. @@ -184,18 +180,6 @@ Possible values for type: ``HXQUOTE_URIENC`` Escapes the string so that it becomes a valid part for an URI. -``HXQUOTE_SQLSQUOTE`` - Escapes all single quotes in the string by double single-quotes, as - required for using it in a single-quoted SQL string. No surrounding - quotes will be generated to facilitate concatenating of HX_strquote - results. - -``HXQUOTE_SQLBQUOTE`` - Escape all backticks in the string by double backticks, as required for - using it in a backtick-quoted SQL string (used for table names and - columns). No surrounding ticks will be generated to facilitate - concatenation. - .. _RFC 4514: http://tools.ietf.org/html/rfc4514 .. _RFC 4515: http://tools.ietf.org/html/rfc4515 .. _RFC 4648: http://tools.ietf.org/html/rfc4648 @@ -246,7 +230,6 @@ Tokenizing char **HX_split(const char *s, const char *delimiters, size_t *fields, int max); char **HX_split_inplace(char *s, const char *delimiters, int *fields, int max); int HX_split_fixed(char *s, const char *delimiters, int max, char **arr); - char *HX_strsep(char **sp, const char *delimiters); char *HX_strsep2(char **sp, const char *dstr); ``HX_split`` @@ -277,20 +260,15 @@ Tokenizing .. [#fixfoot] An implementation may however decide to put ``NULL`` in the unassigned fields, but this is implementation-dependent. -``HX_strsep`` - Extract tokens from a string. This implementation of strsep has been - added since the function is non-standard (according to the manpage, - conforms to BSD4.4 only) and may not be available on every operating - system. This function extracts tokens, separated by one of the - characters in ``delimiters``. The string is modified in-place and thus - must be mutable. The delimiters in the string are then overwritten with - ``'\0'``, ``*sp`` is advanced to the character after the delimiter, and - the original pointer is returned. After the final token, ``HX_strsep`` - will return ``NULL``. - ``HX_strsep2`` - Like ``HX_strsep``, but ``dstr`` is not an array of delimiting - characters, but an entire substring that acts as one delimiter. + strsep is a string tokenization function from BSD4.4; the POSIX + replacement is + + strsep(&string, delim) <=> + strtok_r(nullptr, delim, &string). + + Whereas strsep/strtok would split on any character in ``delim``, + our strsep2 splits only on the entire ``delim`` string. Size-bounded string operations @@ -303,7 +281,6 @@ Size-bounded string operations char *HX_strlcat(char *dest, const char *src, size_t length); char *HX_strlcpy(char *dest, const char *src, size_t length); char *HX_strlncat(char *dest, const char *src, size_t dlen, size_t slen); - size_t HX_strnlen(const char *src, size_t max); ``HX_strlcat`` and ``HX_strlcpy`` provide implementations of the BSD-originating ``strlcat``(3) and ``strlcpy``(3) functions. ``strlcat`` and @@ -312,10 +289,6 @@ they always take the length of the entire buffer specified by ``dest``, instead of just the length that is to be written. The functions guarantee that the buffer is ``'\0'``-terminated. -``HX_strnlen`` will return the length of the input string or the upper bound -given by ``max``, whichever is less. It will not attempt to access more than -this many bytes in the input buffer. - Allocation-related ================== @@ -462,7 +435,7 @@ Conversion from/to human-readable durations with units unsigned int flags); ``HX_strtoull_sec`` and ``HX_strtoull_nsec`` convert a time duration with -units, such as ``"15min30s"`` into an all-seconds and all-nanoseconds value, +units, such as ``15min30s`` into an all-seconds and all-nanoseconds value, respectively. The recognized unit strings are: ``years``, ``year``, ``y``, ``months``, ``month``, ``days``, ``day``, ``d``, ``hours``, ``hour``, ``h``, ``minutes``, ``minute``, ``min``, ``seconds``, ``second``, ``s``, the empty @@ -471,8 +444,15 @@ string (to mean seconds), ``msec``, ``ms``, ``µsec``, ``µs``, ``nsec`` and implementation-defined. When parsing stops at any point, ``*end`` is set to the location, similar to how the ``strtoull`` C function would. -One year is defined to be 365.25 days of 86400 seconds; one month is defined to -be 1/12 such a year. This is consistent with the units employed by systemd. +One day is defined as 86400 seconds. One year is defined to be 365.25 days of +86400 seconds. One month is defined to be 1/12 such a year (30.4375 days). This +is consistent with the units employed by systemd. + +In addition, HX_strtoull_sec recognizes the most common ISO 8601-style period +syntax, e.g. ``PT15M30S``. Time lengths are applied as mentioned above, so +``P1M`` is treated as 2629800 seconds, *not* as a "calendaric month" that would +expand to 28—31 days relative to some start date. There is no function offered +to return a ``struct tm``. ``HX_unit_seconds`` is the reverse and transforms the duration given by ``seconds`` into a string representation broken into days, hours, minutes, and @@ -555,21 +535,3 @@ full-fledged ``HX_split`` that allocates space for each substring. callme(line); HX_zvecfree(field); } - -Using HX_strsep ---------------- - -``HX_strsep`` provides for thread- and reentrant-safe tokenizing a string where -strtok from the C standard would otherwise fail. - -.. code-block:: c - - #include <stdio.h> - #include <libHX/string.h> - - char line[] = "root:x:0:0:root:/root:/bin/bash"; - char *wp, *p; - - wp = line; - while ((p = HX_strsep(&wp, ":")) != NULL) - printf("%s\n", p) |
