1 /* human.c -- print human readable file size
3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
4 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 /* Written by Paul Eggert and Larry McVoy. */
29 # define SIZE_MAX ((size_t) -1)
32 # define UINTMAX_MAX ((uintmax_t) -1)
35 #if HAVE_LOCALE_H && HAVE_LOCALECONV
44 #define _(msgid) gettext (msgid)
50 /* The maximum length of a suffix like "KiB". */
51 #define HUMAN_READABLE_SUFFIX_LENGTH_MAX 3
53 static const char power_letter[] =
56 'K', /* kibi ('k' for kilo is a special case) */
57 'M', /* mega or mebi */
58 'G', /* giga or gibi */
59 'T', /* tera or tebi */
60 'P', /* peta or pebi */
61 'E', /* exa or exbi */
62 'Z', /* zetta or 2**70 */
63 'Y' /* yotta or 2**80 */
67 /* If INEXACT_STYLE is not human_round_to_nearest, and if easily
68 possible, adjust VALUE according to the style. */
71 adjust_value (int inexact_style, long double value)
73 /* Do not use the floorl or ceill functions, as that would mean
74 checking for their presence and possibly linking with the
75 standard math library, which is a porting pain. So leave the
76 value alone if it is too large to easily round. */
77 if (inexact_style != human_round_to_nearest && value < UINTMAX_MAX)
80 value = u + (inexact_style == human_ceiling && u != value);
86 /* Group the digits of NUMBER according to the grouping rules of the
87 current locale. NUMBER contains NUMBERLEN digits. Modify the
88 bytes pointed to by NUMBER in place, subtracting 1 from NUMBER for
89 each byte inserted. Return the starting address of the modified
92 To group the digits, use GROUPING and THOUSANDS_SEP as in `struct
93 lconv' from <locale.h>. */
96 group_number (char *number, size_t numberlen,
97 char const *grouping, char const *thousands_sep)
100 size_t grouplen = SIZE_MAX;
101 size_t thousands_seplen = strlen (thousands_sep);
102 size_t i = numberlen;
104 /* The maximum possible value for NUMBERLEN is the number of digits
105 in the square of the largest uintmax_t, so double the size of
106 uintmax_t before converting to a bound. 302 / 1000 is ceil
107 (log10 (2.0)). Add 1 for integer division truncation. */
108 char buf[2 * sizeof (uintmax_t) * CHAR_BIT * 302 / 1000 + 1];
110 memcpy (buf, number, numberlen);
111 d = number + numberlen;
115 unsigned char g = *grouping;
119 grouplen = g < CHAR_MAX ? g : i;
128 memcpy (d, buf + i, grouplen);
132 d -= thousands_seplen;
133 memcpy (d, thousands_sep, thousands_seplen);
137 /* Convert N to a human readable format in BUF, using the options OPTS.
139 N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
142 Use units of TO_BLOCK_SIZE in the output number. TO_BLOCK_SIZE
145 Use (OPTS & (human_round_to_nearest | human_floor | human_ceiling))
146 to determine whether to take the ceiling or floor of any result
147 that cannot be expressed exactly.
149 If (OPTS & human_group_digits), group the thousands digits
150 according to the locale, e.g., `1,000,000' in an American English
153 If (OPTS & human_autoscale), deduce the output block size
154 automatically; TO_BLOCK_SIZE must be 1 but it has no effect on the
155 output. Use powers of 1024 if (OPTS & human_base_1024), and powers
156 of 1000 otherwise. For example, assuming powers of 1024, 8500
157 would be converted to 8.3, 133456345 to 127, 56990456345 to 53, and
158 so on. Numbers smaller than the power aren't modified.
159 human_autoscale is normally used together with human_SI.
161 If (OPTS & human_space_before_unit), use a space to separate the
162 number from any suffix that is appended as described below.
164 If (OPTS & human_SI), append an SI prefix indicating which power is
165 being used. If in addition (OPTS & human_B), append "B" (if base
166 1000) or "iB" (if base 1024) to the SI prefix. When ((OPTS &
167 human_SI) && ! (OPTS & human_autoscale)), TO_BLOCK_SIZE must be a
168 power of 1024 or of 1000, depending on (OPTS &
172 human_readable (uintmax_t n, char *buf, int opts,
173 uintmax_t from_block_size, uintmax_t to_block_size)
176 opts & (human_round_to_nearest | human_floor | human_ceiling);
177 unsigned int base = opts & human_base_1024 ? 1024 : 1000;
181 int exponent_max = sizeof power_letter - 1;
184 char const *integerlim;
186 /* 0 means adjusted N == AMT.TENTHS;
187 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
188 2 means adjusted N == AMT.TENTHS + 0.05;
189 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
192 char const *decimal_point = ".";
193 size_t decimal_pointlen = 1;
194 char const *grouping = "";
195 char const *thousands_sep = "";
196 #if HAVE_LOCALE_H && HAVE_LOCALECONV
197 struct lconv const *l = localeconv ();
198 size_t pointlen = strlen (l->decimal_point);
199 if (0 < pointlen && pointlen <= MB_LEN_MAX)
201 decimal_point = l->decimal_point;
202 decimal_pointlen = pointlen;
204 grouping = l->grouping;
205 if (strlen (l->thousands_sep) <= MB_LEN_MAX)
206 thousands_sep = l->thousands_sep;
209 psuffix = buf + LONGEST_HUMAN_READABLE - HUMAN_READABLE_SUFFIX_LENGTH_MAX;
212 /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE
213 units. If this can be done exactly with integer arithmetic, do
214 not use floating point operations. */
215 if (to_block_size <= from_block_size)
217 if (from_block_size % to_block_size == 0)
219 uintmax_t multiplier = from_block_size / to_block_size;
220 amt = n * multiplier;
221 if (amt / multiplier == n)
225 goto use_integer_arithmetic;
229 else if (from_block_size != 0 && to_block_size % from_block_size == 0)
231 uintmax_t divisor = to_block_size / from_block_size;
232 uintmax_t r10 = (n % divisor) * 10;
233 uintmax_t r2 = (r10 % divisor) * 2;
235 tenths = r10 / divisor;
236 rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
237 goto use_integer_arithmetic;
241 /* Either the result cannot be computed easily using uintmax_t,
242 or from_block_size is zero. Fall back on floating point.
243 FIXME: This can yield answers that are slightly off. */
245 long double dto_block_size = to_block_size;
246 long double damt = n * (from_block_size / dto_block_size);
248 size_t nonintegerlen;
250 if (! (opts & human_autoscale))
252 sprintf (buf, "%.0Lf", adjust_value (inexact_style, damt));
253 buflen = strlen (buf);
266 while (e * base <= damt && exponent < exponent_max);
270 sprintf (buf, "%.1Lf", adjust_value (inexact_style, damt));
271 buflen = strlen (buf);
272 nonintegerlen = decimal_pointlen + 1;
274 if (1 + nonintegerlen + ! (opts & human_base_1024) < buflen
275 || ((opts & human_suppress_point_zero)
276 && buf[buflen - 1] == '0'))
278 sprintf (buf, "%.0Lf",
279 adjust_value (inexact_style, damt * 10) / 10);
280 buflen = strlen (buf);
285 p = psuffix - buflen;
286 memmove (p, buf, buflen);
287 integerlim = p + buflen - nonintegerlen;
291 use_integer_arithmetic:
293 /* The computation can be done exactly, with integer arithmetic.
295 Use power of BASE notation if requested and if adjusted AMT is
298 if (opts & human_autoscale)
306 unsigned int r10 = (amt % base) * 10 + tenths;
307 unsigned int r2 = (r10 % base) * 2 + (rounding >> 1);
310 rounding = (r2 < base
311 ? (r2 + rounding) != 0
312 : 2 + (base < r2 + rounding));
315 while (base <= amt && exponent < exponent_max);
319 if (inexact_style == human_round_to_nearest
320 ? 2 < rounding + (tenths & 1)
321 : inexact_style == human_ceiling && 0 < rounding)
334 && (tenths || ! (opts & human_suppress_point_zero)))
337 p -= decimal_pointlen;
338 memcpy (p, decimal_point, decimal_pointlen);
339 tenths = rounding = 0;
345 if (inexact_style == human_round_to_nearest
346 ? 5 < tenths + (0 < rounding + (amt & 1))
347 : inexact_style == human_ceiling && 0 < tenths + rounding)
351 if ((opts & human_autoscale)
352 && amt == base && exponent < exponent_max)
355 if (! (opts & human_suppress_point_zero))
358 p -= decimal_pointlen;
359 memcpy (p, decimal_point, decimal_pointlen);
369 int digit = amt % 10;
372 while ((amt /= 10) != 0);
376 if (opts & human_group_digits)
377 p = group_number (p, integerlim - p, grouping, thousands_sep);
385 for (power = 1; power < to_block_size; power *= base)
386 if (++exponent == exponent_max)
390 if ((exponent | (opts & human_B)) && (opts & human_space_before_unit))
394 *psuffix++ = (! (opts & human_base_1024) && exponent == 1
396 : power_letter[exponent]);
400 if ((opts & human_base_1024) && exponent)
412 /* The default block size used for output. This number may change in
413 the future as disks get larger. */
414 #ifndef DEFAULT_BLOCK_SIZE
415 # define DEFAULT_BLOCK_SIZE 1024
418 static char const *const block_size_args[] = { "human-readable", "si", 0 };
419 static int const block_size_opts[] =
421 human_autoscale + human_SI + human_base_1024,
422 human_autoscale + human_SI
426 default_block_size (void)
428 return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
432 humblock (char const *spec, uintmax_t *block_size, int *options)
438 && ! (spec = getenv ("BLOCK_SIZE"))
439 && ! (spec = getenv ("BLOCKSIZE")))
440 *block_size = default_block_size ();
445 opts |= human_group_digits;
449 if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_opts)))
451 opts |= block_size_opts[i];
457 strtol_error e = xstrtoumax (spec, &ptr, 0, block_size,
458 "eEgGkKmMpPtTyYzZ0");
461 for (; ! ('0' <= *spec && *spec <= '9'); spec++)
467 if (ptr[-1] != 'B' || ptr[-2] == 'i')
468 opts |= human_base_1024;
479 human_options (char const *spec, bool report_errors, uintmax_t *block_size)
482 strtol_error e = humblock (spec, block_size, &opts);
483 if (*block_size == 0)
485 *block_size = default_block_size ();
488 if (e != LONGINT_OK && report_errors)
489 STRTOL_FATAL_ERROR (spec, _("block size"), e);