]> sjero.net Git - wget/blobdiff - src/log.c
NEWS: cite --start-pos
[wget] / src / log.c
index d1793d430301434d56c3860c036a6f9beafcb4c7..4f93a21cb050446b7325092d5bcf66e9abdbea83 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1,11 +1,12 @@
 /* Messages logging.
 /* Messages logging.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 
 This file is part of GNU Wget.
 
 GNU Wget 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 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,48 +15,46 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
 
-In addition, as a special exception, the Free Software Foundation
-gives permission to link the code of its release of Wget with the
-OpenSSL project's "OpenSSL" library (or with modified versions of it
-that use the same license as the "OpenSSL" library), and distribute
-the linked executables.  You must obey the GNU General Public License
-in all respects for all of the code used other than "OpenSSL".  If you
-modify this file, you may extend this exception to your version of the
-file, but you are not obligated to do so.  If you do not wish to do
-so, delete this exception statement from your version.  */
+Additional permission under GNU GPL version 3 section 7
 
 
-#include <config.h>
+If you modify this program, or any covered work, by linking or
+combining it with the OpenSSL project's OpenSSL library (or a
+modified version of that library), containing parts covered by the
+terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+grants you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts of OpenSSL used as well
+as that of the covered work.  */
+
+#include "wget.h"
 
 #include <stdio.h>
 
 #include <stdio.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
+#include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
-#ifdef WGET_USE_STDARG
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <stdarg.h>
+#include <unistd.h>
 #include <assert.h>
 #include <errno.h>
 
 #include <assert.h>
 #include <errno.h>
 
-#include "wget.h"
 #include "utils.h"
 #include "log.h"
 
 #include "utils.h"
 #include "log.h"
 
-#ifndef errno
-extern int errno;
-#endif
-
-/* This file impplement support for "logging".  Logging means printing
+/* 2005-10-25 SMS.
+   VMS log files are often VFC record format, not stream, so fputs() can
+   produce multiple records, even when there's no newline terminator in
+   the buffer.  The result is unsightly output with spurious newlines.
+   Using fprintf() instead of fputs(), along with inhibiting some
+   fflush() activity below, seems to solve the problem.
+*/
+#ifdef __VMS
+# define FPUTS( s, f) fprintf( (f), "%s", (s))
+#else /* def __VMS */
+# define FPUTS( s, f) fputs( (s), (f))
+#endif /* def __VMS [else] */
+
+/* This file implements support for "logging".  Logging means printing
    output, plus several additional features:
 
    - Cataloguing output by importance.  You can specify that a log
    output, plus several additional features:
 
    - Cataloguing output by importance.  You can specify that a log
@@ -80,18 +79,22 @@ extern int errno;
    logging is inhibited, logfp is set back to NULL. */
 static FILE *logfp;
 
    logging is inhibited, logfp is set back to NULL. */
 static FILE *logfp;
 
-/* If non-zero, it means logging is inhibited, i.e. nothing is printed
-   or stored.  */
-static int inhibit_logging;
+/* A second file descriptor pointing to the temporary log file for the
+   WARC writer.  If WARC writing is disabled, this is NULL.  */
+static FILE *warclogfp;
+
+/* If true, it means logging is inhibited, i.e. nothing is printed or
+   stored.  */
+static bool inhibit_logging;
 
 /* Whether the last output lines are stored for use as context.  */
 
 /* Whether the last output lines are stored for use as context.  */
-static int save_context_p;
+static bool save_context_p;
 
 /* Whether the log is flushed after each command. */
 
 /* Whether the log is flushed after each command. */
-static int flush_log_p = 1;
+static bool flush_log_p = true;
 
 /* Whether any output has been received while flush_log_p was 0. */
 
 /* Whether any output has been received while flush_log_p was 0. */
-static int needs_flushing;
+static bool needs_flushing;
 
 /* In the event of a hang-up, and if its output was on a TTY, Wget
    redirects its output to `wget-log'.
 
 /* In the event of a hang-up, and if its output was on a TTY, Wget
    redirects its output to `wget-log'.
@@ -120,9 +123,9 @@ static int needs_flushing;
 static struct log_ln {
   char static_line[STATIC_LENGTH + 1]; /* statically allocated
                                           line. */
 static struct log_ln {
   char static_line[STATIC_LENGTH + 1]; /* statically allocated
                                           line. */
-  char *malloced_line;         /* malloc'ed line, for lines of output
+  char *malloced_line;          /* malloc'ed line, for lines of output
                                    larger than 80 characters. */
                                    larger than 80 characters. */
-  char *content;               /* this points either to malloced_line
+  char *content;                /* this points either to malloced_line
                                    or to the appropriate static_line.
                                    If this is NULL, it means the line
                                    has not yet been used. */
                                    or to the appropriate static_line.
                                    If this is NULL, it means the line
                                    has not yet been used. */
@@ -135,13 +138,13 @@ static int log_line_current = -1;
    finish with \n.  This is an important piece of information because
    the code is always careful to append data to trailing lines, rather
    than create new ones.  */
    finish with \n.  This is an important piece of information because
    the code is always careful to append data to trailing lines, rather
    than create new ones.  */
-static int trailing_line;
+static bool trailing_line;
 
 
-static void check_redirect_output PARAMS ((void));
+static void check_redirect_output (void);
 \f
 \f
-#define ROT_ADVANCE(num) do {                  \
-  if (++num >= SAVED_LOG_LINES)                        \
-    num = 0;                                   \
+#define ROT_ADVANCE(num) do {                   \
+  if (++num >= SAVED_LOG_LINES)                 \
+    num = 0;                                    \
 } while (0)
 
 /* Free the log line index with NUM.  This calls free on
 } while (0)
 
 /* Free the log line index with NUM.  This calls free on
@@ -179,21 +182,21 @@ saved_append_1 (const char *start, const char *end)
       struct log_ln *ln;
 
       if (log_line_current == -1)
       struct log_ln *ln;
 
       if (log_line_current == -1)
-       log_line_current = 0;
+        log_line_current = 0;
       else
       else
-       free_log_line (log_line_current);
+        free_log_line (log_line_current);
       ln = log_lines + log_line_current;
       if (len > STATIC_LENGTH)
       ln = log_lines + log_line_current;
       if (len > STATIC_LENGTH)
-       {
-         ln->malloced_line = strdupdelim (start, end);
-         ln->content = ln->malloced_line;
-       }
+        {
+          ln->malloced_line = strdupdelim (start, end);
+          ln->content = ln->malloced_line;
+        }
       else
       else
-       {
-         memcpy (ln->static_line, start, len);
-         ln->static_line[len] = '\0';
-         ln->content = ln->static_line;
-       }
+        {
+          memcpy (ln->static_line, start, len);
+          ln->static_line[len] = '\0';
+          ln->content = ln->static_line;
+        }
     }
   else
     {
     }
   else
     {
@@ -204,38 +207,38 @@ saved_append_1 (const char *start, const char *end)
          convert it to malloc(). */
       struct log_ln *ln = log_lines + log_line_current;
       if (ln->malloced_line)
          convert it to malloc(). */
       struct log_ln *ln = log_lines + log_line_current;
       if (ln->malloced_line)
-       {
-         /* Resize malloc'ed line and append. */
-         int old_len = strlen (ln->malloced_line);
-         ln->malloced_line = xrealloc (ln->malloced_line, old_len + len + 1);
-         memcpy (ln->malloced_line + old_len, start, len);
-         ln->malloced_line[old_len + len] = '\0';
-         /* might have changed due to realloc */
-         ln->content = ln->malloced_line;
-       }
+        {
+          /* Resize malloc'ed line and append. */
+          int old_len = strlen (ln->malloced_line);
+          ln->malloced_line = xrealloc (ln->malloced_line, old_len + len + 1);
+          memcpy (ln->malloced_line + old_len, start, len);
+          ln->malloced_line[old_len + len] = '\0';
+          /* might have changed due to realloc */
+          ln->content = ln->malloced_line;
+        }
       else
       else
-       {
-         int old_len = strlen (ln->static_line);
-         if (old_len + len > STATIC_LENGTH)
-           {
-             /* Allocate memory and concatenate the old and the new
+        {
+          int old_len = strlen (ln->static_line);
+          if (old_len + len > STATIC_LENGTH)
+            {
+              /* Allocate memory and concatenate the old and the new
                  contents. */
                  contents. */
-             ln->malloced_line = (char *)xmalloc (old_len + len + 1);
-             memcpy (ln->malloced_line, ln->static_line,
-                     old_len);
-             memcpy (ln->malloced_line + old_len, start, len);
-             ln->malloced_line[old_len + len] = '\0';
-             ln->content = ln->malloced_line;
-           }
-         else
-           {
-             /* Just append to the old, statically allocated
+              ln->malloced_line = xmalloc (old_len + len + 1);
+              memcpy (ln->malloced_line, ln->static_line,
+                      old_len);
+              memcpy (ln->malloced_line + old_len, start, len);
+              ln->malloced_line[old_len + len] = '\0';
+              ln->content = ln->malloced_line;
+            }
+          else
+            {
+              /* Just append to the old, statically allocated
                  contents.  */
                  contents.  */
-             memcpy (ln->static_line + old_len, start, len);
-             ln->static_line[old_len + len] = '\0';
-             ln->content = ln->static_line;
-           }
-       }
+              memcpy (ln->static_line + old_len, start, len);
+              ln->static_line[old_len + len] = '\0';
+              ln->content = ln->static_line;
+            }
+        }
     }
   trailing_line = !(end[-1] == '\n');
   if (!trailing_line)
     }
   trailing_line = !(end[-1] == '\n');
   if (!trailing_line)
@@ -254,9 +257,9 @@ saved_append (const char *s)
     {
       const char *end = strchr (s, '\n');
       if (!end)
     {
       const char *end = strchr (s, '\n');
       if (!end)
-       end = s + strlen (s);
+        end = s + strlen (s);
       else
       else
-       ++end;
+        ++end;
       saved_append_1 (s, end);
       s = end;
     }
       saved_append_1 (s, end);
       s = end;
     }
@@ -272,22 +275,22 @@ saved_append (const char *s)
    * LOG_NONVERBOSE - print the message if opt.verbose is zero;
 
    * LOG_VERBOSE - print the message if opt.verbose is non-zero.  */
    * LOG_NONVERBOSE - print the message if opt.verbose is zero;
 
    * LOG_VERBOSE - print the message if opt.verbose is non-zero.  */
-#define CHECK_VERBOSE(x)                       \
-  switch (x)                                   \
-    {                                          \
-    case LOG_ALWAYS:                           \
-      break;                                   \
-    case LOG_NOTQUIET:                         \
-      if (opt.quiet)                           \
-       return;                                 \
-      break;                                   \
-    case LOG_NONVERBOSE:                       \
-      if (opt.verbose || opt.quiet)            \
-       return;                                 \
-      break;                                   \
-    case LOG_VERBOSE:                          \
-      if (!opt.verbose)                                \
-       return;                                 \
+#define CHECK_VERBOSE(x)                        \
+  switch (x)                                    \
+    {                                           \
+    case LOG_ALWAYS:                            \
+      break;                                    \
+    case LOG_NOTQUIET:                          \
+      if (opt.quiet)                            \
+        return;                                 \
+      break;                                    \
+    case LOG_NONVERBOSE:                        \
+      if (opt.verbose || opt.quiet)             \
+        return;                                 \
+      break;                                    \
+    case LOG_VERBOSE:                           \
+      if (!opt.verbose)                         \
+        return;                                 \
     }
 
 /* Returns the file descriptor for logging.  This is LOGFP, except if
     }
 
 /* Returns the file descriptor for logging.  This is LOGFP, except if
@@ -305,6 +308,31 @@ get_log_fp (void)
     return logfp;
   return stderr;
 }
     return logfp;
   return stderr;
 }
+
+/* Returns the file descriptor for the secondary log file. This is
+   WARCLOGFP, except if called before log_init, in which case it
+   returns stderr.  This is useful in case someone calls a logging
+   function before log_init.
+
+   If logging is inhibited, return NULL.  */
+
+static FILE *
+get_warc_log_fp (void)
+{
+  if (inhibit_logging)
+    return NULL;
+  if (warclogfp)
+    return warclogfp;
+  return NULL;
+}
+
+/* Sets the file descriptor for the secondary log file.  */
+
+void
+log_set_warc_log_fp (FILE * fp)
+{
+  warclogfp = fp;
+}
 \f
 /* Log a literal string S.  The string is logged as-is, without a
    newline appended.  */
 \f
 /* Log a literal string S.  The string is logged as-is, without a
    newline appended.  */
@@ -313,19 +341,23 @@ void
 logputs (enum log_options o, const char *s)
 {
   FILE *fp;
 logputs (enum log_options o, const char *s)
 {
   FILE *fp;
+  FILE *warcfp;
 
   check_redirect_output ();
   if ((fp = get_log_fp ()) == NULL)
     return;
 
   check_redirect_output ();
   if ((fp = get_log_fp ()) == NULL)
     return;
+  warcfp = get_warc_log_fp ();
   CHECK_VERBOSE (o);
 
   CHECK_VERBOSE (o);
 
-  fputs (s, fp);
+  FPUTS (s, fp);
+  if (warcfp != NULL)
+    FPUTS (s, warcfp);
   if (save_context_p)
     saved_append (s);
   if (flush_log_p)
     logflush ();
   else
   if (save_context_p)
     saved_append (s);
   if (flush_log_p)
     logflush ();
   else
-    needs_flushing = 1;
+    needs_flushing = true;
 }
 
 struct logvprintf_state {
 }
 
 struct logvprintf_state {
@@ -348,17 +380,18 @@ struct logvprintf_state {
    (An alternative approach would be to use va_copy, but that's not
    portable.)  */
 
    (An alternative approach would be to use va_copy, but that's not
    portable.)  */
 
-static int
+static bool
 log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
 log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
-                     va_list args)
+                      va_list args)
 {
   char smallmsg[128];
   char *write_ptr = smallmsg;
   int available_size = sizeof (smallmsg);
   int numwritten;
   FILE *fp = get_log_fp ();
 {
   char smallmsg[128];
   char *write_ptr = smallmsg;
   int available_size = sizeof (smallmsg);
   int numwritten;
   FILE *fp = get_log_fp ();
+  FILE *warcfp = get_warc_log_fp ();
 
 
-  if (!save_context_p)
+  if (!save_context_p && warcfp == NULL)
     {
       /* In the simple case just call vfprintf(), to avoid needless
          allocation and games with vsnprintf(). */
     {
       /* In the simple case just call vfprintf(), to avoid needless
          allocation and games with vsnprintf(). */
@@ -381,35 +414,38 @@ log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
   numwritten = vsnprintf (write_ptr, available_size, fmt, args);
 
   /* vsnprintf() will not step over the limit given by available_size.
   numwritten = vsnprintf (write_ptr, available_size, fmt, args);
 
   /* vsnprintf() will not step over the limit given by available_size.
-     If it fails, it will return either -1 (POSIX?) or the number of
-     characters that *would have* been written, if there had been
-     enough room (C99).  In the former case, we double the
-     available_size and malloc to get a larger buffer, and try again.
-     In the latter case, we use the returned information to build a
-     buffer of the correct size.  */
+     If it fails, it returns either -1 (older implementations) or the
+     number of characters (not counting the terminating \0) that
+     *would have* been written if there had been enough room (C99).
+     In the former case, we double available_size and malloc to get a
+     larger buffer, and try again.  In the latter case, we use the
+     returned information to build a buffer of the correct size.  */
 
   if (numwritten == -1)
     {
       /* Writing failed, and we don't know the needed size.  Try
 
   if (numwritten == -1)
     {
       /* Writing failed, and we don't know the needed size.  Try
-        again with doubled size. */
+         again with doubled size. */
       int newsize = available_size << 1;
       state->bigmsg = xrealloc (state->bigmsg, newsize);
       state->allocated = newsize;
       int newsize = available_size << 1;
       state->bigmsg = xrealloc (state->bigmsg, newsize);
       state->allocated = newsize;
-      return 0;
+      return false;
     }
   else if (numwritten >= available_size)
     {
       /* Writing failed, but we know exactly how much space we
     }
   else if (numwritten >= available_size)
     {
       /* Writing failed, but we know exactly how much space we
-        need. */
+         need. */
       int newsize = numwritten + 1;
       state->bigmsg = xrealloc (state->bigmsg, newsize);
       state->allocated = newsize;
       int newsize = numwritten + 1;
       state->bigmsg = xrealloc (state->bigmsg, newsize);
       state->allocated = newsize;
-      return 0;
+      return false;
     }
 
   /* Writing succeeded. */
     }
 
   /* Writing succeeded. */
-  saved_append (write_ptr);
-  fputs (write_ptr, fp);
+  if (save_context_p)
+    saved_append (write_ptr);
+  FPUTS (write_ptr, fp);
+  if (warcfp != NULL)
+    FPUTS (write_ptr, warcfp);
   if (state->bigmsg)
     xfree (state->bigmsg);
 
   if (state->bigmsg)
     xfree (state->bigmsg);
 
@@ -417,9 +453,9 @@ log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
   if (flush_log_p)
     logflush ();
   else
   if (flush_log_p)
     logflush ();
   else
-    needs_flushing = 1;
+    needs_flushing = true;
 
 
-  return 1;
+  return true;
 }
 
 /* Flush LOGFP.  Useful while flushing is disabled.  */
 }
 
 /* Flush LOGFP.  Useful while flushing is disabled.  */
@@ -427,30 +463,47 @@ void
 logflush (void)
 {
   FILE *fp = get_log_fp ();
 logflush (void)
 {
   FILE *fp = get_log_fp ();
+  FILE *warcfp = get_warc_log_fp ();
   if (fp)
   if (fp)
-    fflush (fp);
-  needs_flushing = 0;
+    {
+/* 2005-10-25 SMS.
+   On VMS, flush only for a terminal.  See note at FPUTS macro, above.
+*/
+#ifdef __VMS
+      if (isatty( fileno( fp)))
+        {
+          fflush (fp);
+        }
+#else /* def __VMS */
+      fflush (fp);
+#endif /* def __VMS [else] */
+    }
+
+  if (warcfp != NULL)
+    fflush (warcfp);
+
+  needs_flushing = false;
 }
 
 /* Enable or disable log flushing. */
 void
 }
 
 /* Enable or disable log flushing. */
 void
-log_set_flush (int flush)
+log_set_flush (bool flush)
 {
   if (flush == flush_log_p)
     return;
 
 {
   if (flush == flush_log_p)
     return;
 
-  if (flush == 0)
+  if (flush == false)
     {
       /* Disable flushing by setting flush_log_p to 0. */
     {
       /* Disable flushing by setting flush_log_p to 0. */
-      flush_log_p = 0;
+      flush_log_p = false;
     }
   else
     {
       /* Reenable flushing.  If anything was printed in no-flush mode,
     }
   else
     {
       /* Reenable flushing.  If anything was printed in no-flush mode,
-        flush the log now.  */
+         flush the log now.  */
       if (needs_flushing)
       if (needs_flushing)
-       logflush ();
-      flush_log_p = 1;
+        logflush ();
+      flush_log_p = true;
     }
 }
 
     }
 }
 
@@ -458,24 +511,14 @@ log_set_flush (int flush)
    status of storing, with which this function can be called again to
    reestablish storing. */
 
    status of storing, with which this function can be called again to
    reestablish storing. */
 
-int
-log_set_save_context (int savep)
+bool
+log_set_save_context (bool savep)
 {
 {
-  int old = save_context_p;
+  bool old = save_context_p;
   save_context_p = savep;
   return old;
 }
 
   save_context_p = savep;
   return old;
 }
 
-/* Handle difference in va_start between pre-ANSI and ANSI C.  Note
-   that we always use `...' in function definitions and let ansi2knr
-   convert it for us.  */
-
-#ifdef WGET_USE_STDARG
-# define VA_START(args, arg1) va_start (args, arg1)
-#else
-# define VA_START(args, ignored) va_start (args)
-#endif
-
 /* Print a message to the screen or to the log.  The first argument
    defines the verbosity of the message, and the rest are as in
    printf(3).  */
 /* Print a message to the screen or to the log.  The first argument
    defines the verbosity of the message, and the rest are as in
    printf(3).  */
@@ -485,7 +528,7 @@ logprintf (enum log_options o, const char *fmt, ...)
 {
   va_list args;
   struct logvprintf_state lpstate;
 {
   va_list args;
   struct logvprintf_state lpstate;
-  int done;
+  bool done;
 
   check_redirect_output ();
   if (inhibit_logging)
 
   check_redirect_output ();
   if (inhibit_logging)
@@ -495,16 +538,19 @@ logprintf (enum log_options o, const char *fmt, ...)
   xzero (lpstate);
   do
     {
   xzero (lpstate);
   do
     {
-      VA_START (args, fmt);
+      va_start (args, fmt);
       done = log_vprintf_internal (&lpstate, fmt, args);
       va_end (args);
       done = log_vprintf_internal (&lpstate, fmt, args);
       va_end (args);
+
+      if (done && errno == EPIPE)
+        exit (1);
     }
   while (!done);
 }
 
 #ifdef ENABLE_DEBUG
 /* The same as logprintf(), but does anything only if opt.debug is
     }
   while (!done);
 }
 
 #ifdef ENABLE_DEBUG
 /* The same as logprintf(), but does anything only if opt.debug is
-   non-zero.  */
+   true.  */
 void
 debug_logprintf (const char *fmt, ...)
 {
 void
 debug_logprintf (const char *fmt, ...)
 {
@@ -512,19 +558,19 @@ debug_logprintf (const char *fmt, ...)
     {
       va_list args;
       struct logvprintf_state lpstate;
     {
       va_list args;
       struct logvprintf_state lpstate;
-      int done;
+      bool done;
 
       check_redirect_output ();
       if (inhibit_logging)
 
       check_redirect_output ();
       if (inhibit_logging)
-       return;
+        return;
 
       xzero (lpstate);
       do
 
       xzero (lpstate);
       do
-       {
-         VA_START (args, fmt);
-         done = log_vprintf_internal (&lpstate, fmt, args);
-         va_end (args);
-       }
+        {
+          va_start (args, fmt);
+          done = log_vprintf_internal (&lpstate, fmt, args);
+          va_end (args);
+        }
       while (!done);
     }
 }
       while (!done);
     }
 }
@@ -533,16 +579,16 @@ debug_logprintf (const char *fmt, ...)
 /* Open FILE and set up a logging stream.  If FILE cannot be opened,
    exit with status of 1.  */
 void
 /* Open FILE and set up a logging stream.  If FILE cannot be opened,
    exit with status of 1.  */
 void
-log_init (const char *file, int appendp)
+log_init (const char *file, bool appendp)
 {
   if (file)
     {
       logfp = fopen (file, appendp ? "a" : "w");
       if (!logfp)
 {
   if (file)
     {
       logfp = fopen (file, appendp ? "a" : "w");
       if (!logfp)
-       {
-         fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
-         exit (1);
-       }
+        {
+          fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
+          exit (1);
+        }
     }
   else
     {
     }
   else
     {
@@ -556,36 +602,36 @@ log_init (const char *file, int appendp)
 
       if (1
 #ifdef HAVE_ISATTY
 
       if (1
 #ifdef HAVE_ISATTY
-         && isatty (fileno (logfp))
+          && isatty (fileno (logfp))
 #endif
 #endif
-         )
-       {
-         /* If the output is a TTY, enable save context, i.e. store
-            the most recent several messages ("context") and dump
-            them to a log file in case SIGHUP or SIGUSR1 is received
-            (or Ctrl+Break is pressed under Windows).  */
-         save_context_p = 1;
-       }
+          )
+        {
+          /* If the output is a TTY, enable save context, i.e. store
+             the most recent several messages ("context") and dump
+             them to a log file in case SIGHUP or SIGUSR1 is received
+             (or Ctrl+Break is pressed under Windows).  */
+          save_context_p = true;
+        }
     }
 }
 
     }
 }
 
-/* Close LOGFP, inhibit further logging and free the memory associated
-   with it.  */
+/* Close LOGFP (only if we opened it, not if it's stderr), inhibit
+   further logging and free the memory associated with it.  */
 void
 log_close (void)
 {
   int i;
 
 void
 log_close (void)
 {
   int i;
 
-  if (logfp)
+  if (logfp && (logfp != stderr))
     fclose (logfp);
   logfp = NULL;
     fclose (logfp);
   logfp = NULL;
-  inhibit_logging = 1;
-  save_context_p = 0;
+  inhibit_logging = true;
+  save_context_p = false;
 
   for (i = 0; i < SAVED_LOG_LINES; i++)
     free_log_line (i);
   log_line_current = -1;
 
   for (i = 0; i < SAVED_LOG_LINES; i++)
     free_log_line (i);
   log_line_current = -1;
-  trailing_line = 0;
+  trailing_line = false;
 }
 
 /* Dump saved lines to logfp. */
 }
 
 /* Dump saved lines to logfp. */
@@ -594,6 +640,7 @@ log_dump_context (void)
 {
   int num = log_line_current;
   FILE *fp = get_log_fp ();
 {
   int num = log_line_current;
   FILE *fp = get_log_fp ();
+  FILE *warcfp = get_warc_log_fp ();
   if (!fp)
     return;
 
   if (!fp)
     return;
 
@@ -605,20 +652,29 @@ log_dump_context (void)
     {
       struct log_ln *ln = log_lines + num;
       if (ln->content)
     {
       struct log_ln *ln = log_lines + num;
       if (ln->content)
-       fputs (ln->content, fp);
+        {
+          FPUTS (ln->content, fp);
+          if (warcfp != NULL)
+            FPUTS (ln->content, warcfp);
+        }
       ROT_ADVANCE (num);
     }
   while (num != log_line_current);
   if (trailing_line)
     if (log_lines[log_line_current].content)
       ROT_ADVANCE (num);
     }
   while (num != log_line_current);
   if (trailing_line)
     if (log_lines[log_line_current].content)
-      fputs (log_lines[log_line_current].content, fp);
+      {
+        FPUTS (log_lines[log_line_current].content, fp);
+        if (warcfp != NULL)
+          FPUTS (log_lines[log_line_current].content, warcfp);
+      }
   fflush (fp);
   fflush (fp);
+  fflush (warcfp);
 }
 \f
 /* String escape functions. */
 
 /* Return the number of non-printable characters in SOURCE.
 }
 \f
 /* String escape functions. */
 
 /* Return the number of non-printable characters in SOURCE.
-   Non-printable characters are determined as per safe-ctype.c.  */
+   Non-printable characters are determined as per c-ctype.c.  */
 
 static int
 count_nonprint (const char *source)
 
 static int
 count_nonprint (const char *source)
@@ -626,7 +682,7 @@ count_nonprint (const char *source)
   const char *p;
   int cnt;
   for (p = source, cnt = 0; *p; p++)
   const char *p;
   int cnt;
   for (p = source, cnt = 0; *p; p++)
-    if (!ISPRINT (*p))
+    if (!c_isprint (*p))
       ++cnt;
   return cnt;
 }
       ++cnt;
   return cnt;
 }
@@ -666,26 +722,26 @@ copy_and_escape (const char *source, char *dest, char escape, int base)
     {
     case 8:
       while ((c = *from++) != '\0')
     {
     case 8:
       while ((c = *from++) != '\0')
-       if (ISPRINT (c))
-         *to++ = c;
-       else
-         {
-           *to++ = escape;
-           *to++ = '0' + (c >> 6);
-           *to++ = '0' + ((c >> 3) & 7);
-           *to++ = '0' + (c & 7);
-         }
+        if (c_isprint (c))
+          *to++ = c;
+        else
+          {
+            *to++ = escape;
+            *to++ = '0' + (c >> 6);
+            *to++ = '0' + ((c >> 3) & 7);
+            *to++ = '0' + (c & 7);
+          }
       break;
     case 16:
       while ((c = *from++) != '\0')
       break;
     case 16:
       while ((c = *from++) != '\0')
-       if (ISPRINT (c))
-         *to++ = c;
-       else
-         {
-           *to++ = escape;
-           *to++ = XNUM_TO_DIGIT (c >> 4);
-           *to++ = XNUM_TO_DIGIT (c & 0xf);
-         }
+        if (c_isprint (c))
+          *to++ = c;
+        else
+          {
+            *to++ = escape;
+            *to++ = XNUM_TO_DIGIT (c >> 4);
+            *to++ = XNUM_TO_DIGIT (c & 0xf);
+          }
       break;
     default:
       abort ();
       break;
     default:
       abort ();
@@ -698,12 +754,12 @@ struct ringel {
   char *buffer;
   int size;
 };
   char *buffer;
   int size;
 };
-static struct ringel ring[RING_SIZE];  /* ring data */
+static struct ringel ring[RING_SIZE];   /* ring data */
 
 static const char *
 escnonprint_internal (const char *str, char escape, int base)
 {
 
 static const char *
 escnonprint_internal (const char *str, char escape, int base)
 {
-  static int ringpos;                  /* current ring position */
+  static int ringpos;                   /* current ring position */
   int nprcnt;
 
   assert (base == 8 || base == 16);
   int nprcnt;
 
   assert (base == 8 || base == 16);
@@ -729,8 +785,8 @@ escnonprint_internal (const char *str, char escape, int base)
        (re)allocate it.  */
     if (r->buffer == NULL || r->size < needed_size)
       {
        (re)allocate it.  */
     if (r->buffer == NULL || r->size < needed_size)
       {
-       r->buffer = xrealloc (r->buffer, needed_size);
-       r->size = needed_size;
+        r->buffer = xrealloc (r->buffer, needed_size);
+        r->size = needed_size;
       }
 
     copy_and_escape (str, r->buffer, escape, base);
       }
 
     copy_and_escape (str, r->buffer, escape, base);
@@ -744,6 +800,18 @@ escnonprint_internal (const char *str, char escape, int base)
    characters in STR, STR is returned.  See copy_and_escape for more
    information on which characters are considered non-printable.
 
    characters in STR, STR is returned.  See copy_and_escape for more
    information on which characters are considered non-printable.
 
+   DON'T call this function on translated strings because escaping
+   will break them.  Don't call it on literal strings from the source,
+   which are by definition trusted.  If newlines are allowed in the
+   string, escape and print it line by line because escaping the whole
+   string will convert newlines to \012.  (This is so that expectedly
+   single-line messages cannot use embedded newlines to mimic Wget's
+   output and deceive the user.)
+
+   escnonprint doesn't quote its escape character because it is notf
+   meant as a general and reversible quoting mechanism, but as a quick
+   way to defang binary junk sent by malicious or buggy servers.
+
    NOTE: since this function can return a pointer to static data, be
    careful to copy its result before calling it again.  However, to be
    more useful with printf, it maintains an internal ring of static
    NOTE: since this function can return a pointer to static data, be
    careful to copy its result before calling it again.  However, to be
    more useful with printf, it maintains an internal ring of static
@@ -759,11 +827,9 @@ escnonprint (const char *str)
 
 /* Return a pointer to a static copy of STR with the non-printable
    characters escaped as %XX.  If there are no non-printable
 
 /* Return a pointer to a static copy of STR with the non-printable
    characters escaped as %XX.  If there are no non-printable
-   characters in STR, STR is returned.  See copy_and_escape for more
-   information on which characters are considered non-printable.
+   characters in STR, STR is returned.
 
 
-   This function returns a pointer to static data which will be
-   overwritten by subsequent calls -- see escnonprint for details.  */
+   See escnonprint for usage details.  */
 
 const char *
 escnonprint_uri (const char *str)
 
 const char *
 escnonprint_uri (const char *str)
@@ -774,14 +840,14 @@ escnonprint_uri (const char *str)
 void
 log_cleanup (void)
 {
 void
 log_cleanup (void)
 {
-  int i;
+  size_t i;
   for (i = 0; i < countof (ring); i++)
     xfree_null (ring[i].buffer);
 }
 \f
 /* When SIGHUP or SIGUSR1 are received, the output is redirected
    elsewhere.  Such redirection is only allowed once. */
   for (i = 0; i < countof (ring); i++)
     xfree_null (ring[i].buffer);
 }
 \f
 /* When SIGHUP or SIGUSR1 are received, the output is redirected
    elsewhere.  Such redirection is only allowed once. */
-enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
+static enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
 static const char *redirect_request_signal_name;
 
 /* Redirect output to `wget-log'.  */
 static const char *redirect_request_signal_name;
 
 /* Redirect output to `wget-log'.  */
@@ -790,11 +856,11 @@ static void
 redirect_output (void)
 {
   char *logfile;
 redirect_output (void)
 {
   char *logfile;
-  logfp = unique_create (DEFAULT_LOGFILE, 0, &logfile);
+  logfp = unique_create (DEFAULT_LOGFILE, false, &logfile);
   if (logfp)
     {
   if (logfp)
     {
-      fprintf (stderr, _("\n%s received, redirecting output to `%s'.\n"),
-              redirect_request_signal_name, logfile);
+      fprintf (stderr, _("\n%s received, redirecting output to %s.\n"),
+               redirect_request_signal_name, quote (logfile));
       xfree (logfile);
       /* Dump the context output to the newly opened log.  */
       log_dump_context ();
       xfree (logfile);
       /* Dump the context output to the newly opened log.  */
       log_dump_context ();
@@ -805,10 +871,10 @@ redirect_output (void)
          can do but disable printing completely. */
       fprintf (stderr, _("\n%s received.\n"), redirect_request_signal_name);
       fprintf (stderr, _("%s: %s; disabling logging.\n"),
          can do but disable printing completely. */
       fprintf (stderr, _("\n%s received.\n"), redirect_request_signal_name);
       fprintf (stderr, _("%s: %s; disabling logging.\n"),
-              logfile, strerror (errno));
-      inhibit_logging = 1;
+               (logfile) ? logfile : DEFAULT_LOGFILE, strerror (errno));
+      inhibit_logging = true;
     }
     }
-  save_context_p = 0;
+  save_context_p = false;
 }
 
 /* Check whether a signal handler requested the output to be
 }
 
 /* Check whether a signal handler requested the output to be