X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fhuman.c;h=600614e011a54bca7ee6668d5d776b5500ce7ea6;hb=19e03725a5160847ec25e1ac559cedb86bf67205;hp=132ba019a936de8e480738c54a0ca31421e5826d;hpb=4abb9676d3b0c61c6111676d8c4eed352abab3bb;p=gnulib.git diff --git a/lib/human.c b/lib/human.c index 132ba019a..600614e01 100644 --- a/lib/human.c +++ b/lib/human.c @@ -30,6 +30,12 @@ # include #endif +#if HAVE_STRING_H +# include +#else +# include +#endif + #ifndef CHAR_BIT # define CHAR_BIT 8 #endif @@ -67,15 +73,27 @@ static const char suffixes[] = 'Y' /* Yotta */ }; +/* Like human_readable_inexact, except always round to even. */ +char * +human_readable (uintmax_t n, char *buf, + int from_block_size, int output_block_size) +{ + return human_readable_inexact (n, buf, from_block_size, output_block_size, + human_round_to_even); +} + /* Convert N to a human readable format in BUF. N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must - be positive. + be nonnegative. If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in the output number. OUTPUT_BLOCK_SIZE must be a multiple of FROM_BLOCK_SIZE or vice versa. + Use INEXACT_STYLE to determine whether to take the ceiling or floor + of any result that cannot be expressed exactly. + If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either @@ -89,13 +107,14 @@ static const char suffixes[] = than -OUTPUT_BLOCK_SIZE aren't modified. */ char * -human_readable (uintmax_t n, char *buf, - int from_block_size, int output_block_size) +human_readable_inexact (uintmax_t n, char *buf, + int from_block_size, int output_block_size, + enum human_inexact_style inexact_style) { uintmax_t amt; int base; int to_block_size; - int tenths; + int tenths = 0; int power; char *p; @@ -103,7 +122,7 @@ human_readable (uintmax_t n, char *buf, 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05; 2 means adjusted N == AMT.TENTHS + 0.05; 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */ - int rounding; + int rounding = 0; if (output_block_size < 0) { @@ -130,7 +149,6 @@ human_readable (uintmax_t n, char *buf, { int multiplier = from_block_size / to_block_size; amt = n * multiplier; - tenths = rounding = 0; if (amt / multiplier != n) { @@ -166,6 +184,8 @@ human_readable (uintmax_t n, char *buf, return buf; } } + else if (from_block_size == 0) + amt = 0; else { int divisor = to_block_size / from_block_size; @@ -200,24 +220,33 @@ human_readable (uintmax_t n, char *buf, if (amt < 10) { - tenths += 2 < rounding + (tenths & 1); - - if (tenths == 10) + if (2 * (1 - (int) inexact_style) + < rounding + (tenths & (inexact_style == human_round_to_even))) { - amt++; - tenths = 0; + tenths++; + rounding = 0; + + if (tenths == 10) + { + amt++; + tenths = 0; + } } if (amt < 10) { *--p = '0' + tenths; *--p = '.'; - tenths = 0; + tenths = rounding = 0; } } } - if (5 < tenths + (2 < rounding + (amt & 1))) + if (inexact_style == human_ceiling + ? 0 < tenths + rounding + : inexact_style == human_round_to_even + ? 5 < tenths + (2 < rounding + (amt & 1)) + : /* inexact_style == human_floor */ 0) { amt++; @@ -247,13 +276,19 @@ human_readable (uintmax_t n, char *buf, static char const *const block_size_args[] = { "human-readable", "si", 0 }; static int const block_size_types[] = { -1024, -1000 }; +static int +default_block_size (void) +{ + return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE; +} + static strtol_error humblock (char const *spec, int *block_size) { int i; if (! spec && ! (spec = getenv ("BLOCK_SIZE"))) - *block_size = getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE; + *block_size = default_block_size (); else if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_types))) *block_size = block_size_types[i]; else @@ -277,6 +312,11 @@ void human_block_size (char const *spec, int report_errors, int *block_size) { strtol_error e = humblock (spec, block_size); + if (*block_size == 0) + { + *block_size = default_block_size (); + e = LONGINT_INVALID; + } if (e != LONGINT_OK && report_errors) STRTOL_FATAL_ERROR (spec, _("block size"), e); }