diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-08-08 23:19:11 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-08-08 23:32:42 +0300 |
commit | fd9a86d37b96789d59e25e64b5d9db8974158a2c (patch) | |
tree | b9e48255ed4dce2167d01812d41de521e53d07fb /libmailutils | |
parent | 0fe801338b9dd8387caa6f69daf9435744a5a6b2 (diff) | |
download | mailutils-fd9a86d37b96789d59e25e64b5d9db8974158a2c.tar.gz mailutils-fd9a86d37b96789d59e25e64b5d9db8974158a2c.tar.bz2 |
New function: mu_strtosize
* include/mailutils/cstr.h (mu_strtosize): New proto.
* libmailutils/string/strtosize.c: New file.
* libmailutils/string/Makefile.am: Add strtosize.c
* libmailutils/string/str_to_c.c: Implement conversions for mu_c_hsize.
* include/mailutils/util.h (mu_c_hsize): New mu_c_type,
* libmailutils/tests/strtoc.c: Add tests for mu_c_hsize.
* libmu_auth/ldap.c: Use mu_strtosize to parse quota.
* mda/lib/mailquota.c: Likewise.
Diffstat (limited to 'libmailutils')
-rw-r--r-- | libmailutils/string/Makefile.am | 1 | ||||
-rw-r--r-- | libmailutils/string/str_to_c.c | 13 | ||||
-rw-r--r-- | libmailutils/string/strtosize.c | 132 | ||||
-rw-r--r-- | libmailutils/tests/strtoc.c | 23 |
4 files changed, 165 insertions, 4 deletions
diff --git a/libmailutils/string/Makefile.am b/libmailutils/string/Makefile.am index 7afa8b801..644ed733d 100644 --- a/libmailutils/string/Makefile.am +++ b/libmailutils/string/Makefile.am @@ -38,6 +38,7 @@ libstring_la_SOURCES = \ stripws.c\ strlst.c\ strrtrim.c\ + strtosize.c\ trueans.c\ unfold.c\ asnprintf.c\ diff --git a/libmailutils/string/str_to_c.c b/libmailutils/string/str_to_c.c index cb401722d..7676a0d7a 100644 --- a/libmailutils/string/str_to_c.c +++ b/libmailutils/string/str_to_c.c @@ -31,6 +31,7 @@ #include <mailutils/cctype.h> #include <mailutils/io.h> #include <mailutils/nls.h> +#include <mailutils/cstr.h> typedef int (*str_to_c_t) (void *tgt, char const *string, char **errmsg); @@ -245,6 +246,12 @@ to_incr (void *tgt, char const *string, char **errmsg) return 0; } +static int +to_hsize (void *tgt, char const *string, char **errmsg) +{ + return mu_strtosize (string, NULL, tgt); +} + static str_to_c_t str_to_c[] = { [mu_c_string] = to_string, [mu_c_short] = to_short, @@ -254,13 +261,14 @@ static str_to_c_t str_to_c[] = { [mu_c_long] = to_long, [mu_c_ulong] = to_ulong, [mu_c_size] = to_size_t, + [mu_c_hsize] = to_hsize, /* FIXME [mu_c_off] = { to_off, generic_dealloc }, */ [mu_c_time] = to_time_t, [mu_c_bool] = to_bool, /* FIXME [mu_c_ipv4] = to_ipv4, */ [mu_c_cidr] = to_cidr, /* FIXME [mu_c_host] = { to_host, generic_dealloc } */ - [mu_c_incr] = to_incr + [mu_c_incr] = to_incr, }; char const *mu_c_type_str[] = { @@ -272,6 +280,7 @@ char const *mu_c_type_str[] = { [mu_c_long] = "mu_c_long", [mu_c_ulong] = "mu_c_ulong", [mu_c_size] = "mu_c_size", + [mu_c_hsize] = "mu_c_hsize", [mu_c_off] = "mu_c_off", [mu_c_time] = "mu_c_time", [mu_c_bool] = "mu_c_bool", @@ -279,7 +288,7 @@ char const *mu_c_type_str[] = { [mu_c_cidr] = "mu_c_cidr", [mu_c_host] = "mu_c_host", [mu_c_incr] = "mu_c_incr", - [mu_c_void] = "mu_c_void" + [mu_c_void] = "mu_c_void", }; int diff --git a/libmailutils/string/strtosize.c b/libmailutils/string/strtosize.c new file mode 100644 index 000000000..9ba0ba0d7 --- /dev/null +++ b/libmailutils/string/strtosize.c @@ -0,0 +1,132 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif +#include <mailutils/errno.h> +#include <mailutils/cctype.h> +#include <mailutils/cstr.h> + +#ifndef SIZE_MAX +# define SIZE_MAX (~((size_t)0)) +#endif + +/* + * Converts the initial part of the string in STR to a size_t value. + * A valid input consists of a sequence of decimal digits, and optional + * size suffix: K, M, or G. Any amount of whitespace is allowed at the + * beginning of STR and between the last digit and size suffix. + * + * On success, the result is stored in RET_VAL and 0 is returned. + * On error, RET_VAL remains untouched and one of the following error + * codes is returned: + * EINVAL - STR is NULL. + * MU_ERR_OUT_PTR_NULL + * RET_VAL is NULL. + * ERANGE - Result is out of allowed range for size_t. + * MU_ERR_PARSE - (0) Unexpected character encountered or + * (1) STR is empty or + * (2) STR contains only whitespace characters or + * (3) ENDP is NULL and the portion of STR that remains + * after conversion contains characters other than + * \0 and whitespace, + * + * If ENDP is not NULL, a pointer to the character in STR at which + * the conversion has stopped is stored in *ENDP. + */ +int +mu_strtosize (char const *str, char **endp, size_t *ret_val) +{ + size_t n = 0; + int rc = 0; + char const *start, *s; + + if (!str) + return EINVAL; + if (!ret_val) + return MU_ERR_OUT_PTR_NULL; + + s = start = mu_str_skip_class (str, MU_CTYPE_SPACE); + + while (*s && mu_isdigit (*s)) + { + size_t x = n * 10 + *s - '0'; + if (x < n) + { + rc = ERANGE; + goto end; + } + n = x; + s++; + } + + if (s == start) + { + rc = MU_ERR_PARSE; + goto end; + } + + str = s; + s = mu_str_skip_class (s, MU_CTYPE_SPACE); + + switch (*s++) + { + case 'g': + case 'G': + if (SIZE_MAX / n < 1024) + { + rc = ERANGE; + break; + } + n <<= 10; + case 'm': + case 'M': + if (SIZE_MAX / n < 1024) + { + rc = ERANGE; + break; + } + n <<= 10; + case 'k': + case 'K': + if (SIZE_MAX / n < 1024) + { + rc = ERANGE; + break; + } + n <<= 10; + break; + + case 0: + s = str; + break; + + default: + s = str; + rc = MU_ERR_PARSE; + } + end: + if (endp) + *endp = (char*) s; + else if (rc == 0 && *mu_str_skip_class (s, MU_CTYPE_SPACE)) + rc = MU_ERR_PARSE; + + if (rc == 0) + *ret_val = n; + return rc; +} diff --git a/libmailutils/tests/strtoc.c b/libmailutils/tests/strtoc.c index 68978120e..dbb15e21b 100644 --- a/libmailutils/tests/strtoc.c +++ b/libmailutils/tests/strtoc.c @@ -197,6 +197,7 @@ struct value_handler value_handler[] = { [mu_c_long] = { v_long_format, v_long_compare }, [mu_c_ulong] = { v_ulong_format, v_ulong_compare }, [mu_c_size] = { v_size_format, v_size_compare }, + [mu_c_hsize] = { v_size_format, v_size_compare }, #if 0 mu_c_time, #endif @@ -244,7 +245,6 @@ struct testdata tests[] = { { mu_c_short, "115", 0, { .v_short = 115 } }, { mu_c_short, "-400", 0, { .v_short = -400 } }, { mu_c_short, "1a", EINVAL, }, - { mu_c_ushort, "110", 0, { .v_ushort = 110 } }, { mu_c_ushort, "-110", ERANGE }, @@ -258,6 +258,19 @@ struct testdata tests[] = { { mu_c_ulong, "10568", 0, { .v_ulong = 10568 } }, + { mu_c_size, "10568", 0, { .v_size = 10568 } }, + + { mu_c_hsize, "0", 0, { .v_size = 0 } }, + { mu_c_hsize, "10", 0, { .v_size = 10 } }, + { mu_c_hsize, "10K", 0, { .v_size = 10240 } }, + { mu_c_hsize, " 10 M ", 0, { .v_size = 10485760 } }, + { mu_c_hsize, "10s", MU_ERR_PARSE }, + { mu_c_hsize, "-1", MU_ERR_PARSE }, + { mu_c_hsize, "", MU_ERR_PARSE }, + { mu_c_hsize, " ", MU_ERR_PARSE }, + { mu_c_hsize, " 1 M b ", MU_ERR_PARSE }, + + { mu_c_bool, "true", 0, { .v_int = 1 } }, { mu_c_bool, "false", 0, { .v_int = 0 } }, @@ -289,7 +302,7 @@ print_test_id (int i, FILE *fp) void usage (int code, FILE *fp, char const *argv0) { - fprintf (fp, "usage: %s [-v]", argv0); + fprintf (fp, "usage: %s [-v]\n", argv0); exit (code); } @@ -341,6 +354,12 @@ main (int argc, char **argv) ++failures; } } + else if (tests[i].err) + { + print_test_id (i, stderr); + fprintf (stderr, "FAIL: unexpected success\n"); + ++failures; + } else if (valcmp (tests[i].type, &tests[i].val, &val)) { fprintf (stderr, "%d: FAIL: %s value differ: ", |