From 686d5116dec3d941f700deb51082b86f78687e46 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Fri, 17 Dec 2021 13:17:59 -0600 Subject: [PATCH] roken: Unparse wider ints --- lib/roken/parse_bytes-test.c | 13 +- lib/roken/parse_bytes.c | 14 +- lib/roken/parse_bytes.h | 8 +- lib/roken/parse_time.c | 12 +- lib/roken/parse_time.h | 12 +- lib/roken/parse_units.c | 252 ++++++++++++++++++++++++++--------- lib/roken/parse_units.h | 27 ++-- 7 files changed, 238 insertions(+), 100 deletions(-) diff --git a/lib/roken/parse_bytes-test.c b/lib/roken/parse_bytes-test.c index 87f2fa898..f7697e65d 100644 --- a/lib/roken/parse_bytes-test.c +++ b/lib/roken/parse_bytes-test.c @@ -38,7 +38,7 @@ static struct testcase { int canonicalp; - int val; + ssize_t val; const char *def_unit; const char *str; } tests[] = { @@ -52,6 +52,7 @@ static struct testcase { {1, 1024 * 1024, NULL, "1 megabyte"}, {0, 1025, NULL, "1 kilobyte 1"}, {1, 1025, NULL, "1 kilobyte 1 byte"}, + {1, 1024UL * 1024 * 1024 * 1024, NULL, "1 terabyte"}, }; int @@ -62,20 +63,20 @@ main(int argc, char **argv) for (i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) { char buf[256]; - int val = parse_bytes (tests[i].str, tests[i].def_unit); + ssize_t val = parse_bytes (tests[i].str, tests[i].def_unit); if (val != tests[i].val) { - printf ("parse_bytes (%s, %s) = %d != %d\n", + printf ("parse_bytes (%s, %s) = %lld != %lld\n", tests[i].str, tests[i].def_unit ? tests[i].def_unit : "none", - val, tests[i].val); + (long long)val, (long long)tests[i].val); ++ret; } if (tests[i].canonicalp) { (void) unparse_bytes (tests[i].val, buf, sizeof(buf)); if (strcmp (tests[i].str, buf) != 0) { - printf ("unparse_bytes (%d) = \"%s\" != \"%s\"\n", - tests[i].val, buf, tests[i].str); + printf ("unparse_bytes (%lld) = \"%s\" != \"%s\"\n", + (long long)tests[i].val, buf, tests[i].str); ++ret; } } diff --git a/lib/roken/parse_bytes.c b/lib/roken/parse_bytes.c index 561079afc..006a3524b 100644 --- a/lib/roken/parse_bytes.c +++ b/lib/roken/parse_bytes.c @@ -37,6 +37,10 @@ #include "parse_bytes.h" static struct units bytes_units[] = { + { "petabyte", 1024UL * 1024 * 1024 * 1024 * 1024 }, + { "PB", 1024UL * 1024 * 1024 * 1024 * 1024 }, + { "terabyte", 1024UL * 1024 * 1024 * 1024 }, + { "TB", 1024UL * 1024 * 1024 * 1024 }, { "gigabyte", 1024 * 1024 * 1024 }, { "gbyte", 1024 * 1024 * 1024 }, { "GB", 1024 * 1024 * 1024 }, @@ -50,26 +54,28 @@ static struct units bytes_units[] = { }; static struct units bytes_short_units[] = { + { "PB", 1024UL * 1024 * 1024 * 1024 * 1024 }, + { "TB", 1024UL * 1024 * 1024 * 1024 }, { "GB", 1024 * 1024 * 1024 }, { "MB", 1024 * 1024 }, { "KB", 1024 }, { NULL, 0 } }; -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -parse_bytes (const char *s, const char *def_unit) +ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL +parse_bytes(const char *s, const char *def_unit) { return parse_units (s, bytes_units, def_unit); } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_bytes (int t, char *s, size_t len) +unparse_bytes(ssize_t t, char *s, size_t len) { return unparse_units (t, bytes_units, s, len); } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_bytes_short (int t, char *s, size_t len) +unparse_bytes_short (ssize_t t, char *s, size_t len) { return unparse_units_approx (t, bytes_short_units, s, len); } diff --git a/lib/roken/parse_bytes.h b/lib/roken/parse_bytes.h index 8a88eca49..c043618ba 100644 --- a/lib/roken/parse_bytes.h +++ b/lib/roken/parse_bytes.h @@ -46,13 +46,13 @@ #endif #endif -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -parse_bytes (const char *s, const char *def_unit); +ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL +parse_bytes(const char *s, const char *def_unit); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_bytes (int t, char *s, size_t len); +unparse_bytes(ssize_t t, char *s, size_t len); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_bytes_short (int t, char *s, size_t len); +unparse_bytes_short(ssize_t t, char *s, size_t len); #endif /* __PARSE_BYTES_H__ */ diff --git a/lib/roken/parse_time.c b/lib/roken/parse_time.c index e1340b0e1..f5a99e31a 100644 --- a/lib/roken/parse_time.c +++ b/lib/roken/parse_time.c @@ -50,20 +50,20 @@ static struct units time_units[] = { {NULL, 0}, }; -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_time (const char *s, const char *def_unit) { return parse_units (s, time_units, def_unit); } ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time (int t, char *s, size_t len) +unparse_time(int64_t t, char *s, size_t len) { return unparse_units (t, time_units, s, len); } ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time_approx (int t, char *s, size_t len) +unparse_time_approx(int64_t t, char *s, size_t len) { return unparse_units_approx (t, time_units, s, len); } @@ -79,20 +79,20 @@ print_time_table (FILE *f) #undef unparse_time_approx #undef print_time_table -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_time(const char *s, const char *def_unit) { return rk_parse_units(s, time_units, def_unit); } ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time(int t, char *s, size_t len) +unparse_time(int64_t t, char *s, size_t len) { return rk_unparse_units(t, time_units, s, len); } ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time_approx(int t, char *s, size_t len) +unparse_time_approx(int64_t t, char *s, size_t len) { return rk_unparse_units_approx(t, time_units, s, len); } diff --git a/lib/roken/parse_time.h b/lib/roken/parse_time.h index ac5470710..7de18c717 100644 --- a/lib/roken/parse_time.h +++ b/lib/roken/parse_time.h @@ -46,14 +46,14 @@ #endif #endif -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_time (const char *s, const char *def_unit); ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time (int t, char *s, size_t len); +unparse_time(int64_t t, char *s, size_t len); ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time_approx (int t, char *s, size_t len); +unparse_time_approx(int64_t t, char *s, size_t len); ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL print_time_table (FILE *f); @@ -65,14 +65,14 @@ print_time_table (FILE *f); #define unparse_time_approx rk_unparse_time_approx #define print_time_table rk_print_time_table -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_time (const char *s, const char *def_unit); ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time (int t, char *s, size_t len); +unparse_time(int64_t t, char *s, size_t len); ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL -unparse_time_approx (int t, char *s, size_t len); +unparse_time_approx(int64_t t, char *s, size_t len); ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL print_time_table (FILE *f); diff --git a/lib/roken/parse_units.c b/lib/roken/parse_units.c index 3ed006017..d76578abf 100644 --- a/lib/roken/parse_units.c +++ b/lib/roken/parse_units.c @@ -44,15 +44,15 @@ * def_unit defines the default unit. */ -static int -parse_something (const char *s, const struct units *units, - const char *def_unit, - int (*func)(int res, int val, unsigned mult), - int init, - int accept_no_val_p) +static int64_t +parse_something_signed(const char *s, const struct units *units, + const char *def_unit, + int64_t (*func)(int64_t res, int64_t val, uint64_t mult), + int64_t init, + int accept_no_val_p) { const char *p; - int res = init; + int64_t res = init; unsigned def_mult = 1; if (def_unit != NULL) { @@ -70,7 +70,7 @@ parse_something (const char *s, const struct units *units, p = s; while (*p) { - int val; + int64_t val; char *next; const struct units *u, *partial_unit; size_t u_len; @@ -80,7 +80,104 @@ parse_something (const char *s, const struct units *units, while (isspace((unsigned char)*p) || *p == ',') ++p; - val = strtol(p, &next, 0); + val = strtoll(p, &next, 0); + if (p == next) { + val = 0; + if(!accept_no_val_p) + return -1; + no_val_p = 1; + } + p = next; + while (isspace((unsigned char)*p)) + ++p; + if (*p == '\0') { + res = (*func)(res, val, def_mult); + if (res < 0) + return res; + break; + } else if (*p == '+') { + ++p; + val = 1; + } else if (*p == '-') { + ++p; + val = -1; + } + if (no_val_p && val == 0) + val = 1; + u_len = strcspn (p, ", \t"); + partial = 0; + partial_unit = NULL; + if (u_len > 1 && p[u_len - 1] == 's') + --u_len; + for (u = units; u->name; ++u) { + if (strncasecmp (p, u->name, u_len) == 0) { + if (u_len == strlen (u->name)) { + p += u_len; + res = (*func)(res, val, u->mult); + if (res < 0) + return res; + break; + } else { + ++partial; + partial_unit = u; + } + } + } + if (u->name == NULL) { + if (partial == 1) { + p += u_len; + res = (*func)(res, val, partial_unit->mult); + if (res < 0) + return res; + } else { + return -1; + } + } + if (*p == 's') + ++p; + while (isspace((unsigned char)*p)) + ++p; + } + return res; +} + +static uint64_t +parse_something_unsigned(const char *s, const struct units *units, + const char *def_unit, + uint64_t (*func)(uint64_t res, int64_t val, uint64_t mult), + uint64_t init, + int accept_no_val_p) +{ + const char *p; + int64_t res = init; + unsigned def_mult = 1; + + if (def_unit != NULL) { + const struct units *u; + + for (u = units; u->name; ++u) { + if (strcasecmp (u->name, def_unit) == 0) { + def_mult = u->mult; + break; + } + } + if (u->name == NULL) + return -1; + } + + p = s; + while (*p) { + int64_t val; + char *next; + const struct units *u, *partial_unit; + size_t u_len; + unsigned partial; + int no_val_p = 0; + + while (isspace((unsigned char)*p) || *p == ',') + ++p; + + val = strtoll(p, &next, 0); if (p == next) { val = 0; if(!accept_no_val_p) @@ -145,17 +242,17 @@ parse_something (const char *s, const struct units *units, * The string consists of a sequence of `n unit' */ -static int -acc_units(int res, int val, unsigned mult) +static int64_t +acc_units(int64_t res, int64_t val, uint64_t mult) { return res + val * mult; } -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_units (const char *s, const struct units *units, const char *def_unit) { - return parse_something (s, units, def_unit, acc_units, 0, 0); + return parse_something_signed(s, units, def_unit, acc_units, 0, 0); } /* @@ -164,8 +261,8 @@ parse_units (const char *s, const struct units *units, * the function value. */ -static int -acc_flags(int res, int val, unsigned mult) +static uint64_t +acc_flags(uint64_t res, int64_t val, uint64_t mult) { if(val == 1) return res | mult; @@ -177,11 +274,11 @@ acc_flags(int res, int val, unsigned mult) return -1; } -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL parse_flags (const char *s, const struct units *units, int orig) { - return parse_something (s, units, NULL, acc_flags, orig, 1); + return parse_something_unsigned (s, units, NULL, acc_flags, orig, 1); } /* @@ -190,17 +287,60 @@ parse_flags (const char *s, const struct units *units, */ static int -unparse_something (int64_t num, const struct units *units, char *s, size_t len, - long long (*get_divisor) (long long, unsigned long long), - int (*print) (char *, size_t, long long, const char *, int), - int (*update) (long long, unsigned long long), - const char *zero_string) +unparse_something_signed(int64_t num, const struct units *units, char *s, + size_t len, + int64_t (*get_divisor)(int64_t, uint64_t), + int (*print)(char *, size_t, int64_t, const char *, int64_t), + int64_t (*update)(int64_t, uint64_t), + const char *zero_string) { const struct units *u; int ret = 0, tmp; if (num == 0) return snprintf (s, len, "%s", zero_string); + if (len) + s[0] = '\0'; + if (num < 0) + return -1; + + for (u = units; num > 0 && u->name; ++u) { + long long divisor = get_divisor(num, u->mult); + + if (divisor) { + num = (*update)(num, u->mult); + tmp = (*print)(s, len, divisor, u->name, num); + if (tmp < 0) + return tmp; + if ((size_t)tmp > len) { + len = 0; + s = NULL; + } else { + len -= tmp; + s += tmp; + } + ret += tmp; + } + } + return ret; +} + +static int +unparse_something_unsigned(uint64_t num, const struct units *units, char *s, + size_t len, + uint64_t (*get_divisor)(uint64_t, uint64_t), + int (*print)(char *, size_t, uint64_t, const char *, uint64_t), + uint64_t (*update)(uint64_t, uint64_t), + const char *zero_string) +{ + const struct units *u; + int64_t tmp; + int ret = 0; + + if (num == 0) + return snprintf (s, len, "%s", zero_string); + if (len) + s[0] = '\0'; for (u = units; num > 0 && u->name; ++u) { long long divisor = get_divisor(num, u->mult); @@ -224,28 +364,26 @@ unparse_something (int64_t num, const struct units *units, char *s, size_t len, } static int -print_unit(char *s, size_t len, long long divisor, const char *name, int rem) +print_unit(char *s, size_t len, int64_t divisor, const char *name, int64_t rem) { - return snprintf (s, len, "%lld %s%s%s", - divisor, name, - divisor == 1 ? "" : "s", - rem > 0 ? " " : ""); + return snprintf(s, len, "%lld %s%s%s", (long long)divisor, name, + divisor == 1 ? "" : "s", rem > 0 ? " " : ""); } -static long long -get_divisor_unit(long long in, unsigned long long mult) +static int64_t +get_divisor_unit(int64_t in, uint64_t mult) { return in / mult; } -static int -update_unit(long long in, unsigned long long mult) +static int64_t +update_unit(int64_t in, uint64_t mult) { return in % mult; } -static int -update_unit_approx (long long in, unsigned long long mult) +static int64_t +update_unit_approx(int64_t in, uint64_t mult) { if (in / mult > 0) return 0; @@ -254,23 +392,18 @@ update_unit_approx (long long in, unsigned long long mult) } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units (int num, const struct units *units, char *s, size_t len) +unparse_units(int64_t num, const struct units *units, char *s, size_t len) { - return unparse_something (num, units, s, len, - get_divisor_unit, - print_unit, - update_unit, - "0"); + return unparse_something_signed(num, units, s, len, + get_divisor_unit, print_unit, update_unit, + "0"); } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units_approx (int num, const struct units *units, char *s, size_t len) +unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len) { - return unparse_something (num, units, s, len, - get_divisor_unit, - print_unit, - update_unit_approx, - "0"); + return unparse_something_signed(num, units, s, len, get_divisor_unit, + print_unit, update_unit_approx, "0"); } ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL @@ -306,32 +439,29 @@ print_units_table (const struct units *units, FILE *f) } } -static long long -get_divisor_flag(long long in, unsigned long long mult) +static uint64_t +get_divisor_flag(uint64_t in, uint64_t mult) { return in & mult; } static int -print_flag (char *s, size_t len, long long divisor, const char *name, int rem) +print_flag(char *s, size_t len, uint64_t divisor, const char *name, uint64_t rem) { return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : ""); } -static int -update_flag (long long in, unsigned long long mult) +static uint64_t +update_flag(uint64_t in, uint64_t mult) { return in & ~mult; } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_flags (int num, const struct units *units, char *s, size_t len) +unparse_flags (uint64_t num, const struct units *units, char *s, size_t len) { - return unparse_something (num, units, s, len, - get_divisor_flag, - print_flag, - update_flag, - ""); + return unparse_something_unsigned(num, units, s, len, get_divisor_flag, + print_flag, update_flag, ""); } ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL @@ -351,7 +481,7 @@ print_flags_table (const struct units *units, FILE *f) #undef unparse_flags #undef print_flags_table -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_units(const char *s, const struct units *units, const char *def_unit) { @@ -359,13 +489,13 @@ parse_units(const char *s, const struct units *units, } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units(int num, const struct units *units, char *s, size_t len) +unparse_units(int64_t num, const struct units *units, char *s, size_t len) { return rk_unparse_units(num, units, s, len); } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units_approx(int num, const struct units *units, char *s, size_t len) +unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len) { return rk_unparse_units_approx(num, units, s, len); } @@ -376,14 +506,14 @@ print_units_table(const struct units *units, FILE *f) rk_print_units_table(units, f); } -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL parse_flags(const char *s, const struct units *units, int orig) { return rk_parse_flags(s, units, orig); } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_flags(int num, const struct units *units, char *s, size_t len) +unparse_flags(uint64_t num, const struct units *units, char *s, size_t len) { return rk_unparse_flags(num, units, s, len); } diff --git a/lib/roken/parse_units.h b/lib/roken/parse_units.h index 0cb5f5a9a..c5b6f2030 100644 --- a/lib/roken/parse_units.h +++ b/lib/roken/parse_units.h @@ -38,6 +38,7 @@ #include #include +#include #ifndef ROKEN_LIB_FUNCTION #ifdef _WIN32 @@ -51,29 +52,29 @@ struct units { const char *name; - unsigned long long mult; + uint64_t mult; }; -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_units (const char *s, const struct units *units, const char *def_unit); ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL print_units_table (const struct units *units, FILE *f); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL parse_flags (const char *s, const struct units *units, int orig); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units (int num, const struct units *units, char *s, size_t len); +unparse_units(int64_t num, const struct units *units, char *s, size_t len); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units_approx (int num, const struct units *units, char *s, - size_t len); +unparse_units_approx(int64_t num, const struct units *units, char *s, + size_t len); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_flags (int num, const struct units *units, char *s, size_t len); +unparse_flags(uint64_t num, const struct units *units, char *s, size_t len); ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL print_flags_table (const struct units *units, FILE *f); @@ -88,26 +89,26 @@ print_flags_table (const struct units *units, FILE *f); #define unparse_flags rk_unparse_flags #define print_flags_table rk_print_flags_table -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL parse_units (const char *s, const struct units *units, const char *def_unit); ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL print_units_table (const struct units *units, FILE *f); -ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL +ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL parse_flags (const char *s, const struct units *units, int orig); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units (int num, const struct units *units, char *s, size_t len); +unparse_units(int64_t num, const struct units *units, char *s, size_t len); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_units_approx (int num, const struct units *units, char *s, - size_t len); +unparse_units_approx(int64_t num, const struct units *units, char *s, + size_t len); ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL -unparse_flags (int num, const struct units *units, char *s, size_t len); +unparse_flags(uint64_t num, const struct units *units, char *s, size_t len); ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL print_flags_table (const struct units *units, FILE *f);