Add uint64_scaled_to_str() function in str.c

This commit is contained in:
Andrew Bettison 2013-02-26 12:59:40 +10:30
parent 5430b70640
commit aeeef0e972
2 changed files with 51 additions and 10 deletions

50
str.c
View File

@ -20,6 +20,7 @@
#define __STR_INLINE
#include "str.h"
#include "strbuf_helpers.h"
#include "constants.h"
#include <stdlib.h>
#include <stdio.h>
@ -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 <andrew@servalproject.com>

11
str.h
View File

@ -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 <andrew@servalproject.com>
*/
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.
*