1 /* human.c -- print human readable file size
2 Copyright (C) 1996, 1997, 1998, 1999 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. */
26 #include <sys/types.h>
46 #ifndef HAVE_DECL_GETENV
52 # define _(Text) gettext (Text)
63 static const char suffixes[] =
76 /* Convert N to a human readable format in BUF.
78 N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
81 If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in
82 the output number. OUTPUT_BLOCK_SIZE must be a multiple of
83 FROM_BLOCK_SIZE or vice versa.
85 If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
86 possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
87 ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
88 1000 or 1024; it must be at least 2. Most people visually process
89 strings of 3-4 digits effectively, but longer strings of digits are
90 more prone to misinterpretation. Hence, converting to an
91 abbreviated form usually improves readability. Use a suffix
92 indicating which power is being used. For example, assuming
93 -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
94 133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
95 than -OUTPUT_BLOCK_SIZE aren't modified. */
98 human_readable (uintmax_t n, char *buf,
99 int from_block_size, int output_block_size)
108 /* 0 means adjusted N == AMT.TENTHS;
109 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
110 2 means adjusted N == AMT.TENTHS + 0.05;
111 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
114 if (output_block_size < 0)
116 base = -output_block_size;
122 to_block_size = output_block_size;
125 p = buf + LONGEST_HUMAN_READABLE;
129 /* Suppress `used before initialized' warning. */
133 /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units. */
135 if (to_block_size <= from_block_size)
137 int multiplier = from_block_size / to_block_size;
138 amt = n * multiplier;
139 tenths = rounding = 0;
141 if (amt / multiplier != n)
143 /* Overflow occurred during multiplication. We should use
144 multiple precision arithmetic here, but we'll be lazy and
145 resort to floating point. This can yield answers that
146 are slightly off. In practice it is quite rare to
147 overflow uintmax_t, so this is good enough for now. */
149 double damt = n * (double) multiplier;
152 sprintf (buf, "%.0f", damt);
163 while (e * base <= damt && power < sizeof suffixes - 1);
167 sprintf (buf, "%.1f%c", damt, suffixes[power]);
168 if (4 < strlen (buf))
169 sprintf (buf, "%.0f%c", damt, suffixes[power]);
177 int divisor = to_block_size / from_block_size;
178 int r10 = (n % divisor) * 10;
179 int r2 = (r10 % divisor) * 2;
181 tenths = r10 / divisor;
182 rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
186 /* Use power of BASE notation if adjusted AMT is large enough. */
188 if (base && base <= amt)
194 int r10 = (amt % base) * 10 + tenths;
195 int r2 = (r10 % base) * 2 + (rounding >> 1);
198 rounding = (r2 < base
200 : 2 + (base < r2 + rounding));
203 while (base <= amt && power < sizeof suffixes - 1);
205 *--p = suffixes[power];
209 tenths += 2 < rounding + (tenths & 1);
226 if (5 < tenths + (2 < rounding + (amt & 1)))
230 if (amt == base && power < sizeof suffixes - 1)
232 *p = suffixes[power + 1];
240 *--p = '0' + (int) (amt % 10);
241 while ((amt /= 10) != 0);
247 /* The default block size used for output. This number may change in
248 the future as disks get larger. */
249 #ifndef DEFAULT_BLOCK_SIZE
250 # define DEFAULT_BLOCK_SIZE 1024
253 static char const *const block_size_args[] = { "human-readable", "si", 0 };
254 static int const block_size_types[] = { -1024, -1000 };
257 humblock (char const *spec, int *block_size)
261 if (! spec && ! (spec = getenv ("BLOCK_SIZE")))
262 *block_size = getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
263 else if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_types)))
264 *block_size = block_size_types[i];
269 strtol_error e = xstrtoul (spec, &ptr, 0, &val, "eEgGkKmMpPtTyYzZ0");
273 return LONGINT_INVALID_SUFFIX_CHAR;
274 if ((int) val < 0 || val != (int) val)
275 return LONGINT_OVERFLOW;
276 *block_size = (int) val;
283 human_block_size (char const *spec, int report_errors, int *block_size)
285 strtol_error e = humblock (spec, block_size);
286 if (e != LONGINT_OK && report_errors)
287 STRTOL_FATAL_ERROR (spec, _("block size"), e);