#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
-#include <limits.h>
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
#ifdef HAVE_UTIME_H
# include <utime.h>
#endif
#endif
#include <fcntl.h>
#include <assert.h>
+#ifdef WGET_USE_STDARG
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
/* For TIOCGWINSZ and friends: */
#ifdef HAVE_SYS_IOCTL_H
return res;
}
\f
+#ifdef WGET_USE_STDARG
+# define VA_START(args, arg1) va_start (args, arg1)
+#else
+# define VA_START(args, ignored) va_start (args)
+#endif
+
+/* Like sprintf, but allocates a string of sufficient size with malloc
+ and returns it. GNU libc has a similar function named asprintf,
+ which requires the pointer to the string to be passed. */
+
+char *
+aprintf (const char *fmt, ...)
+{
+ /* This function is implemented using vsnprintf, which we provide
+ for the systems that don't have it. Therefore, it should be 100%
+ portable. */
+
+ int size = 32;
+ char *str = xmalloc (size);
+
+ while (1)
+ {
+ int n;
+ va_list args;
+
+ /* See log_vprintf_internal for explanation why it's OK to rely
+ on the return value of vsnprintf. */
+
+ VA_START (args, fmt);
+ n = vsnprintf (str, size, fmt, args);
+ va_end (args);
+
+ /* If the printing worked, return the string. */
+ if (n > -1 && n < size)
+ return str;
+
+ /* Else try again with a larger buffer. */
+ if (n > -1) /* C99 */
+ size = n + 1; /* precisely what is needed */
+ else
+ size <<= 1; /* twice the old size */
+ str = xrealloc (str, size);
+ }
+ return NULL; /* unreached */
+}
+\f
/* Return pointer to a static char[] buffer in which zero-terminated
string-representation of TM (in form hh:mm:ss) is printed.
- If TM is non-NULL, the current time-in-seconds will be stored
- there.
-
- (#### This is misleading: one would expect TM would be used instead
- of the current time in that case. This design was probably
- influenced by the design time(2), and should be changed at some
- points. No callers use non-NULL TM anyway.) */
+ If TM is NULL, the current time will be used. */
char *
time_str (time_t *tm)
{
static char output[15];
struct tm *ptm;
- time_t secs = time (tm);
+ time_t secs = tm ? *tm : time (NULL);
if (secs == -1)
{
{
static char output[20]; /* "YYYY-MM-DD hh:mm:ss" + \0 */
struct tm *ptm;
- time_t secs = time (tm);
+ time_t secs = tm ? *tm : time (NULL);
if (secs == -1)
{
remove_link (const char *file)
{
int err = 0;
- struct stat st;
+ struct_stat st;
if (lstat (file, &st) == 0 && S_ISLNK (st.st_mode))
{
#ifdef HAVE_ACCESS
return access (filename, F_OK) >= 0;
#else
- struct stat buf;
+ struct_stat buf;
return stat (filename, &buf) >= 0;
#endif
}
int
file_non_directory_p (const char *path)
{
- struct stat buf;
+ 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 the size of file named by FILENAME, or -1 if it cannot be
opened or seeked into. */
-long
+wgint
file_size (const char *filename)
{
- long size;
+#if defined(HAVE_FSEEKO) && defined(HAVE_FTELLO)
+ wgint size;
/* We use fseek rather than stat to determine the file size because
- that way we can also verify whether the file is readable.
- Inspired by the POST patch by Arnaud Wylie. */
+ that way we can also verify that the file is readable without
+ explicitly checking for permissions. Inspired by the POST patch
+ by Arnaud Wylie. */
FILE *fp = fopen (filename, "rb");
if (!fp)
return -1;
- fseek (fp, 0, SEEK_END);
- size = ftell (fp);
+ fseeko (fp, 0, SEEK_END);
+ size = ftello (fp);
fclose (fp);
return size;
+#else
+ struct_stat st;
+ if (stat (filename, &st) < 0)
+ return -1;
+ return st.st_size;
+#endif
}
/* stat file names named PREFIX.1, PREFIX.2, etc., until one that
{
int fd;
struct file_memory *fm;
- long size;
+ wgint size;
int inhibit_close = 0;
/* Some magic in the finest tradition of Perl and its kin: if FILE
#ifdef HAVE_MMAP
{
- struct stat buf;
+ struct_stat buf;
if (fstat (fd, &buf) < 0)
goto mmap_lose;
fm->length = buf.st_size;
fm->content = xmalloc (size);
while (1)
{
- long nread;
+ wgint nread;
if (fm->length > size / 2)
{
/* #### I'm not sure whether the whole exponential-growth
return outbuf;
}
-/* Legible -- return a static pointer to the legibly printed long. */
+/* Legible -- return a static pointer to the legibly printed wgint. */
char *
-legible (long l)
+legible (wgint l)
{
char inbuf[24];
/* Print the number into the buffer. */
return legible_1 (inbuf);
}
-/* Count the digits in a (long) integer. */
+/* Count the digits in an integer number. */
int
-numdigit (long number)
+numdigit (wgint number)
{
int cnt = 1;
if (number < 0)
return cnt;
}
-/* A half-assed implementation of INT_MAX on machines that don't
- bother to define one. */
-#ifndef INT_MAX
-# define INT_MAX ((int) ~((unsigned)1 << 8 * sizeof (int) - 1))
-#endif
-
#define ONE_DIGIT(figure) *p++ = n / (figure) + '0'
#define ONE_DIGIT_ADVANCE(figure) (ONE_DIGIT (figure), n %= (figure))
#define DIGITS_9(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_8 ((figure) / 10)
#define DIGITS_10(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_9 ((figure) / 10)
-/* DIGITS_<11-20> are only used on machines with 64-bit longs. */
+/* DIGITS_<11-20> are only used on machines with 64-bit numbers. */
#define DIGITS_11(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_10 ((figure) / 10)
#define DIGITS_12(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_11 ((figure) / 10)
#define DIGITS_18(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_17 ((figure) / 10)
#define DIGITS_19(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_18 ((figure) / 10)
-/* Print NUMBER to BUFFER in base 10. This should be completely
- equivalent to `sprintf(buffer, "%ld", number)', only much faster.
+/* It is annoying that we have three different syntaxes for 64-bit constants:
+ - nnnL for 64-bit systems, where they are of type long;
+ - nnnLL for 32-bit systems that support long long;
+ - nnnI64 for MS compiler on Windows, which doesn't support long long. */
+
+#if SIZEOF_LONG > 4
+/* If long is large enough, use long constants. */
+# define C10000000000 10000000000L
+# define C100000000000 100000000000L
+# define C1000000000000 1000000000000L
+# define C10000000000000 10000000000000L
+# define C100000000000000 100000000000000L
+# define C1000000000000000 1000000000000000L
+# define C10000000000000000 10000000000000000L
+# define C100000000000000000 100000000000000000L
+# define C1000000000000000000 1000000000000000000L
+#else
+# if SIZEOF_LONG_LONG != 0
+/* Otherwise, if long long is available, use long long constants. */
+# define C10000000000 10000000000LL
+# define C100000000000 100000000000LL
+# define C1000000000000 1000000000000LL
+# define C10000000000000 10000000000000LL
+# define C100000000000000 100000000000000LL
+# define C1000000000000000 1000000000000000LL
+# define C10000000000000000 10000000000000000LL
+# define C100000000000000000 100000000000000000LL
+# define C1000000000000000000 1000000000000000000LL
+# else
+# if defined(WINDOWS)
+/* Use __int64 constants under Windows. */
+# define C10000000000 10000000000I64
+# define C100000000000 100000000000I64
+# define C1000000000000 1000000000000I64
+# define C10000000000000 10000000000000I64
+# define C100000000000000 100000000000000I64
+# define C1000000000000000 1000000000000000I64
+# define C10000000000000000 10000000000000000I64
+# define C100000000000000000 100000000000000000I64
+# define C1000000000000000000 1000000000000000000I64
+# endif
+# endif
+#endif
+
+/* SPRINTF_WGINT is used by number_to_string to handle pathological
+ cases and to portably support strange sizes of wgint. */
+#if SIZEOF_LONG >= SIZEOF_WGINT
+# define SPRINTF_WGINT(buf, n) sprintf(buf, "%ld", (long) (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))
+# endif
+# endif
+#endif
+
+/* Print NUMBER to BUFFER in base 10. This is equivalent to
+ `sprintf(buffer, "%lld", (long long) number)', only much faster and
+ portable to machines without long long.
The speedup may make a difference in programs that frequently
convert numbers to strings. Some implementations of sprintf,
particularly the one in GNU libc, have been known to be extremely
- slow compared to this function.
+ slow when converting integers to strings.
Return the pointer to the location where the terminating zero was
printed. (Equivalent to calling buffer+strlen(buffer) after the
terminating '\0'. */
char *
-number_to_string (char *buffer, long number)
+number_to_string (char *buffer, wgint number)
{
char *p = buffer;
- long n = number;
+ wgint n = number;
-#if (SIZEOF_LONG != 4) && (SIZEOF_LONG != 8)
+#if (SIZEOF_WGINT != 4) && (SIZEOF_WGINT != 8)
/* We are running in a strange or misconfigured environment. Let
sprintf cope with it. */
- sprintf (buffer, "%ld", n);
+ SPRINTF_WGINT (buffer, n);
p += strlen (buffer);
-#else /* (SIZEOF_LONG == 4) || (SIZEOF_LONG == 8) */
+#else /* (SIZEOF_WGINT == 4) || (SIZEOF_WGINT == 8) */
if (n < 0)
{
- if (n < -INT_MAX)
+ if (n < -WGINT_MAX)
{
/* We cannot print a '-' and assign -n to n because -n would
overflow. Let sprintf deal with this border case. */
- sprintf (buffer, "%ld", n);
+ SPRINTF_WGINT (buffer, n);
p += strlen (buffer);
return p;
}
else if (n < 10000000) { DIGITS_7 (1000000); }
else if (n < 100000000) { DIGITS_8 (10000000); }
else if (n < 1000000000) { DIGITS_9 (100000000); }
-#if SIZEOF_LONG == 4
+#if SIZEOF_WGINT == 4
+ /* wgint is four bytes long: we're done. */
/* ``if (1)'' serves only to preserve editor indentation. */
else if (1) { DIGITS_10 (1000000000); }
-#else /* SIZEOF_LONG != 4 */
- else if (n < 10000000000L) { DIGITS_10 (1000000000L); }
- else if (n < 100000000000L) { DIGITS_11 (10000000000L); }
- else if (n < 1000000000000L) { DIGITS_12 (100000000000L); }
- else if (n < 10000000000000L) { DIGITS_13 (1000000000000L); }
- else if (n < 100000000000000L) { DIGITS_14 (10000000000000L); }
- else if (n < 1000000000000000L) { DIGITS_15 (100000000000000L); }
- else if (n < 10000000000000000L) { DIGITS_16 (1000000000000000L); }
- else if (n < 100000000000000000L) { DIGITS_17 (10000000000000000L); }
- else if (n < 1000000000000000000L) { DIGITS_18 (100000000000000000L); }
- else { DIGITS_19 (1000000000000000000L); }
-#endif /* SIZEOF_LONG != 4 */
+#else
+ /* wgint is 64 bits long -- make sure to process all the digits. */
+ else if (n < C10000000000) { DIGITS_10 (1000000000); }
+ else if (n < C100000000000) { DIGITS_11 (C10000000000); }
+ else if (n < C1000000000000) { DIGITS_12 (C100000000000); }
+ else if (n < C10000000000000) { DIGITS_13 (C1000000000000); }
+ else if (n < C100000000000000) { DIGITS_14 (C10000000000000); }
+ else if (n < C1000000000000000) { DIGITS_15 (C100000000000000); }
+ else if (n < C10000000000000000) { DIGITS_16 (C1000000000000000); }
+ else if (n < C100000000000000000) { DIGITS_17 (C10000000000000000); }
+ else if (n < C1000000000000000000) { DIGITS_18 (C100000000000000000); }
+ else { DIGITS_19 (C1000000000000000000); }
+#endif
*p = '\0';
-#endif /* (SIZEOF_LONG == 4) || (SIZEOF_LONG == 8) */
+#endif /* (SIZEOF_WGINT == 4) || (SIZEOF_WGINT == 8) */
return p;
}
#undef DIGITS_17
#undef DIGITS_18
#undef DIGITS_19
+
+#define RING_SIZE 3
+
+/* Print NUMBER to a statically allocated string and return a pointer
+ to the printed representation.
+
+ This function is intended to be used in conjunction with printf.
+ It is hard to portably print wgint values:
+ a) you cannot use printf("%ld", number) because wgint can be long
+ long on 32-bit machines with LFS.
+ b) you cannot use printf("%lld", number) because NUMBER could be
+ long on 32-bit machines without LFS, or on 64-bit machines,
+ which do not require LFS. Also, Windows doesn't support %lld.
+ c) you cannot use printf("%j", (int_max_t) number) because not all
+ versions of printf support "%j", the most notable being the one
+ on Windows.
+ d) you cannot #define WGINT_FMT to the appropriate format and use
+ printf(WGINT_FMT, number) because that would break translations
+ for user-visible messages, such as printf("Downloaded: %d
+ bytes\n", number).
+
+ What you should use instead is printf("%s", number_to_static_string
+ (number)).
+
+ CAVEAT: since the function returns pointers to static data, you
+ must be careful to copy its result before calling it again.
+ However, to make it more useful with printf, the function maintains
+ an internal ring of static buffers to return. That way things like
+ printf("%s %s", number_to_static_string (num1),
+ number_to_static_string (num2)) work as expected. Three buffers
+ are currently used, which means that "%s %s %s" will work, but "%s
+ %s %s %s" won't. If you need to print more than three wgints,
+ bump the RING_SIZE (or rethink your message.) */
+
+char *
+number_to_static_string (wgint number)
+{
+ static char ring[RING_SIZE][24];
+ static int ringpos;
+ char *buf = ring[ringpos];
+ number_to_string (buf, number);
+ ringpos = (ringpos + 1) % RING_SIZE;
+ return buf;
+}
\f
/* Support for timers. */
#endif
struct wget_timer {
+ /* Whether the start time has been initialized. */
+ int initialized;
+
/* The starting point in time which, subtracted from the current
time, yields elapsed time. */
wget_sys_time start;
double elapsed_pre_start;
};
-/* Allocate a timer. It is not legal to do anything with a freshly
- allocated timer, except call wtimer_reset() or wtimer_delete(). */
+/* Allocate a timer. Calling wtimer_read on the timer will return
+ zero. It is not legal to call wtimer_update with a freshly
+ allocated timer -- use wtimer_reset first. */
struct wget_timer *
wtimer_allocate (void)
{
struct wget_timer *wt = xnew (struct wget_timer);
+ xzero (*wt);
return wt;
}
}
/* Reset timer WT. This establishes the starting point from which
- wtimer_elapsed() will return the number of elapsed
- milliseconds. It is allowed to reset a previously used timer. */
+ wtimer_elapsed() will return the number of elapsed milliseconds.
+ It is allowed to reset a previously used timer.
+
+ If a non-zero value is used as START, the timer's values will be
+ offset by START. */
void
wtimer_reset (struct wget_timer *wt)
wtimer_sys_set (&wt->start);
wt->elapsed_last = 0;
wt->elapsed_pre_start = 0;
+ wt->initialized = 1;
}
static double
#endif
}
-/* Return the number of milliseconds elapsed since the timer was last
- reset. It is allowed to call this function more than once to get
- increasingly higher elapsed values. These timers handle clock
- skew. */
+/* Update the timer's elapsed interval. This function causes the
+ timer to call gettimeofday (or time(), etc.) to update its idea of
+ current time. To get the elapsed interval in milliseconds, use
+ wtimer_read.
-double
-wtimer_elapsed (struct wget_timer *wt)
+ This function handles clock skew, i.e. time that moves backwards is
+ ignored. */
+
+void
+wtimer_update (struct wget_timer *wt)
{
wget_sys_time now;
double elapsed;
+ assert (wt->initialized != 0);
+
wtimer_sys_set (&now);
elapsed = wt->elapsed_pre_start + wtimer_sys_diff (&now, &wt->start);
}
wt->elapsed_last = elapsed;
- return elapsed;
+}
+
+/* Return the elapsed time in milliseconds between the last call to
+ wtimer_reset and the last call to wtimer_update.
+
+ A typical use of the timer interface would be:
+
+ struct wtimer *timer = wtimer_new ();
+ ... do something that takes a while ...
+ wtimer_update ();
+ double msecs = wtimer_read (); */
+
+double
+wtimer_read (const struct wget_timer *wt)
+{
+ return wt->elapsed_last;
}
/* Return the assessed granularity of the timer implementation, in
{
/* If there's a way to get the terminal size using POSIX
tcgetattr(), somebody please tell me. */
-#ifndef TIOCGWINSZ
- return 0;
-#else /* TIOCGWINSZ */
+#ifdef TIOCGWINSZ
int fd;
struct winsize wsz;
return 0; /* most likely ENOTTY */
return wsz.ws_col;
-#endif /* TIOCGWINSZ */
+#else /* not TIOCGWINSZ */
+# ifdef WINDOWS
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ if (!GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &csbi))
+ return 0;
+ return csbi.dwSize.X;
+# else /* neither WINDOWS nor TIOCGWINSZ */
+ return 0;
+#endif /* neither WINDOWS nor TIOCGWINSZ */
+#endif /* not TIOCGWINSZ */
}
/* Return a random number between 0 and MAX-1, inclusive.
}
#endif /* not WINDOWS */
#endif /* not USE_SIGNAL_TIMEOUT */
+\f
+#ifndef WINDOWS
+
+/* Sleep the specified amount of seconds. On machines without
+ nanosleep(), this may sleep shorter if interrupted by signals. */
+
+void
+xsleep (double seconds)
+{
+#ifdef HAVE_NANOSLEEP
+ /* nanosleep is the preferred interface because it offers high
+ accuracy and, more importantly, because it allows us to reliably
+ restart after having been interrupted by a signal such as
+ SIGWINCH. */
+ struct timespec sleep, remaining;
+ sleep.tv_sec = (long) seconds;
+ sleep.tv_nsec = 1000000000L * (seconds - (long) seconds);
+ while (nanosleep (&sleep, &remaining) < 0 && errno == EINTR)
+ /* 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
+ /* If usleep is available, use it in preference to select. */
+ if (seconds >= 1)
+ {
+ /* On some systems, usleep cannot handle values larger than
+ 1,000,000. If the period is larger than that, use sleep
+ first, then add usleep for subsecond accuracy. */
+ sleep (seconds);
+ seconds -= (long) seconds;
+ }
+ usleep (seconds * 1000000L);
+#else /* not HAVE_USLEEP */
+#ifdef HAVE_SELECT
+ struct timeval sleep;
+ sleep.tv_sec = (long) seconds;
+ sleep.tv_usec = 1000000L * (seconds - (long) seconds);
+ select (0, NULL, NULL, NULL, &sleep);
+ /* If select returns -1 and errno is EINTR, it means we were
+ 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 /* not WINDOWS */