1 /* human.c -- print human readable file size
2 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Originally contributed by lm@sgi.com;
19 --si, output block size selection, and large file support
20 added by eggert@twinsun.com. */
27 # include <inttypes.h>
30 #include <sys/types.h>
44 #ifndef HAVE_DECL_GETENV
50 # define _(Text) gettext (Text)
61 static const char suffixes[] =
74 /* Convert N to a human readable format in BUF.
76 N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
79 If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in
80 the output number. OUTPUT_BLOCK_SIZE must be a multiple of
81 FROM_BLOCK_SIZE or vice versa.
83 If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
84 possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
85 ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
86 1000 or 1024; it must be at least 2. Most people visually process
87 strings of 3-4 digits effectively, but longer strings of digits are
88 more prone to misinterpretation. Hence, converting to an
89 abbreviated form usually improves readability. Use a suffix
90 indicating which power is being used. For example, assuming
91 -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
92 133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
93 than -OUTPUT_BLOCK_SIZE aren't modified. */
96 human_readable (uintmax_t n, char *buf,
97 int from_block_size, int output_block_size)
106 /* 0 means adjusted N == AMT.TENTHS;
107 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
108 2 means adjusted N == AMT.TENTHS + 0.05;
109 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
112 if (output_block_size < 0)
114 base = -output_block_size;
120 to_block_size = output_block_size;
123 p = buf + LONGEST_HUMAN_READABLE;
127 /* Suppress `used before initialized' warning. */
131 /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units. */
133 if (to_block_size <= from_block_size)
135 int multiplier = from_block_size / to_block_size;
136 amt = n * multiplier;
137 tenths = rounding = 0;
139 if (amt / multiplier != n)
141 /* Overflow occurred during multiplication. We should use
142 multiple precision arithmetic here, but we'll be lazy and
143 resort to floating point. This can yield answers that
144 are slightly off. In practice it is quite rare to
145 overflow uintmax_t, so this is good enough for now. */
147 double damt = n * (double) multiplier;
150 sprintf (buf, "%.0f", damt);
161 while (e * base <= damt && power < sizeof suffixes - 1);
165 sprintf (buf, "%.1f%c", damt, suffixes[power]);
166 if (4 < strlen (buf))
167 sprintf (buf, "%.0f%c", damt, suffixes[power]);
175 int divisor = to_block_size / from_block_size;
176 int r10 = (n % divisor) * 10;
177 int r2 = (r10 % divisor) * 2;
179 tenths = r10 / divisor;
180 rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
184 /* Use power of BASE notation if adjusted AMT is large enough. */
186 if (base && base <= amt)
192 int r10 = (amt % base) * 10 + tenths;
193 int r2 = (r10 % base) * 2 + (rounding >> 1);
196 rounding = (r2 < base
198 : 2 + (base < r2 + rounding));
201 while (base <= amt && power < sizeof suffixes - 1);
203 *--p = suffixes[power];
207 tenths += 2 < rounding + (tenths & 1);
224 if (5 < tenths + (2 < rounding + (amt & 1)))
228 if (amt == base && power < sizeof suffixes - 1)
230 *p = suffixes[power + 1];
238 *--p = '0' + (int) (amt % 10);
239 while ((amt /= 10) != 0);
245 /* The default block size used for output. This number may change in
246 the future as disks get larger. */
247 #ifndef DEFAULT_BLOCK_SIZE
248 # define DEFAULT_BLOCK_SIZE 1024
251 static char const *const block_size_args[] = { "human-readable", "si", 0 };
252 static int const block_size_types[] = { -1024, -1000 };
255 humblock (char const *spec, int *block_size)
259 if (! spec && ! (spec = getenv ("BLOCK_SIZE")))
260 *block_size = getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
261 else if (0 <= (i = argmatch (spec, block_size_args)))
262 *block_size = block_size_types[i];
267 strtol_error e = xstrtoul (spec, &ptr, 0, &val, "eEgGkKmMpPtTyYzZ0");
271 return LONGINT_INVALID_SUFFIX_CHAR;
272 if ((int) val < 0 || val != (int) val)
273 return LONGINT_OVERFLOW;
274 *block_size = (int) val;
281 human_block_size (char const *spec, int report_errors, int *block_size)
283 strtol_error e = humblock (spec, block_size);
284 if (e != LONGINT_OK && report_errors)
285 STRTOL_FATAL_ERROR (spec, _("block size"), e);