commit: c913c735be27d2f67221abf255dc38e31a9c3bad Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> AuthorDate: Sat Nov 12 17:22:17 2016 +0000 Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> CommitDate: Sat Nov 12 17:22:17 2016 +0000 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c913c735
human_readable: resync with upstream busybox #590932 URL: https://bugs.gentoo.org/590932 Reported-by: S. Gilles <sgilles <AT> math.umd.edu> libq/human_readable.c | 77 +++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/libq/human_readable.c b/libq/human_readable.c index 3a8aa34..0bb044a 100644 --- a/libq/human_readable.c +++ b/libq/human_readable.c @@ -13,16 +13,13 @@ * representations (say, powers of 1024) and manipulating coefficients. * The base ten "bytes" output could be handled similarly. * - * 2) This routine always outputs a decimal point and a tenths digit when - * display_unit != 0. Hence, it isn't uncommon for the returned string + * 2) This routine outputs a decimal point and a tenths digit when + * display_unit == 0. Hence, it isn't uncommon for the returned string * to have a length of 5 or 6. * - * It might be nice to add a flag to indicate no decimal digits in - * that case. This could be either an additional parameter, or a - * special value of display_unit. Such a flag would also be nice for du. + * If block_size is also 0, no decimal digits are printed. * - * Some code to omit the decimal point and tenths digit is sketched out - * and "#if 0"'d below. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include <stdio.h> @@ -33,59 +30,59 @@ enum { MEGABYTE = (KILOBYTE*1024), GIGABYTE = (MEGABYTE*1024) }; -const char *make_human_readable_str(unsigned long long size, + +const char* make_human_readable_str(unsigned long long val, unsigned long block_size, unsigned long display_unit) { - /* The code will adjust for additional (appended) units. */ - static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' }; - static const char fmt[] = "%'Lu"; - static const char fmt_tenths[] = "%'Lu%s%d%c"; + static const char unit_chars[] = { + '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' + }; + + unsigned frac; /* 0..9 - the fractional digit */ + const char *u; + const char *fmt; static char str[21]; /* Sufficient for 64 bit unsigned integers. */ - unsigned long long val; - int frac; - const char *u; - const char *f; + if (val == 0) + return "0"; - u = zero_and_units; - f = fmt; + fmt = "%llu"; + if (block_size > 1) + val *= block_size; frac = 0; - - val = size * block_size; - if (val == 0) { - return u; - } + u = unit_chars; if (display_unit) { - val += display_unit/2; /* Deal with rounding. */ - val /= display_unit; /* Don't combine with the line above!!! */ + val += display_unit/2; /* Deal with rounding */ + val /= display_unit; /* Don't combine with the line above! */ + /* will just print it as ulonglong (below) */ } else { - ++u; - while ((val >= KILOBYTE) - && (u < zero_and_units + sizeof(zero_and_units) - 1)) { - f = fmt_tenths; - ++u; - frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE; - val /= KILOBYTE; + while ((val >= 1024) + /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */ + ) { + fmt = "%llu.%u%c"; + u++; + frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024; + val /= 1024; } - if (frac >= 10) { /* We need to round up here. */ + if (frac >= 10) { /* we need to round up here */ ++val; frac = 0; } -#if 0 - /* Sample code to omit decimal point and tenths digit. */ - if (1) { /* no_tenths */ - if (frac >= 5) +#if 1 + /* If block_size is 0, dont print fractional part */ + if (block_size == 0) { + if (frac >= 5) { ++val; - f = "%Lu%*c"; /* fmt_no_tenths */ + } + fmt = "%llu%*c"; frac = 1; } #endif } - /* If f==fmt then 'frac' and 'u' are ignored. */ - snprintf(str, sizeof(str), f, val, decimal_point, frac, *u); + snprintf(str, sizeof(str), fmt, val, frac, *u); return str; }