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;
140 if (amt / multiplier != n)
142 /* Overflow occurred during multiplication. We should use
143 multiple precision arithmetic here, but we'll be lazy and
144 resort to floating point. This can yield answers that
145 are slightly off. In practice it is quite rare to
146 overflow uintmax_t, so this is good enough for now. */
148 double damt = n * (double) multiplier;
151 sprintf (buf, "%.0f", damt);
162 while (e * base <= damt && power < sizeof suffixes - 1);
166 sprintf (buf, "%.1f%c", damt, suffixes[power]);
167 if (4 < strlen (buf))
168 sprintf (buf, "%.0f%c", damt, suffixes[power]);
174 else if (from_block_size == 0)
178 int divisor = to_block_size / from_block_size;
179 int r10 = (n % divisor) * 10;
180 int r2 = (r10 % divisor) * 2;
182 tenths = r10 / divisor;
183 rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
187 /* Use power of BASE notation if adjusted AMT is large enough. */
189 if (base && base <= amt)
195 int r10 = (amt % base) * 10 + tenths;
196 int r2 = (r10 % base) * 2 + (rounding >> 1);
199 rounding = (r2 < base
201 : 2 + (base < r2 + rounding));
204 while (base <= amt && power < sizeof suffixes - 1);
206 *--p = suffixes[power];
210 tenths += 2 < rounding + (tenths & 1);
227 if (5 < tenths + (2 < rounding + (amt & 1)))
231 if (amt == base && power < sizeof suffixes - 1)
233 *p = suffixes[power + 1];
241 *--p = '0' + (int) (amt % 10);
242 while ((amt /= 10) != 0);
248 /* The default block size used for output. This number may change in
249 the future as disks get larger. */
250 #ifndef DEFAULT_BLOCK_SIZE
251 # define DEFAULT_BLOCK_SIZE 1024
254 static char const *const block_size_args[] = { "human-readable", "si", 0 };
255 static int const block_size_types[] = { -1024, -1000 };
258 humblock (char const *spec, int *block_size)
262 if (! spec && ! (spec = getenv ("BLOCK_SIZE")))
263 *block_size = getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
264 else if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_types)))
265 *block_size = block_size_types[i];
270 strtol_error e = xstrtoul (spec, &ptr, 0, &val, "eEgGkKmMpPtTyYzZ0");
274 return LONGINT_INVALID_SUFFIX_CHAR;
275 if ((int) val < 0 || val != (int) val)
276 return LONGINT_OVERFLOW;
277 *block_size = (int) val;
284 human_block_size (char const *spec, int report_errors, int *block_size)
286 strtol_error e = humblock (spec, block_size);
287 if (e != LONGINT_OK && report_errors)
288 STRTOL_FATAL_ERROR (spec, _("block size"), e);