1 /* human.c -- print human readable file size
2 Copyright (C) 1996, 1997, 1998, 1999, 2000 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
47 "this configure-time declaration test was not run"
55 # define _(Text) gettext (Text)
66 static const char suffixes
[] =
79 /* Like human_readable_inexact, except always round to even. */
81 human_readable (uintmax_t n
, char *buf
,
82 int from_block_size
, int output_block_size
)
84 return human_readable_inexact (n
, buf
, from_block_size
, output_block_size
,
88 /* Convert N to a human readable format in BUF.
90 N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
93 If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in
94 the output number. OUTPUT_BLOCK_SIZE must be a multiple of
95 FROM_BLOCK_SIZE or vice versa.
97 Use INEXACT_STYLE to determine whether to take the ceiling or floor
98 of any result that cannot be expressed exactly.
100 If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
101 possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
102 ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
103 1000 or 1024; it must be at least 2. Most people visually process
104 strings of 3-4 digits effectively, but longer strings of digits are
105 more prone to misinterpretation. Hence, converting to an
106 abbreviated form usually improves readability. Use a suffix
107 indicating which power is being used. For example, assuming
108 -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
109 133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
110 than -OUTPUT_BLOCK_SIZE aren't modified. */
113 human_readable_inexact (uintmax_t n
, char *buf
,
114 int from_block_size
, int output_block_size
,
115 enum human_inexact_style inexact_style
)
124 /* 0 means adjusted N == AMT.TENTHS;
125 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
126 2 means adjusted N == AMT.TENTHS + 0.05;
127 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
130 if (output_block_size
< 0)
132 base
= -output_block_size
;
138 to_block_size
= output_block_size
;
141 p
= buf
+ LONGEST_HUMAN_READABLE
;
145 /* Suppress `used before initialized' warning. */
149 /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units. */
151 if (to_block_size
<= from_block_size
)
153 int multiplier
= from_block_size
/ to_block_size
;
154 amt
= n
* multiplier
;
156 if (amt
/ multiplier
!= n
)
158 /* Overflow occurred during multiplication. We should use
159 multiple precision arithmetic here, but we'll be lazy and
160 resort to floating point. This can yield answers that
161 are slightly off. In practice it is quite rare to
162 overflow uintmax_t, so this is good enough for now. */
164 double damt
= n
* (double) multiplier
;
167 sprintf (buf
, "%.0f", damt
);
178 while (e
* base
<= damt
&& power
< sizeof suffixes
- 1);
182 sprintf (buf
, "%.1f%c", damt
, suffixes
[power
]);
183 if (4 < strlen (buf
))
184 sprintf (buf
, "%.0f%c", damt
, suffixes
[power
]);
190 else if (from_block_size
== 0)
194 int divisor
= to_block_size
/ from_block_size
;
195 int r10
= (n
% divisor
) * 10;
196 int r2
= (r10
% divisor
) * 2;
198 tenths
= r10
/ divisor
;
199 rounding
= r2
< divisor
? 0 < r2
: 2 + (divisor
< r2
);
203 /* Use power of BASE notation if adjusted AMT is large enough. */
205 if (base
&& base
<= amt
)
211 int r10
= (amt
% base
) * 10 + tenths
;
212 int r2
= (r10
% base
) * 2 + (rounding
>> 1);
215 rounding
= (r2
< base
217 : 2 + (base
< r2
+ rounding
));
220 while (base
<= amt
&& power
< sizeof suffixes
- 1);
222 *--p
= suffixes
[power
];
226 if (2 * (1 - (int) inexact_style
)
227 < rounding
+ (tenths
& (inexact_style
== human_round_to_even
)))
243 tenths
= rounding
= 0;
248 if (inexact_style
== human_ceiling
249 ? 0 < tenths
+ rounding
250 : inexact_style
== human_round_to_even
251 ? 5 < tenths
+ (2 < rounding
+ (amt
& 1))
252 : /* inexact_style == human_floor */ 0)
256 if (amt
== base
&& power
< sizeof suffixes
- 1)
258 *p
= suffixes
[power
+ 1];
266 *--p
= '0' + (int) (amt
% 10);
267 while ((amt
/= 10) != 0);
273 /* The default block size used for output. This number may change in
274 the future as disks get larger. */
275 #ifndef DEFAULT_BLOCK_SIZE
276 # define DEFAULT_BLOCK_SIZE 1024
279 static char const *const block_size_args
[] = { "human-readable", "si", 0 };
280 static int const block_size_types
[] = { -1024, -1000 };
283 default_block_size (void)
285 return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE
;
289 humblock (char const *spec
, int *block_size
)
293 if (! spec
&& ! (spec
= getenv ("BLOCK_SIZE")))
294 *block_size
= default_block_size ();
295 else if (0 <= (i
= ARGMATCH (spec
, block_size_args
, block_size_types
)))
296 *block_size
= block_size_types
[i
];
301 strtol_error e
= xstrtoul (spec
, &ptr
, 0, &val
, "eEgGkKmMpPtTyYzZ0");
305 return LONGINT_INVALID_SUFFIX_CHAR
;
306 if ((int) val
< 0 || val
!= (int) val
)
307 return LONGINT_OVERFLOW
;
308 *block_size
= (int) val
;
315 human_block_size (char const *spec
, int report_errors
, int *block_size
)
317 strtol_error e
= humblock (spec
, block_size
);
318 if (*block_size
== 0)
320 *block_size
= default_block_size ();
323 if (e
!= LONGINT_OK
&& report_errors
)
324 STRTOL_FATAL_ERROR (spec
, _("block size"), e
);