*** empty log message ***
[coreutils.git] / lib / human.c
blob600614e011a54bca7ee6668d5d776b5500ce7ea6
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)
7 any later version.
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. */
22 #if HAVE_CONFIG_H
23 # include <config.h>
24 #endif
26 #include <sys/types.h>
27 #include <stdio.h>
29 #if HAVE_LIMITS_H
30 # include <limits.h>
31 #endif
33 #if HAVE_STRING_H
34 # include <string.h>
35 #else
36 # include <strings.h>
37 #endif
39 #ifndef CHAR_BIT
40 # define CHAR_BIT 8
41 #endif
42 #if HAVE_STDLIB_H
43 # include <stdlib.h>
44 #endif
46 #ifndef HAVE_DECL_GETENV
47 char *getenv ();
48 #endif
50 #if ENABLE_NLS
51 # include <libintl.h>
52 # define _(Text) gettext (Text)
53 #else
54 # define _(Text) Text
55 #endif
57 #include <argmatch.h>
58 #include <error.h>
59 #include <xstrtol.h>
61 #include "human.h"
63 static const char suffixes[] =
65 0, /* not used */
66 'k', /* kilo */
67 'M', /* Mega */
68 'G', /* Giga */
69 'T', /* Tera */
70 'P', /* Peta */
71 'E', /* Exa */
72 'Z', /* Zetta */
73 'Y' /* Yotta */
76 /* Like human_readable_inexact, except always round to even. */
77 char *
78 human_readable (uintmax_t n, char *buf,
79 int from_block_size, int output_block_size)
81 return human_readable_inexact (n, buf, from_block_size, output_block_size,
82 human_round_to_even);
85 /* Convert N to a human readable format in BUF.
87 N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
88 be nonnegative.
90 If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in
91 the output number. OUTPUT_BLOCK_SIZE must be a multiple of
92 FROM_BLOCK_SIZE or vice versa.
94 Use INEXACT_STYLE to determine whether to take the ceiling or floor
95 of any result that cannot be expressed exactly.
97 If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
98 possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
99 ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
100 1000 or 1024; it must be at least 2. Most people visually process
101 strings of 3-4 digits effectively, but longer strings of digits are
102 more prone to misinterpretation. Hence, converting to an
103 abbreviated form usually improves readability. Use a suffix
104 indicating which power is being used. For example, assuming
105 -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
106 133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
107 than -OUTPUT_BLOCK_SIZE aren't modified. */
109 char *
110 human_readable_inexact (uintmax_t n, char *buf,
111 int from_block_size, int output_block_size,
112 enum human_inexact_style inexact_style)
114 uintmax_t amt;
115 int base;
116 int to_block_size;
117 int tenths = 0;
118 int power;
119 char *p;
121 /* 0 means adjusted N == AMT.TENTHS;
122 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
123 2 means adjusted N == AMT.TENTHS + 0.05;
124 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
125 int rounding = 0;
127 if (output_block_size < 0)
129 base = -output_block_size;
130 to_block_size = 1;
132 else
134 base = 0;
135 to_block_size = output_block_size;
138 p = buf + LONGEST_HUMAN_READABLE;
139 *p = '\0';
141 #ifdef lint
142 /* Suppress `used before initialized' warning. */
143 power = 0;
144 #endif
146 /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units. */
148 if (to_block_size <= from_block_size)
150 int multiplier = from_block_size / to_block_size;
151 amt = n * multiplier;
153 if (amt / multiplier != n)
155 /* Overflow occurred during multiplication. We should use
156 multiple precision arithmetic here, but we'll be lazy and
157 resort to floating point. This can yield answers that
158 are slightly off. In practice it is quite rare to
159 overflow uintmax_t, so this is good enough for now. */
161 double damt = n * (double) multiplier;
163 if (! base)
164 sprintf (buf, "%.0f", damt);
165 else
167 double e = 1;
168 power = 0;
172 e *= base;
173 power++;
175 while (e * base <= damt && power < sizeof suffixes - 1);
177 damt /= e;
179 sprintf (buf, "%.1f%c", damt, suffixes[power]);
180 if (4 < strlen (buf))
181 sprintf (buf, "%.0f%c", damt, suffixes[power]);
184 return buf;
187 else if (from_block_size == 0)
188 amt = 0;
189 else
191 int divisor = to_block_size / from_block_size;
192 int r10 = (n % divisor) * 10;
193 int r2 = (r10 % divisor) * 2;
194 amt = n / divisor;
195 tenths = r10 / divisor;
196 rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
200 /* Use power of BASE notation if adjusted AMT is large enough. */
202 if (base && base <= amt)
204 power = 0;
208 int r10 = (amt % base) * 10 + tenths;
209 int r2 = (r10 % base) * 2 + (rounding >> 1);
210 amt /= base;
211 tenths = r10 / base;
212 rounding = (r2 < base
213 ? 0 < r2 + rounding
214 : 2 + (base < r2 + rounding));
215 power++;
217 while (base <= amt && power < sizeof suffixes - 1);
219 *--p = suffixes[power];
221 if (amt < 10)
223 if (2 * (1 - (int) inexact_style)
224 < rounding + (tenths & (inexact_style == human_round_to_even)))
226 tenths++;
227 rounding = 0;
229 if (tenths == 10)
231 amt++;
232 tenths = 0;
236 if (amt < 10)
238 *--p = '0' + tenths;
239 *--p = '.';
240 tenths = rounding = 0;
245 if (inexact_style == human_ceiling
246 ? 0 < tenths + rounding
247 : inexact_style == human_round_to_even
248 ? 5 < tenths + (2 < rounding + (amt & 1))
249 : /* inexact_style == human_floor */ 0)
251 amt++;
253 if (amt == base && power < sizeof suffixes - 1)
255 *p = suffixes[power + 1];
256 *--p = '0';
257 *--p = '.';
258 amt = 1;
263 *--p = '0' + (int) (amt % 10);
264 while ((amt /= 10) != 0);
266 return p;
270 /* The default block size used for output. This number may change in
271 the future as disks get larger. */
272 #ifndef DEFAULT_BLOCK_SIZE
273 # define DEFAULT_BLOCK_SIZE 1024
274 #endif
276 static char const *const block_size_args[] = { "human-readable", "si", 0 };
277 static int const block_size_types[] = { -1024, -1000 };
279 static int
280 default_block_size (void)
282 return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
285 static strtol_error
286 humblock (char const *spec, int *block_size)
288 int i;
290 if (! spec && ! (spec = getenv ("BLOCK_SIZE")))
291 *block_size = default_block_size ();
292 else if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_types)))
293 *block_size = block_size_types[i];
294 else
296 char *ptr;
297 unsigned long val;
298 strtol_error e = xstrtoul (spec, &ptr, 0, &val, "eEgGkKmMpPtTyYzZ0");
299 if (e != LONGINT_OK)
300 return e;
301 if (*ptr)
302 return LONGINT_INVALID_SUFFIX_CHAR;
303 if ((int) val < 0 || val != (int) val)
304 return LONGINT_OVERFLOW;
305 *block_size = (int) val;
308 return LONGINT_OK;
311 void
312 human_block_size (char const *spec, int report_errors, int *block_size)
314 strtol_error e = humblock (spec, block_size);
315 if (*block_size == 0)
317 *block_size = default_block_size ();
318 e = LONGINT_INVALID;
320 if (e != LONGINT_OK && report_errors)
321 STRTOL_FATAL_ERROR (spec, _("block size"), e);