#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
#endif
#undef USE_SIGNAL_TIMEOUT
-#ifdef HAVE_SIGNAL
-# if defined(HAVE_SIGSETJMP) || defined(HAVE_SIGBLOCK)
-# define USE_SIGNAL_TIMEOUT
-# endif
+#if defined(HAVE_SIGSETJMP) || defined(HAVE_SIGBLOCK)
+# define USE_SIGNAL_TIMEOUT
#endif
#include "wget.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. */
+/* Get grouping data, the separator and grouping info, by calling
+ localeconv(). The information is cached after the first call to
+ the function.
-static char *
-add_thousand_seps (const char *repr)
-{
- static char outbuf[48];
- int i, i1, mod;
- char *outptr;
- const char *inptr;
+ 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. */
- /* Reset the pointers. */
- outptr = outbuf;
- inptr = repr;
-
- /* 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 */
}
would just use "%j" and intmax_t, but many systems don't support
it, so it's used only if nothing else works. */
#if SIZEOF_LONG >= SIZEOF_WGINT
-# define SPRINTF_WGINT(buf, n) sprintf (buf, "%ld", (long) (n))
+# define SPRINTF_WGINT(buf, n) sprintf (buf, "%ld", (long) (n))
+#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, "%I64d", (__int64) (n))
#else
-# if SIZEOF_LONG_LONG >= SIZEOF_WGINT
-# define SPRINTF_WGINT(buf, n) sprintf (buf, "%lld", (long long) (n))
-# else
-# ifdef WINDOWS
-# define SPRINTF_WGINT(buf, n) sprintf (buf, "%I64", (__int64) (n))
-# else
-# define SPRINTF_WGINT(buf, n) sprintf (buf, "%j", (intmax_t) (n))
-# endif
-# endif
+# define SPRINTF_WGINT(buf, n) sprintf (buf, "%j", (intmax_t) (n))
#endif
/* Shorthand for casting to wgint. */
#undef PR
#undef W
+#undef SPRINTF_WGINT
#undef DIGITS_1
#undef DIGITS_2
#undef DIGITS_3
return 0; /* most likely ENOTTY */
return wsz.ws_col;
-#else /* not TIOCGWINSZ */
-# ifdef WINDOWS
+#elif defined(WINDOWS)
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (!GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &csbi))
return 0;
return csbi.dwSize.X;
-# else /* neither WINDOWS nor TIOCGWINSZ */
+#else /* neither TIOCGWINSZ nor WINDOWS */
return 0;
-#endif /* neither WINDOWS nor TIOCGWINSZ */
-#endif /* not TIOCGWINSZ */
+#endif /* neither TIOCGWINSZ nor WINDOWS */
}
/* Return a random number between 0 and MAX-1, inclusive.
}
/* 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 */
/* If nanosleep has been interrupted by a signal, adjust the
sleeping period and return to sleep. */
sleep = remaining;
-#else /* not HAVE_NANOSLEEP */
-#ifdef HAVE_USLEEP
+#elif defined(HAVE_USLEEP)
/* If usleep is available, use it in preference to select. */
if (seconds >= 1)
{
seconds -= (long) seconds;
}
usleep (seconds * 1000000);
-#else /* not HAVE_USLEEP */
-#ifdef HAVE_SELECT
- /* Note that, although Windows supports select, this sleeping
- strategy doesn't work there because Winsock's select doesn't
- implement timeout when it is passed NULL pointers for all fd
- sets. (But it does work under Cygwin, which implements its own
- select.) */
+#else /* fall back select */
+ /* Note that, although Windows supports select, it can't be used to
+ implement sleeping because Winsock's select doesn't implement
+ timeout when it is passed NULL pointers for all fd sets. (But it
+ does under Cygwin, which implements Unix-compatible select.) */
struct timeval sleep;
sleep.tv_sec = (long) seconds;
sleep.tv_usec = 1000000 * (seconds - (long) seconds);
interrupted by a signal. But without knowing how long we've
actually slept, we can't return to sleep. Using gettimeofday to
track sleeps is slow and unreliable due to clock skew. */
-#else /* not HAVE_SELECT */
- sleep (seconds);
-#endif /* not HAVE_SELECT */
-#endif /* not HAVE_USLEEP */
-#endif /* not HAVE_NANOSLEEP */
+#endif
}
#endif /* not WINDOWS */