Subject: humanize_number again
To: None <tech-userlevel@netbsd.org>
From: Tomas Svensson <tsn@gbdev.net>
List: tech-userlevel
Date: 02/04/2002 01:02:21
Hi,
Here is a modified version of humanize_number(9) that I think should
be sufficient for my df(1)/du(1) humanization needs. Differences
from the kernel version are:
- the bytes argument is signed (negative sizes can be used).
- rounding is done like floating point numbers were used.
- the suffix-prefix K is changed to k, which should be correct
according to standards.
- three flags can be used : HN_DECIMAL tells it to use one decimal
for numbers less than 10, HN_NOSPACE removes the space between
the number and the prefix and HN_B will use the prefix "B" for
numbers that would normally not have a prefix (bytes less than
1000). Use 0 if no flags are used (not worth the trouble with
varargs?).
- Tomas
#define HN_DECIMAL 1
#define HN_NOSPACE 2
#define HN_B 4
int humanize_number(char *buf, size_t len, int64_t bytes,
const char *suffix, int divisor, int flags) {
static const char prefixes[] = " kMGTPE";
int i, r;
int64_t max, s1, s2, sign;
size_t baselen, suffixlen;
if (buf == NULL)
return -1;
if (len > 0)
buf[0] = '\0';
if (bytes < 0) {
sign = -1;
bytes *= -100;
baselen = 4;
} else {
sign = 1;
bytes *= 100;
baselen = 3;
}
suffixlen = strlen(suffix);
/* check if enough room for `x y' + suffix + `\0' */
if (len < baselen + suffixlen + 1)
return (-1);
max = 100;
for (i = 0; i < len - suffixlen - baselen + ((flags & HN_NOSPACE) ?
1 : 0) ; i++)
max *= 10;
for (i = 0; bytes >= max && i < sizeof(prefixes); i++)
bytes /= divisor;
if (bytes < 1000 && flags & HN_DECIMAL) {
if (len < (baselen + 2 + ( (flags & HN_NOSPACE) || (i == 0
&& !(flags & HN_B)) ? 0 : 1)))
return (-1);
s1 = bytes / 100;
if ((s2 = (( (bytes % 100 ) + 5 ) / 10 ) ) == 10 ) {
s1++;
s2 = 0;
}
r = snprintf(buf, len, "%qd%s%qd%s%c%s", sign * s1,
localeconv()->decimal_points2, (i == 0 && !(flags & HN_B) )
|| flags & HN_NOSPACE ? "" : " ", (i == 0 && (flags &
HN_B)) ? 'B' : prefixes[i], suffix);
} else
r = snprintf(buf, len, "%qd%s%c%s", sign * ((bytes + 50) / 100),
i == 0 || flags & HN_NOSPACE ? "" : " ", (i == 0 &&
(flags & HN_B)) ? 'B' : prefixes[i], suffix);
return r;
}