#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
{
pid_t pid;
/* Whether we arrange our own version of opt.lfilename here. */
- int logfile_changed = 0;
+ bool logfile_changed = false;
if (!opt.lfilename)
{
use fopen_excl) or lying to the user about the log file name
(which arises from using unique_name, printing the name, and
using fopen_excl later on.) */
- FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, 0, &opt.lfilename);
+ FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, false, &opt.lfilename);
if (new_log_fp)
{
- logfile_changed = 1;
+ logfile_changed = true;
fclose (new_log_fp);
}
}
else if (pid != 0)
{
/* parent, no error */
- printf (_("Continuing in background, pid %d.\n"), (int)pid);
+ printf (_("Continuing in background, pid %d.\n"), (int) pid);
if (logfile_changed)
printf (_("Output will be written to `%s'.\n"), opt.lfilename);
exit (0); /* #### should we use _exit()? */
proper way should, of course, be to have a third, error state,
other than true/false, but that would introduce uncalled-for
additional complexity to the callers. */
-int
+bool
file_exists_p (const char *filename)
{
#ifdef HAVE_ACCESS
/* Returns 0 if PATH is a directory, 1 otherwise (any kind of file).
Returns 0 on error. */
-int
+bool
file_non_directory_p (const char *path)
{
struct_stat buf;
/* Use lstat() rather than stat() so that symbolic links pointing to
directories can be identified correctly. */
if (lstat (path, &buf) != 0)
- return 0;
- return S_ISDIR (buf.st_mode) ? 0 : 1;
+ return false;
+ return S_ISDIR (buf.st_mode) ? false : true;
}
/* Return the size of file named by FILENAME, or -1 if it cannot be
(and therefore doesn't need changing). */
char *
-unique_name (const char *file, int allow_passthrough)
+unique_name (const char *file, bool allow_passthrough)
{
/* If the FILE itself doesn't exist, return it without
modification. */
opening the file returned by unique_name. */
FILE *
-unique_create (const char *name, int binary, char **opened_name)
+unique_create (const char *name, bool binary, char **opened_name)
{
/* unique file name, based on NAME */
- char *uname = unique_name (name, 0);
+ char *uname = unique_name (name, false);
FILE *fp;
while ((fp = fopen_excl (uname, binary)) == NULL && errno == EEXIST)
{
xfree (uname);
- uname = unique_name (name, 0);
+ uname = unique_name (name, false);
}
if (opened_name && fp != NULL)
{
appropriately. */
FILE *
-fopen_excl (const char *fname, int binary)
+fopen_excl (const char *fname, bool binary)
{
int fd;
#ifdef O_EXCL
return result;
}
\f
-static int in_acclist (const char *const *, const char *, int);
+static bool in_acclist (const char *const *, const char *, bool);
/* Determine whether a file is acceptable to be followed, according to
lists of patterns to accept/reject. */
-int
+bool
acceptable (const char *s)
{
int l = strlen (s);
if (opt.accepts)
{
if (opt.rejects)
- return (in_acclist ((const char *const *)opt.accepts, s, 1)
- && !in_acclist ((const char *const *)opt.rejects, s, 1));
+ return (in_acclist ((const char *const *)opt.accepts, s, true)
+ && !in_acclist ((const char *const *)opt.rejects, s, true));
else
- return in_acclist ((const char *const *)opt.accepts, s, 1);
+ return in_acclist ((const char *const *)opt.accepts, s, true);
}
else if (opt.rejects)
- return !in_acclist ((const char *const *)opt.rejects, s, 1);
- return 1;
+ return !in_acclist ((const char *const *)opt.rejects, s, true);
+ return true;
}
/* Compare S1 and S2 frontally; S2 must begin with S1. E.g. if S1 is
`/something', frontcmp() will return 1 only if S2 begins with
`/something'. Otherwise, 0 is returned. */
-int
+bool
frontcmp (const char *s1, const char *s2)
{
for (; *s1 && *s2 && (*s1 == *s2); ++s1, ++s2);
- return !*s1;
+ return *s1 == '\0';
}
/* Iterate through STRLIST, and return the first element that matches
If FLAGS is ALLABS, the leading `/' is ignored in paths; relative
and absolute paths may be freely intermixed. */
-int
+bool
accdir (const char *directory, enum accd flags)
{
/* Remove starting '/'. */
if (opt.includes)
{
if (!proclist (opt.includes, directory, flags))
- return 0;
+ return false;
}
if (opt.excludes)
{
if (proclist (opt.excludes, directory, flags))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-/* Return non-zero if STRING ends with TAIL. For instance:
+/* Return true if STRING ends with TAIL. For instance:
- match_tail ("abc", "bc", 0) -> 1
- match_tail ("abc", "ab", 0) -> 0
- match_tail ("abc", "abc", 0) -> 1
+ match_tail ("abc", "bc", false) -> 1
+ match_tail ("abc", "ab", false) -> 0
+ match_tail ("abc", "abc", false) -> 1
- If FOLD_CASE_P is non-zero, the comparison will be
- case-insensitive. */
+ If FOLD_CASE is true, the comparison will be case-insensitive. */
-int
-match_tail (const char *string, const char *tail, int fold_case_p)
+bool
+match_tail (const char *string, const char *tail, bool fold_case)
{
int i, j;
/* We want this to be fast, so we code two loops, one with
case-folding, one without. */
- if (!fold_case_p)
+ if (!fold_case)
{
for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--)
if (string[i] != tail[j])
/* If the tail was exhausted, the match was succesful. */
if (j == -1)
- return 1;
+ return true;
else
- return 0;
+ return false;
}
/* Checks whether string S matches each element of ACCEPTS. A list
element are matched either with fnmatch() or match_tail(),
according to whether the element contains wildcards or not.
- If the BACKWARD is 0, don't do backward comparison -- just compare
+ If the BACKWARD is false, don't do backward comparison -- just compare
them normally. */
-static int
-in_acclist (const char *const *accepts, const char *s, int backward)
+static bool
+in_acclist (const char *const *accepts, const char *s, bool backward)
{
for (; *accepts; accepts++)
{
/* fnmatch returns 0 if the pattern *does* match the
string. */
if (fnmatch (*accepts, s, 0) == 0)
- return 1;
+ return true;
}
else
{
if (backward)
{
if (match_tail (s, *accepts, 0))
- return 1;
+ return true;
}
else
{
if (!strcmp (s, *accepts))
- return 1;
+ return true;
}
}
}
- return 0;
+ return false;
}
/* Return the location of STR's suffix (file extension). Examples:
return NULL;
}
-/* Return non-zero if S contains globbing wildcards (`*', `?', `[' or
+/* Return true if S contains globbing wildcards (`*', `?', `[' or
`]'). */
-int
+bool
has_wildcards_p (const char *s)
{
for (; *s; s++)
if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
- return 1;
- return 0;
+ return true;
+ return false;
}
-/* Return non-zero if FNAME ends with a typical HTML suffix. The
- following (case-insensitive) suffixes are presumed to be HTML files:
+/* Return true if FNAME ends with a typical HTML suffix. The
+ following (case-insensitive) suffixes are presumed to be HTML
+ files:
html
htm
#### CAVEAT. This is not necessarily a good indication that FNAME
refers to a file that contains HTML! */
-int
+bool
has_html_suffix_p (const char *fname)
{
char *suf;
if ((suf = suffix (fname)) == NULL)
- return 0;
+ return false;
if (!strcasecmp (suf, "html"))
- return 1;
+ return true;
if (!strcasecmp (suf, "htm"))
- return 1;
+ return true;
if (suf[0] && !strcasecmp (suf + 1, "html"))
- return 1;
- return 0;
+ return true;
+ return false;
}
/* Read a line from FP and return the pointer to freshly allocated
int fd;
struct file_memory *fm;
long size;
- int inhibit_close = 0;
+ bool inhibit_close = false;
/* Some magic in the finest tradition of Perl and its kin: if FILE
is "-", just use stdin. */
if (HYPHENP (file))
{
fd = fileno (stdin);
- inhibit_close = 1;
+ inhibit_close = true;
/* Note that we don't inhibit mmap() in this case. If stdin is
redirected from a regular file, mmap() will still work. */
}
#ifdef HAVE_MMAP
{
- struct_stat buf;
+ struct_fstat buf;
if (fstat (fd, &buf) < 0)
goto mmap_lose;
fm->length = buf.st_size;
}
\f
-/* Add thousand separators to a number already in string form. Used
- by with_thousand_seps and with_thousand_seps_large. */
-
-static char *
-add_thousand_seps (const char *repr)
-{
- static char outbuf[48];
- int i, i1, mod;
- char *outptr;
- const char *inptr;
+/* Get grouping data, the separator and grouping info, by calling
+ localeconv(). The information is cached after the first call to
+ the function.
- /* Reset the pointers. */
- outptr = outbuf;
- inptr = repr;
+ In locales that don't set a thousand separator (such as the "C"
+ locale), this forces it to be ",". We are now only showing
+ thousand separators in one place, so this shouldn't be a problem in
+ practice. */
- /* 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++)
+static void
+get_grouping_data (const char **sep, const char **grouping)
+{
+ static const char *cached_sep;
+ static const char *cached_grouping;
+ static bool initialized;
+ if (!initialized)
{
- if (i % 3 == 0 && i1 != 0)
- *outptr++ = ',';
- *outptr++ = inptr[i1];
+ /* Get the grouping info from the locale. */
+ struct lconv *lconv = localeconv ();
+ cached_sep = lconv->thousands_sep;
+ cached_grouping = lconv->grouping;
+ if (!*cached_sep)
+ {
+ /* Many locales (such as "C" or "hr_HR") don't specify
+ grouping, which we still want to use it for legibility.
+ In those locales set the sep char to ',', unless that
+ character is used for decimal point, in which case set it
+ to " ". */
+ if (*lconv->decimal_point != ',')
+ cached_sep = ",";
+ else
+ cached_sep = " ";
+ cached_grouping = "\x03";
+ }
+ initialized = true;
}
- /* Zero-terminate the string. */
- *outptr = '\0';
- return outbuf;
+ *sep = cached_sep;
+ *grouping = cached_grouping;
}
-/* Return a static pointer to the number printed with thousand
- separators inserted at the right places. */
+/* 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.
-char *
-with_thousand_seps (wgint l)
+ 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)
{
- char inbuf[24];
- /* Print the number into the buffer. */
- number_to_string (inbuf, l);
- return add_thousand_seps (inbuf);
-}
+ static char outbuf[48];
+ char *p = outbuf + sizeof outbuf;
-/* Write a string representation of LARGE_INT NUMBER into the provided
- buffer.
+ /* Info received from locale */
+ const char *grouping, *sep;
+ int seplen;
- 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. */
+ /* State information */
+ int i = 0, groupsize;
+ const char *atgroup;
-static void
-large_int_to_string (char *buffer, int bufsize, LARGE_INT number)
-{
- snprintf (buffer, bufsize, LARGE_INT_FMT, number);
-}
+ bool negative = n < 0;
-/* The same as with_thousand_seps, but works on LARGE_INT. */
+ /* Initialize grouping data. */
+ get_grouping_data (&sep, &grouping);
+ seplen = strlen (sep);
+ atgroup = grouping;
+ groupsize = *atgroup++;
-char *
-with_thousand_seps_large (LARGE_INT l)
-{
- char inbuf[48];
- large_int_to_string (inbuf, sizeof (inbuf), l);
- return add_thousand_seps (inbuf);
+ /* This will overflow on WGINT_MIN, but we're not using this to
+ print negative numbers anyway. */
+ if (negative)
+ n = -n;
+
+ /* Write the number into the buffer, backwards, inserting the
+ separators as necessary. */
+ *--p = '\0';
+ while (1)
+ {
+ *--p = n % 10 + '0';
+ n /= 10;
+ if (n == 0)
+ break;
+ /* Prepend SEP to every groupsize'd digit and get new groupsize. */
+ if (++i == groupsize)
+ {
+ if (seplen == 1)
+ *--p = *sep;
+ else
+ memcpy (p -= seplen, sep, seplen);
+ i = 0;
+ if (*atgroup)
+ groupsize = *atgroup++;
+ }
+ }
+ if (negative)
+ *--p = '-';
+
+ 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.) */
- double val = (double) (long) n / 1024.0;
+ double val = n / 1024.0;
/* Print values smaller than 10 with one decimal digits, and
others without any decimals. */
snprintf (buf, sizeof (buf), "%.*f%c",
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
#undef PR
#undef W
+#undef SPRINTF_WGINT
#undef DIGITS_1
#undef DIGITS_2
#undef DIGITS_3
}
/* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
- seconds. Returns non-zero if the function was interrupted with a
- timeout, zero otherwise.
+ seconds. Returns true if the function was interrupted with a
+ timeout, false otherwise.
This works by setting up SIGALRM to be delivered in TIMEOUT seconds
using setitimer() or alarm(). The timeout is enforced by
are normally freed prior to exit from the functions, they will be
lost in case of timeout. */
-int
+bool
run_with_timeout (double timeout, void (*fun) (void *), void *arg)
{
int saved_errno;
if (timeout == 0)
{
fun (arg);
- return 0;
+ return false;
}
signal (SIGALRM, abort_run_with_timeout);
{
/* Longjumped out of FUN with a timeout. */
signal (SIGALRM, SIG_DFL);
- return 1;
+ return true;
}
alarm_set (timeout);
fun (arg);
signal (SIGALRM, SIG_DFL);
errno = saved_errno;
- return 0;
+ return false;
}
#else /* not USE_SIGNAL_TIMEOUT */
run_with_timeout (double timeout, void (*fun) (void *), void *arg)
{
fun (arg);
- return 0;
+ return false;
}
#endif /* not WINDOWS */
#endif /* not USE_SIGNAL_TIMEOUT */