Index: lib/libutil/humanize_number.3 =================================================================== --- lib/libutil/humanize_number.3 (revision 317681) +++ lib/libutil/humanize_number.3 (working copy) @@ -28,7 +28,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd October 7, 2013 +.Dd May 3, 2017 .Dt HUMANIZE_NUMBER 3 .Os .Sh NAME @@ -139,6 +139,10 @@ The following flags may be passed in .Fa flags : .Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent +.It Dv HN_FRACTIONAL +Display up to two additional fractional digits if they would fit, +unless the value was so small (i.e. less than 1000 or less than 1024) +that it wouldn't make sense. .It Dv HN_DECIMAL If the final result is less than 10, display it using one decimal place. .It Dv HN_NOSPACE Index: lib/libutil/humanize_number.c =================================================================== --- lib/libutil/humanize_number.c (revision 317681) +++ lib/libutil/humanize_number.c (working copy) @@ -157,13 +157,43 @@ } } - /* If a value <= 9.9 after rounding and ... */ /* - * XXX - should we make sure there is enough space for the decimal - * place and if not, don't do HN_DECIMAL? + * Generate base output */ - if (((quotient == 9 && remainder < divisordeccut) || quotient < 9) && - i > 0 && flags & HN_DECIMAL) { + r = snprintf(buf, len, "%" PRId64 "%s%s%s", + sign * (quotient + (remainder + divisor / 2) / divisor), + sep, SCALE2PREFIX(i), suffix); + + if ((flags & HN_FRACTIONAL) && (u_int)r + 3 <= len && i) { + /* + * If FRACTIONAL is specified output up to two fractional + * digits, unless the value was not divided out. + */ + int64_t frac; + int n; + + n = (int)len - r - 2; + frac = 1; + if (n > 2) /* max 2 fractional digits */ + n = 2; + + while (n) { + frac = frac * 10; + --n; + } + s1 = (int)quotient + ((remainder * frac + divisor / 2) / + divisor / frac); + s2 = ((remainder * frac + divisor / 2) / divisor) % frac; + r = snprintf(buf, len, "%d%s%d%s%s%s", + sign * s1, localeconv()->decimal_point, s2, + sep, SCALE2PREFIX(i), suffix); + } else if ((flags & HN_DECIMAL) && (u_int)r + 3 <= len && + (((quotient == 9 && remainder < divisordeccut) || + quotient < 9) && i > 0)) { + /* + * If DECIMAL is specified and the value is <= 9.9 after + * rounding, and it fits, add one fractional digit. + */ s1 = (int)quotient + ((remainder * 10 + divisor / 2) / divisor / 10); s2 = ((remainder * 10 + divisor / 2) / divisor) % 10; @@ -170,10 +200,6 @@ 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, "%" PRId64 "%s%s%s", - sign * (quotient + (remainder + divisor / 2) / divisor), - sep, SCALE2PREFIX(i), suffix); - + } return (r); } Index: lib/libutil/libutil.h =================================================================== --- lib/libutil/libutil.h (revision 317681) +++ lib/libutil/libutil.h (working copy) @@ -223,6 +223,7 @@ #define HN_B 0x04 #define HN_DIVISOR_1000 0x08 #define HN_IEC_PREFIXES 0x10 +#define HN_FRACTIONAL 0x20 /* Values for humanize_number(3)'s scale parameter. */ #define HN_GETSCALE 0x10 Index: bin/df/df.c =================================================================== --- bin/df/df.c (revision 317681) +++ bin/df/df.c (working copy) @@ -72,6 +72,10 @@ #define UNITS_SI 1 #define UNITS_2 2 +#ifndef HN_FRACTIONAL +#define HN_FRACTIONAL HN_DECIMAL +#endif + /* Maximum widths of various fields. */ struct maxwidths { int mntfrom; @@ -410,10 +414,10 @@ static void prthumanval(const char *fmt, int64_t bytes) { - char buf[6]; + char buf[7]; int flags; - flags = HN_B | HN_NOSPACE | HN_DECIMAL; + flags = HN_B | HN_NOSPACE | HN_FRACTIONAL; if (hflag == UNITS_SI) flags |= HN_DIVISOR_1000; @@ -433,7 +437,7 @@ char buf[6]; int flags; - flags = HN_NOSPACE | HN_DECIMAL | HN_DIVISOR_1000; + flags = HN_NOSPACE | HN_FRACTIONAL | HN_DIVISOR_1000; humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), bytes, "", HN_AUTOSCALE, flags); Index: usr.sbin/pstat/pstat.c =================================================================== --- usr.sbin/pstat/pstat.c (revision 317681) +++ usr.sbin/pstat/pstat.c (working copy) @@ -72,6 +72,10 @@ #include #include +#ifndef HN_FRACTIONAL +#define HN_FRACTIONAL HN_DECIMAL +#endif + enum { NL_CONSTTY, NL_MAXFILES, @@ -492,10 +496,10 @@ if (humanflag) { humanize_number(usedbuf, sizeof(usedbuf), CONVERT_BLOCKS(bused), "", - HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_FRACTIONAL); humanize_number(availbuf, sizeof(availbuf), CONVERT_BLOCKS(bavail), "", - HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_FRACTIONAL); printf("%8s %8s %5.0f%%\n", usedbuf, availbuf, bpercent); } else { printf("%8jd %8jd %5.0f%%\n", (intmax_t)CONVERT(bused),