Import from coreutils.
[gnulib.git] / lib / human.c
1 /* human.c -- print human readable file size
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
4    Free Software Foundation, Inc.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 /* Written by Paul Eggert and Larry McVoy.  */
21
22 #if HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include "human.h"
27
28 #ifndef SIZE_MAX
29 # define SIZE_MAX ((size_t) -1)
30 #endif
31 #ifndef UINTMAX_MAX
32 # define UINTMAX_MAX ((uintmax_t) -1)
33 #endif
34
35 #if HAVE_LOCALE_H && HAVE_LOCALECONV
36 # include <locale.h>
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "gettext.h"
44 #define _(msgid) gettext (msgid)
45
46 #include <argmatch.h>
47 #include <error.h>
48 #include <xstrtol.h>
49
50 /* The maximum length of a suffix like "KiB".  */
51 #define HUMAN_READABLE_SUFFIX_LENGTH_MAX 3
52
53 static const char power_letter[] =
54 {
55   0,    /* not used */
56   'K',  /* kibi ('k' for kilo is a special case) */
57   'M',  /* mega or mebi */
58   'G',  /* giga or gibi */
59   'T',  /* tera or tebi */
60   'P',  /* peta or pebi */
61   'E',  /* exa or exbi */
62   'Z',  /* zetta or 2**70 */
63   'Y'   /* yotta or 2**80 */
64 };
65
66
67 /* If INEXACT_STYLE is not human_round_to_nearest, and if easily
68    possible, adjust VALUE according to the style.  */
69
70 static long double
71 adjust_value (int inexact_style, long double value)
72 {
73   /* Do not use the floorl or ceill functions, as that would mean
74      checking for their presence and possibly linking with the
75      standard math library, which is a porting pain.  So leave the
76      value alone if it is too large to easily round.  */
77   if (inexact_style != human_round_to_nearest && value < UINTMAX_MAX)
78     {
79       uintmax_t u = value;
80       value = u + (inexact_style == human_ceiling && u != value);
81     }
82
83   return value;
84 }
85
86 /* Group the digits of NUMBER according to the grouping rules of the
87    current locale.  NUMBER contains NUMBERLEN digits.  Modify the
88    bytes pointed to by NUMBER in place, subtracting 1 from NUMBER for
89    each byte inserted.  Return the starting address of the modified
90    number.
91
92    To group the digits, use GROUPING and THOUSANDS_SEP as in `struct
93    lconv' from <locale.h>.  */
94
95 static char *
96 group_number (char *number, size_t numberlen,
97               char const *grouping, char const *thousands_sep)
98 {
99   register char *d;
100   size_t grouplen = SIZE_MAX;
101   size_t thousands_seplen = strlen (thousands_sep);
102   size_t i = numberlen;
103
104   /* The maximum possible value for NUMBERLEN is the number of digits
105      in the square of the largest uintmax_t, so double the size of
106      uintmax_t before converting to a bound.  302 / 1000 is ceil
107      (log10 (2.0)).  Add 1 for integer division truncation.  */
108   char buf[2 * sizeof (uintmax_t) * CHAR_BIT * 302 / 1000 + 1];
109
110   memcpy (buf, number, numberlen);
111   d = number + numberlen;
112
113   for (;;)
114     {
115       unsigned char g = *grouping;
116
117       if (g)
118         {
119           grouplen = g < CHAR_MAX ? g : i;
120           grouping++;
121         }
122
123       if (i < grouplen)
124         grouplen = i;
125
126       d -= grouplen;
127       i -= grouplen;
128       memcpy (d, buf + i, grouplen);
129       if (i == 0)
130         return d;
131
132       d -= thousands_seplen;
133       memcpy (d, thousands_sep, thousands_seplen);
134     }
135 }
136
137 /* Convert N to a human readable format in BUF, using the options OPTS.
138
139    N is expressed in units of FROM_BLOCK_SIZE.  FROM_BLOCK_SIZE must
140    be nonnegative.
141
142    Use units of TO_BLOCK_SIZE in the output number.  TO_BLOCK_SIZE
143    must be positive.
144
145    Use (OPTS & (human_round_to_nearest | human_floor | human_ceiling))
146    to determine whether to take the ceiling or floor of any result
147    that cannot be expressed exactly.
148
149    If (OPTS & human_group_digits), group the thousands digits
150    according to the locale, e.g., `1,000,000' in an American English
151    locale.
152
153    If (OPTS & human_autoscale), deduce the output block size
154    automatically; TO_BLOCK_SIZE must be 1 but it has no effect on the
155    output.  Use powers of 1024 if (OPTS & human_base_1024), and powers
156    of 1000 otherwise.  For example, assuming powers of 1024, 8500
157    would be converted to 8.3, 133456345 to 127, 56990456345 to 53, and
158    so on.  Numbers smaller than the power aren't modified.
159    human_autoscale is normally used together with human_SI.
160
161    If (OPTS & human_space_before_unit), use a space to separate the
162    number from any suffix that is appended as described below.
163
164    If (OPTS & human_SI), append an SI prefix indicating which power is
165    being used.  If in addition (OPTS & human_B), append "B" (if base
166    1000) or "iB" (if base 1024) to the SI prefix.  When ((OPTS &
167    human_SI) && ! (OPTS & human_autoscale)), TO_BLOCK_SIZE must be a
168    power of 1024 or of 1000, depending on (OPTS &
169    human_base_1024).  */
170
171 char *
172 human_readable (uintmax_t n, char *buf, int opts,
173                 uintmax_t from_block_size, uintmax_t to_block_size)
174 {
175   int inexact_style =
176     opts & (human_round_to_nearest | human_floor | human_ceiling);
177   unsigned int base = opts & human_base_1024 ? 1024 : 1000;
178   uintmax_t amt;
179   int tenths;
180   int exponent = -1;
181   int exponent_max = sizeof power_letter - 1;
182   char *p;
183   char *psuffix;
184   char const *integerlim;
185
186   /* 0 means adjusted N == AMT.TENTHS;
187      1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
188      2 means adjusted N == AMT.TENTHS + 0.05;
189      3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1.  */
190   int rounding;
191
192   char const *decimal_point = ".";
193   size_t decimal_pointlen = 1;
194   char const *grouping = "";
195   char const *thousands_sep = "";
196 #if HAVE_LOCALE_H && HAVE_LOCALECONV
197   struct lconv const *l = localeconv ();
198   size_t pointlen = strlen (l->decimal_point);
199   if (0 < pointlen && pointlen <= MB_LEN_MAX)
200     {
201       decimal_point = l->decimal_point;
202       decimal_pointlen = pointlen;
203     }
204   grouping = l->grouping;
205   if (strlen (l->thousands_sep) <= MB_LEN_MAX)
206     thousands_sep = l->thousands_sep;
207 #endif
208
209   psuffix = buf + LONGEST_HUMAN_READABLE - HUMAN_READABLE_SUFFIX_LENGTH_MAX;
210   p = psuffix;
211
212   /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE
213      units.  If this can be done exactly with integer arithmetic, do
214      not use floating point operations.  */
215   if (to_block_size <= from_block_size)
216     {
217       if (from_block_size % to_block_size == 0)
218         {
219           uintmax_t multiplier = from_block_size / to_block_size;
220           amt = n * multiplier;
221           if (amt / multiplier == n)
222             {
223               tenths = 0;
224               rounding = 0;
225               goto use_integer_arithmetic;
226             }
227         }
228     }
229   else if (from_block_size != 0 && to_block_size % from_block_size == 0)
230     {
231       uintmax_t divisor = to_block_size / from_block_size;
232       uintmax_t r10 = (n % divisor) * 10;
233       uintmax_t r2 = (r10 % divisor) * 2;
234       amt = n / divisor;
235       tenths = r10 / divisor;
236       rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
237       goto use_integer_arithmetic;
238     }
239
240   {
241     /* Either the result cannot be computed easily using uintmax_t,
242        or from_block_size is zero.  Fall back on floating point.
243        FIXME: This can yield answers that are slightly off.  */
244
245     long double dto_block_size = to_block_size;
246     long double damt = n * (from_block_size / dto_block_size);
247     size_t buflen;
248     size_t nonintegerlen;
249
250     if (! (opts & human_autoscale))
251       {
252         sprintf (buf, "%.0Lf", adjust_value (inexact_style, damt));
253         buflen = strlen (buf);
254         nonintegerlen = 0;
255       }
256     else
257       {
258         long double e = 1;
259         exponent = 0;
260
261         do
262           {
263             e *= base;
264             exponent++;
265           }
266         while (e * base <= damt && exponent < exponent_max);
267
268         damt /= e;
269
270         sprintf (buf, "%.1Lf", adjust_value (inexact_style, damt));
271         buflen = strlen (buf);
272         nonintegerlen = decimal_pointlen + 1;
273
274         if (1 + nonintegerlen + ! (opts & human_base_1024) < buflen
275             || ((opts & human_suppress_point_zero)
276                 && buf[buflen - 1] == '0'))
277           {
278             sprintf (buf, "%.0Lf",
279                      adjust_value (inexact_style, damt * 10) / 10);
280             buflen = strlen (buf);
281             nonintegerlen = 0;
282           }
283       }
284
285     p = psuffix - buflen;
286     memmove (p, buf, buflen);
287     integerlim = p + buflen - nonintegerlen;
288   }
289   goto do_grouping;
290
291  use_integer_arithmetic:
292   {
293     /* The computation can be done exactly, with integer arithmetic.
294
295        Use power of BASE notation if requested and if adjusted AMT is
296        large enough.  */
297
298     if (opts & human_autoscale)
299       {
300         exponent = 0;
301
302         if (base <= amt)
303           {
304             do
305               {
306                 unsigned int r10 = (amt % base) * 10 + tenths;
307                 unsigned int r2 = (r10 % base) * 2 + (rounding >> 1);
308                 amt /= base;
309                 tenths = r10 / base;
310                 rounding = (r2 < base
311                             ? (r2 + rounding) != 0
312                             : 2 + (base < r2 + rounding));
313                 exponent++;
314               }
315             while (base <= amt && exponent < exponent_max);
316
317             if (amt < 10)
318               {
319                 if (inexact_style == human_round_to_nearest
320                     ? 2 < rounding + (tenths & 1)
321                     : inexact_style == human_ceiling && 0 < rounding)
322                   {
323                     tenths++;
324                     rounding = 0;
325
326                     if (tenths == 10)
327                       {
328                         amt++;
329                         tenths = 0;
330                       }
331                   }
332
333                 if (amt < 10
334                     && (tenths || ! (opts & human_suppress_point_zero)))
335                   {
336                     *--p = '0' + tenths;
337                     p -= decimal_pointlen;
338                     memcpy (p, decimal_point, decimal_pointlen);
339                     tenths = rounding = 0;
340                   }
341               }
342           }
343       }
344
345     if (inexact_style == human_round_to_nearest
346         ? 5 < tenths + (0 < rounding + (amt & 1))
347         : inexact_style == human_ceiling && 0 < tenths + rounding)
348       {
349         amt++;
350
351         if ((opts & human_autoscale)
352             && amt == base && exponent < exponent_max)
353           {
354             exponent++;
355             if (! (opts & human_suppress_point_zero))
356               {
357                 *--p = '0';
358                 p -= decimal_pointlen;
359                 memcpy (p, decimal_point, decimal_pointlen);
360               }
361             amt = 1;
362           }
363       }
364
365     integerlim = p;
366
367     do
368       {
369         int digit = amt % 10;
370         *--p = digit + '0';
371       }
372     while ((amt /= 10) != 0);
373   }
374
375  do_grouping:
376   if (opts & human_group_digits)
377     p = group_number (p, integerlim - p, grouping, thousands_sep);
378
379   if (opts & human_SI)
380     {
381       if (exponent < 0)
382         {
383           uintmax_t power;
384           exponent = 0;
385           for (power = 1; power < to_block_size; power *= base)
386             if (++exponent == exponent_max)
387               break;
388         }
389
390       if ((exponent | (opts & human_B)) && (opts & human_space_before_unit))
391         *psuffix++ = ' ';
392
393       if (exponent)
394         *psuffix++ = (! (opts & human_base_1024) && exponent == 1
395                       ? 'k'
396                       : power_letter[exponent]);
397
398       if (opts & human_B)
399         {
400           if ((opts & human_base_1024) && exponent)
401             *psuffix++ = 'i';
402           *psuffix++ = 'B';
403         }
404     }
405
406   *psuffix = '\0';
407
408   return p;
409 }
410
411
412 /* The default block size used for output.  This number may change in
413    the future as disks get larger.  */
414 #ifndef DEFAULT_BLOCK_SIZE
415 # define DEFAULT_BLOCK_SIZE 1024
416 #endif
417
418 static char const *const block_size_args[] = { "human-readable", "si", 0 };
419 static int const block_size_opts[] =
420   {
421     human_autoscale + human_SI + human_base_1024,
422     human_autoscale + human_SI
423   };
424
425 static uintmax_t
426 default_block_size (void)
427 {
428   return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
429 }
430
431 static strtol_error
432 humblock (char const *spec, uintmax_t *block_size, int *options)
433 {
434   int i;
435   int opts = 0;
436
437   if (! spec
438       && ! (spec = getenv ("BLOCK_SIZE"))
439       && ! (spec = getenv ("BLOCKSIZE")))
440     *block_size = default_block_size ();
441   else
442     {
443       if (*spec == '\'')
444         {
445           opts |= human_group_digits;
446           spec++;
447         }
448
449       if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_opts)))
450         {
451           opts |= block_size_opts[i];
452           *block_size = 1;
453         }
454       else
455         {
456           char *ptr;
457           strtol_error e = xstrtoumax (spec, &ptr, 0, block_size,
458                                        "eEgGkKmMpPtTyYzZ0");
459           if (e != LONGINT_OK)
460             return e;
461           for (; ! ('0' <= *spec && *spec <= '9'); spec++)
462             if (spec == ptr)
463               {
464                 opts |= human_SI;
465                 if (ptr[-1] == 'B')
466                   opts |= human_B;
467                 if (ptr[-1] != 'B' || ptr[-2] == 'i')
468                   opts |= human_base_1024;
469                 break;
470               }
471         }
472     }
473
474   *options = opts;
475   return LONGINT_OK;
476 }
477
478 int
479 human_options (char const *spec, bool report_errors, uintmax_t *block_size)
480 {
481   int opts;
482   strtol_error e = humblock (spec, block_size, &opts);
483   if (*block_size == 0)
484     {
485       *block_size = default_block_size ();
486       e = LONGINT_INVALID;
487     }
488   if (e != LONGINT_OK && report_errors)
489     STRTOL_FATAL_ERROR (spec, _("block size"), e);
490   return opts;
491 }