X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=inline;f=lib%2Fhuman.c;h=f5b9511ca19bc0d3b9521947d9548aee1508b900;hb=e8269e90e35140ebb75f39669d39bd021e364105;hp=a838e8c41effe9f5f25760348a6e603160328a3f;hpb=ba21d44f8a2da711c7abbecc64aa356b25c8ab4a;p=gnulib.git
diff --git a/lib/human.c b/lib/human.c
index a838e8c41..f5b9511ca 100644
--- a/lib/human.c
+++ b/lib/human.c
@@ -1,12 +1,12 @@
/* human.c -- print human readable file size
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free
- Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,69 +14,37 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ along with this program. If not, see . */
/* Written by Paul Eggert and Larry McVoy. */
-#if HAVE_CONFIG_H
-# include
-#endif
+#include
#include "human.h"
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-#ifndef UINTMAX_MAX
-# define UINTMAX_MAX ((uintmax_t) -1)
-#endif
-
-#if HAVE_LOCALE_H && HAVE_LOCALECONV
-# include
-#endif
-
-#if HAVE_STDLIB_H
-# include
-#endif
-#ifndef HAVE_DECL_GETENV
-"this configure-time declaration test was not run"
-#endif
-#if !HAVE_DECL_GETENV
-char *getenv ();
-#endif
-
-#if HAVE_STRING_H
-# include
-#endif
-
-#if HAVE_STRINGS_H
-# include
-#endif
-
+#include
#include
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
+#include
+#include
#include
#include
-#include
+#include
/* The maximum length of a suffix like "KiB". */
#define HUMAN_READABLE_SUFFIX_LENGTH_MAX 3
static const char power_letter[] =
{
- 0, /* not used */
- 'K', /* kibi ('k' for kilo is a special case) */
- 'M', /* mega or mebi */
- 'G', /* giga or gibi */
- 'T', /* tera or tebi */
- 'P', /* peta or pebi */
- 'E', /* exa or exbi */
- 'Z', /* zetta or 2**70 */
- 'Y' /* yotta or 2**80 */
+ 0, /* not used */
+ 'K', /* kibi ('k' for kilo is a special case) */
+ 'M', /* mega or mebi */
+ 'G', /* giga or gibi */
+ 'T', /* tera or tebi */
+ 'P', /* peta or pebi */
+ 'E', /* exa or exbi */
+ 'Z', /* zetta or 2**70 */
+ 'Y' /* yotta or 2**80 */
};
@@ -110,7 +78,7 @@ adjust_value (int inexact_style, long double value)
static char *
group_number (char *number, size_t numberlen,
- char const *grouping, char const *thousands_sep)
+ char const *grouping, char const *thousands_sep)
{
register char *d;
size_t grouplen = SIZE_MAX;
@@ -118,10 +86,8 @@ group_number (char *number, size_t numberlen,
size_t i = numberlen;
/* The maximum possible value for NUMBERLEN is the number of digits
- in the square of the largest uintmax_t, so double the size of
- uintmax_t before converting to a bound. 302 / 1000 is ceil
- (log10 (2.0)). Add 1 for integer division truncation. */
- char buf[2 * sizeof (uintmax_t) * CHAR_BIT * 302 / 1000 + 1];
+ in the square of the largest uintmax_t, so double the size needed. */
+ char buf[2 * INT_STRLEN_BOUND (uintmax_t) + 1];
memcpy (buf, number, numberlen);
d = number + numberlen;
@@ -131,19 +97,19 @@ group_number (char *number, size_t numberlen,
unsigned char g = *grouping;
if (g)
- {
- grouplen = g < CHAR_MAX ? g : i;
- grouping++;
- }
+ {
+ grouplen = g < CHAR_MAX ? g : i;
+ grouping++;
+ }
if (i < grouplen)
- grouplen = i;
+ grouplen = i;
d -= grouplen;
i -= grouplen;
memcpy (d, buf + i, grouplen);
if (i == 0)
- return d;
+ return d;
d -= thousands_seplen;
memcpy (d, thousands_sep, thousands_seplen);
@@ -174,6 +140,9 @@ group_number (char *number, size_t numberlen,
so on. Numbers smaller than the power aren't modified.
human_autoscale is normally used together with human_SI.
+ If (OPTS & human_space_before_unit), use a space to separate the
+ number from any suffix that is appended as described below.
+
If (OPTS & human_SI), append an SI prefix indicating which power is
being used. If in addition (OPTS & human_B), append "B" (if base
1000) or "iB" (if base 1024) to the SI prefix. When ((OPTS &
@@ -183,7 +152,7 @@ group_number (char *number, size_t numberlen,
char *
human_readable (uintmax_t n, char *buf, int opts,
- uintmax_t from_block_size, uintmax_t to_block_size)
+ uintmax_t from_block_size, uintmax_t to_block_size)
{
int inexact_style =
opts & (human_round_to_nearest | human_floor | human_ceiling);
@@ -206,7 +175,6 @@ human_readable (uintmax_t n, char *buf, int opts,
size_t decimal_pointlen = 1;
char const *grouping = "";
char const *thousands_sep = "";
-#if HAVE_LOCALE_H && HAVE_LOCALECONV
struct lconv const *l = localeconv ();
size_t pointlen = strlen (l->decimal_point);
if (0 < pointlen && pointlen <= MB_LEN_MAX)
@@ -217,7 +185,6 @@ human_readable (uintmax_t n, char *buf, int opts,
grouping = l->grouping;
if (strlen (l->thousands_sep) <= MB_LEN_MAX)
thousands_sep = l->thousands_sep;
-#endif
psuffix = buf + LONGEST_HUMAN_READABLE - HUMAN_READABLE_SUFFIX_LENGTH_MAX;
p = psuffix;
@@ -228,16 +195,16 @@ human_readable (uintmax_t n, char *buf, int opts,
if (to_block_size <= from_block_size)
{
if (from_block_size % to_block_size == 0)
- {
- uintmax_t multiplier = from_block_size / to_block_size;
- amt = n * multiplier;
- if (amt / multiplier == n)
- {
- tenths = 0;
- rounding = 0;
- goto use_integer_arithmetic;
- }
- }
+ {
+ uintmax_t multiplier = from_block_size / to_block_size;
+ amt = n * multiplier;
+ if (amt / multiplier == n)
+ {
+ tenths = 0;
+ rounding = 0;
+ goto use_integer_arithmetic;
+ }
+ }
}
else if (from_block_size != 0 && to_block_size % from_block_size == 0)
{
@@ -262,37 +229,37 @@ human_readable (uintmax_t n, char *buf, int opts,
if (! (opts & human_autoscale))
{
- sprintf (buf, "%.0Lf", adjust_value (inexact_style, damt));
- buflen = strlen (buf);
- nonintegerlen = 0;
+ sprintf (buf, "%.0Lf", adjust_value (inexact_style, damt));
+ buflen = strlen (buf);
+ nonintegerlen = 0;
}
else
{
- long double e = 1;
- exponent = 0;
-
- do
- {
- e *= base;
- exponent++;
- }
- while (e * base <= damt && exponent < exponent_max);
-
- damt /= e;
-
- sprintf (buf, "%.1Lf", adjust_value (inexact_style, damt));
- buflen = strlen (buf);
- nonintegerlen = decimal_pointlen + 1;
-
- if (1 + nonintegerlen + ! (opts & human_base_1024) < buflen
- || ((opts & human_suppress_point_zero)
- && buf[buflen - 1] == '0'))
- {
- sprintf (buf, "%.0Lf",
- adjust_value (inexact_style, damt * 10) / 10);
- buflen = strlen (buf);
- nonintegerlen = 0;
- }
+ long double e = 1;
+ exponent = 0;
+
+ do
+ {
+ e *= base;
+ exponent++;
+ }
+ while (e * base <= damt && exponent < exponent_max);
+
+ damt /= e;
+
+ sprintf (buf, "%.1Lf", adjust_value (inexact_style, damt));
+ buflen = strlen (buf);
+ nonintegerlen = decimal_pointlen + 1;
+
+ if (1 + nonintegerlen + ! (opts & human_base_1024) < buflen
+ || ((opts & human_suppress_point_zero)
+ && buf[buflen - 1] == '0'))
+ {
+ sprintf (buf, "%.0Lf",
+ adjust_value (inexact_style, damt * 10) / 10);
+ buflen = strlen (buf);
+ nonintegerlen = 0;
+ }
}
p = psuffix - buflen;
@@ -310,79 +277,77 @@ human_readable (uintmax_t n, char *buf, int opts,
if (opts & human_autoscale)
{
- exponent = 0;
-
- if (base <= amt)
- {
- do
- {
- unsigned r10 = (amt % base) * 10 + tenths;
- unsigned r2 = (r10 % base) * 2 + (rounding >> 1);
- amt /= base;
- tenths = r10 / base;
- rounding = (r2 < base
- ? (r2 + rounding) != 0
- : 2 + (base < r2 + rounding));
- exponent++;
- }
- while (base <= amt && exponent < exponent_max);
-
- if (amt < 10)
- {
- if (inexact_style == human_round_to_nearest
- ? 2 < rounding + (tenths & 1)
- : inexact_style == human_ceiling && 0 < rounding)
- {
- tenths++;
- rounding = 0;
-
- if (tenths == 10)
- {
- amt++;
- tenths = 0;
- }
- }
-
- if (amt < 10
- && (tenths || ! (opts & human_suppress_point_zero)))
- {
- *--p = '0' + tenths;
- p -= decimal_pointlen;
- memcpy (p, decimal_point, decimal_pointlen);
- tenths = rounding = 0;
- }
- }
- }
+ exponent = 0;
+
+ if (base <= amt)
+ {
+ do
+ {
+ unsigned int r10 = (amt % base) * 10 + tenths;
+ unsigned int r2 = (r10 % base) * 2 + (rounding >> 1);
+ amt /= base;
+ tenths = r10 / base;
+ rounding = (r2 < base
+ ? (r2 + rounding) != 0
+ : 2 + (base < r2 + rounding));
+ exponent++;
+ }
+ while (base <= amt && exponent < exponent_max);
+
+ if (amt < 10)
+ {
+ if (inexact_style == human_round_to_nearest
+ ? 2 < rounding + (tenths & 1)
+ : inexact_style == human_ceiling && 0 < rounding)
+ {
+ tenths++;
+ rounding = 0;
+
+ if (tenths == 10)
+ {
+ amt++;
+ tenths = 0;
+ }
+ }
+
+ if (amt < 10
+ && (tenths || ! (opts & human_suppress_point_zero)))
+ {
+ *--p = '0' + tenths;
+ p -= decimal_pointlen;
+ memcpy (p, decimal_point, decimal_pointlen);
+ tenths = rounding = 0;
+ }
+ }
+ }
}
- if (inexact_style == human_ceiling
- ? 0 < tenths + rounding
- : inexact_style == human_round_to_nearest
- ? 5 < tenths + (2 < rounding + (amt & 1))
- : /* inexact_style == human_floor */ 0)
+ if (inexact_style == human_round_to_nearest
+ ? 5 < tenths + (0 < rounding + (amt & 1))
+ : inexact_style == human_ceiling && 0 < tenths + rounding)
{
- amt++;
-
- if ((opts & human_autoscale)
- && amt == base && exponent < exponent_max)
- {
- exponent++;
- if (! (opts & human_suppress_point_zero))
- {
- *--p = '0';
- p -= decimal_pointlen;
- memcpy (p, decimal_point, decimal_pointlen);
- }
- amt = 1;
- }
+ amt++;
+
+ if ((opts & human_autoscale)
+ && amt == base && exponent < exponent_max)
+ {
+ exponent++;
+ if (! (opts & human_suppress_point_zero))
+ {
+ *--p = '0';
+ p -= decimal_pointlen;
+ memcpy (p, decimal_point, decimal_pointlen);
+ }
+ amt = 1;
+ }
}
integerlim = p;
do
{
- int digit = amt % 10;
- *--p = digit + '0';
+ int digit = amt % 10;
+ *--p = digit + '0';
}
while ((amt /= 10) != 0);
}
@@ -394,25 +359,28 @@ human_readable (uintmax_t n, char *buf, int opts,
if (opts & human_SI)
{
if (exponent < 0)
- {
- uintmax_t power;
- exponent = 0;
- for (power = 1; power < to_block_size; power *= base)
- if (++exponent == exponent_max)
- break;
- }
+ {
+ uintmax_t power;
+ exponent = 0;
+ for (power = 1; power < to_block_size; power *= base)
+ if (++exponent == exponent_max)
+ break;
+ }
+
+ if ((exponent | (opts & human_B)) && (opts & human_space_before_unit))
+ *psuffix++ = ' ';
if (exponent)
- *psuffix++ = (! (opts & human_base_1024) && exponent == 1
- ? 'k'
- : power_letter[exponent]);
+ *psuffix++ = (! (opts & human_base_1024) && exponent == 1
+ ? 'k'
+ : power_letter[exponent]);
if (opts & human_B)
- {
- if ((opts & human_base_1024) && exponent)
- *psuffix++ = 'i';
- *psuffix++ = 'B';
- }
+ {
+ if ((opts & human_base_1024) && exponent)
+ *psuffix++ = 'i';
+ *psuffix++ = 'B';
+ }
}
*psuffix = '\0';
@@ -446,58 +414,58 @@ humblock (char const *spec, uintmax_t *block_size, int *options)
int i;
int opts = 0;
- if (! spec && ! (spec = getenv ("BLOCK_SIZE")))
+ if (! spec
+ && ! (spec = getenv ("BLOCK_SIZE"))
+ && ! (spec = getenv ("BLOCKSIZE")))
*block_size = default_block_size ();
else
{
if (*spec == '\'')
- {
- opts |= human_group_digits;
- spec++;
- }
+ {
+ opts |= human_group_digits;
+ spec++;
+ }
if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_opts)))
- {
- opts |= block_size_opts[i];
- *block_size = 1;
- }
+ {
+ opts |= block_size_opts[i];
+ *block_size = 1;
+ }
else
- {
- char *ptr;
- strtol_error e = xstrtoumax (spec, &ptr, 0, block_size,
- "eEgGkKmMpPtTyYzZ0");
- if (e != LONGINT_OK)
- return e;
- if (*ptr)
- return LONGINT_INVALID_SUFFIX_CHAR;
- for (; ! ('0' <= *spec && *spec <= '9'); spec++)
- if (spec == ptr)
- {
- opts |= human_SI;
- if (ptr[-1] == 'B')
- opts |= human_B;
- if (ptr[-1] != 'B' || ptr[-2] == 'i')
- opts |= human_base_1024;
- break;
- }
- }
+ {
+ char *ptr;
+ strtol_error e = xstrtoumax (spec, &ptr, 0, block_size,
+ "eEgGkKmMpPtTyYzZ0");
+ if (e != LONGINT_OK)
+ {
+ *options = 0;
+ return e;
+ }
+ for (; ! ('0' <= *spec && *spec <= '9'); spec++)
+ if (spec == ptr)
+ {
+ opts |= human_SI;
+ if (ptr[-1] == 'B')
+ opts |= human_B;
+ if (ptr[-1] != 'B' || ptr[-2] == 'i')
+ opts |= human_base_1024;
+ break;
+ }
+ }
}
*options = opts;
return LONGINT_OK;
}
-int
-human_options (char const *spec, bool report_errors, uintmax_t *block_size)
+enum strtol_error
+human_options (char const *spec, int *opts, uintmax_t *block_size)
{
- int opts;
- strtol_error e = humblock (spec, block_size, &opts);
+ strtol_error e = humblock (spec, block_size, opts);
if (*block_size == 0)
{
*block_size = default_block_size ();
e = LONGINT_INVALID;
}
- if (e != LONGINT_OK && report_errors)
- STRTOL_FATAL_ERROR (spec, _("block size"), e);
- return opts;
+ return e;
}