#include <fcntl.h>
#include <assert.h>
#include <stdarg.h>
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
/* For TIOCGWINSZ and friends: */
#ifdef HAVE_SYS_IOCTL_H
}
\f
-/* Add thousand separators to a number already in string form. Used
- by with_thousand_seps and with_thousand_seps_large. */
+/* Return a printed representation of N with thousand separators.
+ This should respect locale settings, with the exception of the "C"
+ locale which mandates no separator, but we use one anyway.
-static char *
-add_thousand_seps (const char *repr)
+ Unfortunately, we cannot use %'d (in fact it would be %'j) to get
+ the separators because it's too non-portable, and it's hard to test
+ for this feature at configure time. Besides, it wouldn't work in
+ the "C" locale, which many Unix users still work in. */
+
+const char *
+with_thousand_seps (wgint n)
{
static char outbuf[48];
- int i, i1, mod;
- char *outptr;
- const char *inptr;
- /* Reset the pointers. */
- outptr = outbuf;
- inptr = repr;
+ static char loc_sepchar;
+ static const char *loc_grouping;
- /* Ignore the sign for the purpose of adding thousand
- separators. */
- if (*inptr == '-')
- {
- *outptr++ = '-';
- ++inptr;
- }
- /* How many digits before the first separator? */
- mod = strlen (inptr) % 3;
- /* Insert them. */
- for (i = 0; i < mod; i++)
- *outptr++ = inptr[i];
- /* Now insert the rest of them, putting separator before every
- third digit. */
- for (i1 = i, i = 0; inptr[i1]; i++, i1++)
+ int i = 0, groupsize;
+ char *p;
+ const char *atgroup;
+
+ if (!loc_sepchar)
{
- if (i % 3 == 0 && i1 != 0)
- *outptr++ = ',';
- *outptr++ = inptr[i1];
+#ifdef LC_NUMERIC
+ /* Get the grouping character from the locale. */
+ struct lconv *lconv;
+ const char *oldlocale = setlocale (LC_NUMERIC, "");
+ lconv = localeconv ();
+ loc_sepchar = *lconv->thousands_sep;
+ loc_grouping = xstrdup (lconv->grouping);
+ /* Restore the C locale semantics of printing and reading numbers */
+ setlocale (LC_NUMERIC, oldlocale);
+ if (!loc_sepchar)
+#endif
+ /* defaults for C locale or no locale */
+ loc_sepchar = ',', loc_grouping = "\x03";
}
- /* Zero-terminate the string. */
- *outptr = '\0';
- return outbuf;
-}
-
-/* Return a static pointer to the number printed with thousand
- separators inserted at the right places. */
-
-char *
-with_thousand_seps (wgint l)
-{
- char inbuf[24];
- /* Print the number into the buffer. */
- number_to_string (inbuf, l);
- return add_thousand_seps (inbuf);
-}
-
-/* Write a string representation of LARGE_INT NUMBER into the provided
- buffer.
+ atgroup = loc_grouping;
- It would be dangerous to use sprintf, because the code wouldn't
- work on a machine with gcc-provided long long support, but without
- libc support for "%lld". However, such old systems platforms
- typically lack snprintf and will end up using our version, which
- does support "%lld" whereever long longs are available. */
+ p = outbuf + sizeof outbuf;
+ *--p = '\0';
+ groupsize = *atgroup++;
-static void
-large_int_to_string (char *buffer, int bufsize, LARGE_INT number)
-{
- snprintf (buffer, bufsize, LARGE_INT_FMT, number);
-}
-
-/* The same as with_thousand_seps, but works on LARGE_INT. */
-
-char *
-with_thousand_seps_large (LARGE_INT l)
-{
- char inbuf[48];
- large_int_to_string (inbuf, sizeof (inbuf), l);
- return add_thousand_seps (inbuf);
+ while (1)
+ {
+ *--p = n % 10 + '0';
+ n /= 10;
+ if (n == 0)
+ break;
+ /* Insert the separator on every groupsize'd digit, and get the
+ new groupsize. */
+ if (++i == groupsize)
+ {
+ *--p = loc_sepchar;
+ i = 0;
+ if (*atgroup)
+ groupsize = *atgroup++;
+ }
+ }
+ return p;
}
/* N, a byte quantity, is converted to a human-readable abberviated
usually improves readability."
This intentionally uses kilobyte (KB), megabyte (MB), etc. in their
- original computer science meaning of "powers of 1024". Powers of
+ original computer-related meaning of "powers of 1024". Powers of
1000 would be useless since Wget already displays sizes with
thousand separators. We don't use the "*bibyte" names invented in
1998, and seldom used in practice. Wikipedia's entry on kilobyte
discusses this in some detail. */
char *
-human_readable (wgint n)
+human_readable (HR_NUMTYPE n)
{
/* These suffixes are compatible with those of GNU `ls -lh'. */
static char powers[] =
/* At each iteration N is greater than the *subsequent* power.
That way N/1024.0 produces a decimal number in the units of
*this* power. */
- if ((n >> 10) < 1024 || i == countof (powers) - 1)
+ if ((n / 1024) < 1024 || i == countof (powers) - 1)
{
/* Must cast to long first because MS VC can't directly cast
__int64 to double. (This is safe because N is known to
- be <2**20.) */
+ be < 1024^2, so always fits into long.) */
double val = (double) (long) n / 1024.0;
/* Print values smaller than 10 with one decimal digits, and
others without any decimals. */
val < 10 ? 1 : 0, val, powers[i]);
return buf;
}
- n >>= 10;
+ n /= 1024;
}
return NULL; /* unreached */
}
#elif SIZEOF_LONG_LONG >= SIZEOF_WGINT
# define SPRINTF_WGINT(buf, n) sprintf (buf, "%lld", (long long) (n))
#elif defined(WINDOWS)
-# define SPRINTF_WGINT(buf, n) sprintf (buf, "%I64", (__int64) (n))
+# define SPRINTF_WGINT(buf, n) sprintf (buf, "%I64d", (__int64) (n))
#else
# define SPRINTF_WGINT(buf, n) sprintf (buf, "%j", (intmax_t) (n))
#endif