(default_block_size): New function.
[gnulib.git] / lib / human.c
1 /* human.c -- print human readable file size
2    Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
3
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.
8
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.
13
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.  */
17
18 /* Originally contributed by lm@sgi.com;
19    --si, output block size selection, and large file support
20    added by eggert@twinsun.com.  */
21
22 #if HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <sys/types.h>
27 #include <stdio.h>
28
29 #if HAVE_LIMITS_H
30 # include <limits.h>
31 #endif
32
33 #if HAVE_STRING_H
34 # include <string.h>
35 #else
36 # include <strings.h>
37 #endif
38
39 #ifndef CHAR_BIT
40 # define CHAR_BIT 8
41 #endif
42 #if HAVE_STDLIB_H
43 # include <stdlib.h>
44 #endif
45
46 #ifndef HAVE_DECL_GETENV
47 char *getenv ();
48 #endif
49
50 #if ENABLE_NLS
51 # include <libintl.h>
52 # define _(Text) gettext (Text)
53 #else
54 # define _(Text) Text
55 #endif
56
57 #include <argmatch.h>
58 #include <error.h>
59 #include <xstrtol.h>
60
61 #include "human.h"
62
63 static const char suffixes[] =
64 {
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 */
74 };
75
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)
80 {
81   return human_readable_inexact (n, buf, from_block_size, output_block_size,
82                                  human_round_to_even);
83 }
84
85 /* Convert N to a human readable format in BUF.
86
87    N is expressed in units of FROM_BLOCK_SIZE.  FROM_BLOCK_SIZE must
88    be nonnegative.
89
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.
93
94    Use INEXACT_STYLE to determine whether to take the ceiling or floor
95    of any result that cannot be expressed exactly.
96
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.  */
108
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)
113 {
114   uintmax_t amt;
115   int base;
116   int to_block_size;
117   int tenths = 0;
118   int power;
119   char *p;
120
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;
126
127   if (output_block_size < 0)
128     {
129       base = -output_block_size;
130       to_block_size = 1;
131     }
132   else
133     {
134       base = 0;
135       to_block_size = output_block_size;
136     }
137
138   p = buf + LONGEST_HUMAN_READABLE;
139   *p = '\0';
140
141 #ifdef lint
142   /* Suppress `used before initialized' warning.  */
143   power = 0;
144 #endif
145
146   /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units.  */
147
148   if (to_block_size <= from_block_size)
149     {
150       int multiplier = from_block_size / to_block_size;
151       amt = n * multiplier;
152
153       if (amt / multiplier != n)
154         {
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.  */
160
161           double damt = n * (double) multiplier;
162
163           if (! base)
164             sprintf (buf, "%.0f", damt);
165           else
166             {
167               double e = 1;
168               power = 0;
169
170               do
171                 {
172                   e *= base;
173                   power++;
174                 }
175               while (e * base <= damt && power < sizeof suffixes - 1);
176
177               damt /= e;
178
179               sprintf (buf, "%.1f%c", damt, suffixes[power]);
180               if (4 < strlen (buf))
181                 sprintf (buf, "%.0f%c", damt, suffixes[power]);
182             }
183
184           return buf;
185         }
186     }
187   else if (from_block_size == 0)
188     amt = 0;
189   else
190     {
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);
197     }
198
199
200   /* Use power of BASE notation if adjusted AMT is large enough.  */
201
202   if (base && base <= amt)
203     {
204       power = 0;
205
206       do
207         {
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++;
216         }
217       while (base <= amt && power < sizeof suffixes - 1);
218
219       *--p = suffixes[power];
220
221       if (amt < 10)
222         {
223           if (2 * (1 - (int) inexact_style)
224               < rounding + (tenths & (inexact_style == human_round_to_even)))
225             {
226               tenths++;
227               rounding = 0;
228
229               if (tenths == 10)
230                 {
231                   amt++;
232                   tenths = 0;
233                 }
234             }
235
236           if (amt < 10)
237             {
238               *--p = '0' + tenths;
239               *--p = '.';
240               tenths = rounding = 0;
241             }
242         }
243     }
244
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)
250     {
251       amt++;
252
253       if (amt == base && power < sizeof suffixes - 1)
254         {
255           *p = suffixes[power + 1];
256           *--p = '0';
257           *--p = '.';
258           amt = 1;
259         }
260     }
261
262   do
263     *--p = '0' + (int) (amt % 10);
264   while ((amt /= 10) != 0);
265
266   return p;
267 }
268
269
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
275
276 static char const *const block_size_args[] = { "human-readable", "si", 0 };
277 static int const block_size_types[] = { -1024, -1000 };
278
279 static int
280 default_block_size (void)
281 {
282   return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
283 }
284
285 static strtol_error
286 humblock (char const *spec, int *block_size)
287 {
288   int i;
289
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
295     {
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;
306     }
307
308   return LONGINT_OK;
309 }
310
311 void
312 human_block_size (char const *spec, int report_errors, int *block_size)
313 {
314   strtol_error e = humblock (spec, block_size);
315   if (*block_size == 0)
316     {
317       *block_size = default_block_size ();
318       e = LONGINT_INVALID;
319     }
320   if (e != LONGINT_OK && report_errors)
321     STRTOL_FATAL_ERROR (spec, _("block size"), e);
322 }