diff --git a/lib/libutil/humanize_number.3 b/lib/libutil/humanize_number.3 index 09ed619a5653..5e1f9aeeea97 100644 --- a/lib/libutil/humanize_number.3 +++ b/lib/libutil/humanize_number.3 @@ -35,7 +35,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd May 25, 2004 +.Dd Sep 25, 2004 .Dt HUMANIZE_NUMBER 3 .Os .Sh NAME @@ -53,14 +53,13 @@ .Sh DESCRIPTION The .Fn humanize_number -function formats the signed 64-bit quantity given in +function formats the signed 64 bit quantity given in .Fa number into .Fa buffer . A space and then .Fa suffix is appended to the end. -The buffer pointed to by .Fa buffer must be at least .Fa len @@ -80,30 +79,29 @@ with the appropriate SI designator. The prefixes are: .Bl -column "Prefix" "Description" "Multiplier" -offset indent .It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier" -.It Li k Ta No kilo Ta 1024 -.It Li M Ta No mega Ta 1048576 -.It Li G Ta No giga Ta 1073741824 -.It Li T Ta No tera Ta 1099511627776 -.It Li P Ta No peta Ta 1125899906842624 -.It Li E Ta No exa Ta 1152921504606846976 +.It k kilo 1024 +.It M mega 1048576 +.It G giga 1073741824 +.It T tera 1099511627776 +.It P peta 1125899906842624 +.It E exa 1152921504606846976 .El .Pp -The .Fa len -argument must be at least 4 plus the length of +must be at least 4 plus the length of .Fa suffix , in order to ensure a useful result is generated into .Fa buffer . To use a specific prefix, specify this as .Fa scale -(multiplier = 1024 ^ scale). -This cannot be combined with any of the +(Multiplier = 1024 ^ scale). +This can not be combined with any of the .Fa scale flags below. .Pp The following flags may be passed in -.Fa scale : -.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent +.Pa scale : +.Bl -tag -width Dv -offset indent .It Dv HN_AUTOSCALE Format the buffer using the lowest multiplier possible. .It Dv HN_GETSCALE @@ -113,8 +111,8 @@ must be divided to fit) instead of formatting it to the buffer. .El .Pp The following flags may be passed in -.Fa flags : -.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent +.Pa flags : +.Bl -tag -width Dv -offset indent .It Dv HN_DECIMAL If the final result is less than 10, display it using one digit. .It Dv HN_NOSPACE @@ -122,27 +120,21 @@ Do not put a space between .Fa number and the prefix. .It Dv HN_B -Use -.Ql B -(bytes) as prefix if the original result does not have a prefix. +Use 'B' (bytes) as prefix if the original result does not have a prefix. .It Dv HN_DIVISOR_1000 Divide .Fa number with 1000 instead of 1024. .El .Sh RETURN VALUES -The .Fn humanize_number -function returns the number of characters stored in +returns the number of characters stored in .Fa buffer -(excluding the terminating -.Dv NUL ) -upon success, or \-1 upon failure. +(excluding the terminating NUL) upon success, or \-1 upon failure. If .Dv HN_GETSCALE is specified, the prefix index number will be returned instead. .Sh HISTORY -The .Fn humanize_number -function first appeared in +first appeared in .Nx 2.0 . diff --git a/lib/libutil/humanize_number.c b/lib/libutil/humanize_number.c index 51bd24bb20d6..21d5e3962c45 100644 --- a/lib/libutil/humanize_number.c +++ b/lib/libutil/humanize_number.c @@ -1,4 +1,4 @@ -/* $NetBSD: humanize_number.c,v 1.5 2003/12/26 11:30:36 simonb Exp $ */ +/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. @@ -52,10 +52,10 @@ int humanize_number(char *buf, size_t len, int64_t bytes, const char *suffix, int scale, int flags) { - const char *prefixes; - int i, r; - int64_t divisor, max, s1, s2, sign; - size_t baselen, suffixlen; + const char *prefixes, *sep; + int b, i, r, maxscale, s1, s2, sign; + int64_t divisor, max; + size_t baselen; assert(buf != NULL); assert(suffix != NULL); @@ -64,18 +64,27 @@ humanize_number(char *buf, size_t len, int64_t bytes, if (flags & HN_DIVISOR_1000) { /* SI for decimal multiplies */ divisor = 1000; - prefixes = " kMGTPE"; + if (flags & HN_B) + prefixes = "B\0k\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0k\0M\0G\0T\0P\0E"; } else { /* * binary multiplies * XXX IEC 60027-2 recommends Ki, Mi, Gi... */ divisor = 1024; - prefixes = " KMGTPE"; + if (flags & HN_B) + prefixes = "B\0K\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0K\0M\0G\0T\0P\0E"; } - if ((size_t) scale >= strlen(prefixes) && scale != HN_AUTOSCALE && - scale != HN_GETSCALE) +#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1]) + maxscale = 7; + + if (scale >= maxscale && + (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0) return (-1); if (buf == NULL || suffix == NULL) @@ -86,75 +95,54 @@ humanize_number(char *buf, size_t len, int64_t bytes, if (bytes < 0) { sign = -1; bytes *= -100; - baselen = 4; + baselen = 3; /* sign, digit, prefix */ } else { sign = 1; bytes *= 100; - baselen = 3; + baselen = 2; /* digit, prefix */ } + if (flags & HN_NOSPACE) + sep = ""; + else { + sep = " "; + baselen++; + } + baselen += strlen(suffix); - suffixlen = strlen(suffix); - - /* check if enough room for `x y' + suffix + `\0' */ - if (len < baselen + suffixlen + 1) + /* Check if enough room for `x y' + suffix + `\0' */ + if (len < baselen + 1) return (-1); - if (flags & HN_DIVISOR_1000) - divisor = 1000; - else - divisor = 1024; + if (scale & (HN_AUTOSCALE | HN_GETSCALE)) { + /* See if there is additional columns can be used. */ + for (max = 100, i = len - baselen; i-- > 0;) + max *= 10; - max = 100; - for (i = 0; - (size_t) i < len - suffixlen - baselen + ((flags & HN_NOSPACE) ? - 1 : 0); i++) - max *= 10; - - if ((scale & HN_AUTOSCALE) || (scale & HN_GETSCALE)) { - for (i = 0; bytes >= max && prefixes[i + 1]; i++) + for (i = 0; bytes >= max && i < maxscale; i++) bytes /= divisor; - } else { - for (i = 0; i < scale && prefixes[i + 1]; i++) - bytes /= divisor; - } - - if (scale & HN_GETSCALE) - return (i); - - 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; - } - if (s1 < 10 && i == 0) - /* Don't ever use .0 for a number less than 10. */ - r = snprintf(buf, len, "%lld%s%c%s", - /* LONGLONG */ - (long long)(sign * s1), - (i == 0 && !(flags & HN_B)) || flags & HN_NOSPACE ? - "" : " ", (i == 0 && (flags & HN_B)) ? 'B' : - prefixes[i], suffix); - else - r = snprintf(buf, len, "%lld%s%lld%s%c%s", - /* LONGLONG */ - (long long)(sign * s1), - localeconv()->decimal_point, - /* LONGLONG */ - (long long)s2, - (i == 0 && !(flags & HN_B)) || flags & HN_NOSPACE ? - "" : " ", (i == 0 && (flags & HN_B)) ? 'B' : - prefixes[i], suffix); + if (scale & HN_GETSCALE) + return (i); } else - r = snprintf(buf, len, "%lld%s%c%s", + for (i = 0; i < scale && i < maxscale; i++) + bytes /= divisor; + + /* If a value <= 9.9 after rounding and ... */ + if (bytes < 995 && i > 0 && flags & HN_DECIMAL) { + /* baselen + \0 + .N */ + if (len < baselen + 1 + 2) + return (-1); + b = ((int)bytes + 5) / 10; + s1 = b / 10; + s2 = b % 10; + r = snprintf(buf, len, "%d%s%d%s%s%s", + sign * s1, localeconv()->decimal_point, s2, + sep, SCALE2PREFIX(i), suffix); + } else + r = snprintf(buf, len, "%lld%s%s%s", /* LONGLONG */ (long long)(sign * ((bytes + 50) / 100)), - i == 0 || flags & HN_NOSPACE ? "" : " ", (i == 0 && - (flags & HN_B)) ? 'B' : prefixes[i], suffix); + sep, SCALE2PREFIX(i), suffix); return (r); }