use double quotes, not single quotes around syntax-error-evoking string
[gnulib.git] / lib / human.c
1 /* human.c -- print human readable file size
2    Copyright (C) 1996, 1997, 1998, 1999, 2000 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 "this configure-time declaration test was not run"
48 #endif
49 #if !HAVE_DECL_GETENV
50 char *getenv ();
51 #endif
52
53 #if ENABLE_NLS
54 # include <libintl.h>
55 # define _(Text) gettext (Text)
56 #else
57 # define _(Text) Text
58 #endif
59
60 #include <argmatch.h>
61 #include <error.h>
62 #include <xstrtol.h>
63
64 #include "human.h"
65
66 static const char suffixes[] =
67 {
68   0,    /* not used */
69   'k',  /* kilo */
70   'M',  /* Mega */
71   'G',  /* Giga */
72   'T',  /* Tera */
73   'P',  /* Peta */
74   'E',  /* Exa */
75   'Z',  /* Zetta */
76   'Y'   /* Yotta */
77 };
78
79 /* Like human_readable_inexact, except always round to even.  */
80 char *
81 human_readable (uintmax_t n, char *buf,
82                 int from_block_size, int output_block_size)
83 {
84   return human_readable_inexact (n, buf, from_block_size, output_block_size,
85                                  human_round_to_even);
86 }
87
88 /* Convert N to a human readable format in BUF.
89
90    N is expressed in units of FROM_BLOCK_SIZE.  FROM_BLOCK_SIZE must
91    be nonnegative.
92
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.
96
97    Use INEXACT_STYLE to determine whether to take the ceiling or floor
98    of any result that cannot be expressed exactly.
99
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.  */
111
112 char *
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)
116 {
117   uintmax_t amt;
118   int base;
119   int to_block_size;
120   int tenths = 0;
121   int power;
122   char *p;
123
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.  */
128   int rounding = 0;
129
130   if (output_block_size < 0)
131     {
132       base = -output_block_size;
133       to_block_size = 1;
134     }
135   else
136     {
137       base = 0;
138       to_block_size = output_block_size;
139     }
140
141   p = buf + LONGEST_HUMAN_READABLE;
142   *p = '\0';
143
144 #ifdef lint
145   /* Suppress `used before initialized' warning.  */
146   power = 0;
147 #endif
148
149   /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units.  */
150
151   if (to_block_size <= from_block_size)
152     {
153       int multiplier = from_block_size / to_block_size;
154       amt = n * multiplier;
155
156       if (amt / multiplier != n)
157         {
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.  */
163
164           double damt = n * (double) multiplier;
165
166           if (! base)
167             sprintf (buf, "%.0f", damt);
168           else
169             {
170               double e = 1;
171               power = 0;
172
173               do
174                 {
175                   e *= base;
176                   power++;
177                 }
178               while (e * base <= damt && power < sizeof suffixes - 1);
179
180               damt /= e;
181
182               sprintf (buf, "%.1f%c", damt, suffixes[power]);
183               if (4 < strlen (buf))
184                 sprintf (buf, "%.0f%c", damt, suffixes[power]);
185             }
186
187           return buf;
188         }
189     }
190   else if (from_block_size == 0)
191     amt = 0;
192   else
193     {
194       int divisor = to_block_size / from_block_size;
195       int r10 = (n % divisor) * 10;
196       int r2 = (r10 % divisor) * 2;
197       amt = n / divisor;
198       tenths = r10 / divisor;
199       rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
200     }
201
202
203   /* Use power of BASE notation if adjusted AMT is large enough.  */
204
205   if (base && base <= amt)
206     {
207       power = 0;
208
209       do
210         {
211           int r10 = (amt % base) * 10 + tenths;
212           int r2 = (r10 % base) * 2 + (rounding >> 1);
213           amt /= base;
214           tenths = r10 / base;
215           rounding = (r2 < base
216                       ? 0 < r2 + rounding
217                       : 2 + (base < r2 + rounding));
218           power++;
219         }
220       while (base <= amt && power < sizeof suffixes - 1);
221
222       *--p = suffixes[power];
223
224       if (amt < 10)
225         {
226           if (2 * (1 - (int) inexact_style)
227               < rounding + (tenths & (inexact_style == human_round_to_even)))
228             {
229               tenths++;
230               rounding = 0;
231
232               if (tenths == 10)
233                 {
234                   amt++;
235                   tenths = 0;
236                 }
237             }
238
239           if (amt < 10)
240             {
241               *--p = '0' + tenths;
242               *--p = '.';
243               tenths = rounding = 0;
244             }
245         }
246     }
247
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)
253     {
254       amt++;
255
256       if (amt == base && power < sizeof suffixes - 1)
257         {
258           *p = suffixes[power + 1];
259           *--p = '0';
260           *--p = '.';
261           amt = 1;
262         }
263     }
264
265   do
266     *--p = '0' + (int) (amt % 10);
267   while ((amt /= 10) != 0);
268
269   return p;
270 }
271
272
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
277 #endif
278
279 static char const *const block_size_args[] = { "human-readable", "si", 0 };
280 static int const block_size_types[] = { -1024, -1000 };
281
282 static int
283 default_block_size (void)
284 {
285   return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
286 }
287
288 static strtol_error
289 humblock (char const *spec, int *block_size)
290 {
291   int i;
292
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];
297   else
298     {
299       char *ptr;
300       unsigned long val;
301       strtol_error e = xstrtoul (spec, &ptr, 0, &val, "eEgGkKmMpPtTyYzZ0");
302       if (e != LONGINT_OK)
303         return e;
304       if (*ptr)
305         return LONGINT_INVALID_SUFFIX_CHAR;
306       if ((int) val < 0 || val != (int) val)
307         return LONGINT_OVERFLOW;
308       *block_size = (int) val;
309     }
310
311   return LONGINT_OK;
312 }
313
314 void
315 human_block_size (char const *spec, int report_errors, int *block_size)
316 {
317   strtol_error e = humblock (spec, block_size);
318   if (*block_size == 0)
319     {
320       *block_size = default_block_size ();
321       e = LONGINT_INVALID;
322     }
323   if (e != LONGINT_OK && report_errors)
324     STRTOL_FATAL_ERROR (spec, _("block size"), e);
325 }