From aeeef0e972293617ceafbb737d46242bc40a616d Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Tue, 26 Feb 2013 12:59:40 +1030 Subject: [PATCH] Add uint64_scaled_to_str() function in str.c --- str.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- str.h | 11 +++++++++++ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/str.c b/str.c index 7b165d31..f8b9e47b 100644 --- a/str.c +++ b/str.c @@ -20,6 +20,7 @@ #define __STR_INLINE #include "str.h" #include "strbuf_helpers.h" +#include "constants.h" #include #include @@ -181,17 +182,29 @@ char *str_str(char *haystack, const char *needle, int haystack_len) return NULL; } +static struct scale_factor { + char symbol; + uint64_t factor; +} + scale_factors[] = { + { 'G', 1024LL * 1024LL * 1024LL }, + { 'g', 1000LL * 1000LL * 1000LL }, + { 'M', 1024LL * 1024LL }, + { 'm', 1000LL * 1000LL }, + { 'K', 1024LL }, + { 'k', 1000LL } + }; + uint64_t scale_factor(const char *str, const char **afterp) { uint64_t factor = 1; - switch (str[0]) { - case 'k': ++str; factor = 1000LL; break; - case 'K': ++str; factor = 1024LL; break; - case 'm': ++str; factor = 1000LL * 1000LL; break; - case 'M': ++str; factor = 1024LL * 1024LL; break; - case 'g': ++str; factor = 1000LL * 1000LL * 1000LL; break; - case 'G': ++str; factor = 1024LL * 1024LL * 1024LL; break; - } + int i; + for (i = 0; i != NELS(scale_factors); ++i) + if (scale_factors[i].symbol == str[0]) { + ++str; + factor = scale_factors[i].factor; + break; + } if (afterp) *afterp = str; else if (*str) @@ -201,7 +214,7 @@ uint64_t scale_factor(const char *str, const char **afterp) int str_to_int64_scaled(const char *str, int base, int64_t *result, const char **afterp) { - if (!(isdigit(*str) || *str == '-' || *str == '+')) + if (isspace(*str)) return 0; const char *end = str; long long value = strtoll(str, (char**)&end, base); @@ -218,7 +231,7 @@ int str_to_int64_scaled(const char *str, int base, int64_t *result, const char * int str_to_uint64_scaled(const char *str, int base, uint64_t *result, const char **afterp) { - if (!isdigit(*str)) + if (isspace(*str)) return 0; const char *end = str; unsigned long long value = strtoull(str, (char**)&end, base); @@ -233,6 +246,23 @@ int str_to_uint64_scaled(const char *str, int base, uint64_t *result, const char return 1; } +int uint64_scaled_to_str(char *str, size_t len, uint64_t value) +{ + char symbol = '\0'; + int i; + for (i = 0; i != NELS(scale_factors); ++i) + if (value % scale_factors[i].factor == 0) { + value /= scale_factors[i].factor; + symbol = scale_factors[i].symbol; + break; + } + strbuf b = strbuf_local(str, len); + strbuf_sprintf(b, "%llu", (unsigned long long) value); + if (symbol) + strbuf_putc(b, symbol); + return strbuf_overrun(b) ? 0 : 1; +} + /* Format a buffer of data as a printable representation, eg: "Abc\x0b\n\0", for display in log messages. @author Andrew Bettison diff --git a/str.h b/str.h index 06888275..58c219fc 100644 --- a/str.h +++ b/str.h @@ -160,6 +160,17 @@ int str_to_int64_scaled(const char *str, int base, int64_t *result, const char * int str_to_uint64_scaled(const char *str, int base, uint64_t *result, const char **afterp); uint64_t scale_factor(const char *str, const char **afterp); +/* Format a string as a decimal integer in ASCII radix notation with a scale suffix character in the + * set {kKmMgG}: 'k' = 1e3, 'K' = 1<<10, 'm' = 1e6, 'M' = 1<<20, 'g' = 1e9, 'G' = * 1<<30 if the + * value is an exact multiple. + * + * Return 1 if the supplied string buffer was large enough to hold the formatted result plus a + * terminating nul character, 0 otherwise. + * + * @author Andrew Bettison + */ +int uint64_scaled_to_str(char *str, size_t len, uint64_t value); + /* Return true if the string resembles a nul-terminated URI. * Based on RFC-3986 generic syntax, assuming nothing about the hierarchical part. *