2 Copyright (C) 1998, 2000 Free Software Foundation, Inc.
4 This file is part of Wget.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
30 # define WGET_USE_STDARG
48 /* The file descriptor used for logging. */
52 /* Whether logging is saved at all. */
55 /* In the event of a hang-up, and if its output was on a TTY, Wget
56 redirects its output to `wget-log'.
58 For the convenience of reading this newly-created log, we store the
59 last several lines ("screenful", hence the choice of 24) of Wget
60 output, and dump them as context when the time comes. */
61 #define SAVED_LOG_LINES 24
63 /* log_lines is a circular buffer that stores SAVED_LOG_LINES lines of
64 output. log_line_current always points to the position in the
65 buffer that will be written to next. When log_line_current reaches
66 SAVED_LOG_LINES, it is reset to zero.
68 The problem here is that we'd have to either (re)allocate and free
69 strings all the time, or limit the lines to an arbitrary number of
70 characters. Instead of settling for either of these, we do both:
71 if the line is smaller than a certain "usual" line length (80 chars
72 by default), a preallocated memory is used. The rare lines that
73 are longer than 80 characters are malloc'ed and freed separately.
74 This gives good performance with minimum memory consumption and
77 #define STATIC_LENGTH 80
79 static struct log_ln {
80 char static_line[STATIC_LENGTH + 1]; /* statically allocated
82 char *malloced_line; /* malloc'ed line, for lines of output
83 larger than 80 characters. */
84 char *content; /* this points either to malloced_line
85 or to the appropriate static_line.
86 If this is NULL, it means the line
87 has not yet been used. */
88 } log_lines[SAVED_LOG_LINES];
90 /* The current position in the ring. */
91 static int log_line_current = -1;
93 /* Whether the most recently written line was "trailing", i.e. did not
94 finish with \n. This is an important piece of information because
95 the code is always careful to append data to trailing lines, rather
96 than create new ones. */
97 static int trailing_line;
100 #define ROT_ADVANCE(num) do { \
101 if (++num >= SAVED_LOG_LINES) \
105 /* Free the log line index with NUM. This calls free on
106 ln->malloced_line if it's non-NULL, and it also resets
107 ln->malloced_line and ln->content to NULL. */
110 free_log_line (int num)
112 struct log_ln *ln = log_lines + num;
113 if (ln->malloced_line)
115 xfree (ln->malloced_line);
116 ln->malloced_line = NULL;
121 /* Append bytes in the range [start, end) to one line in the log. The
122 region is not supposed to contain newlines, except for the last
123 character (at end[-1]). */
126 saved_append_1 (const char *start, const char *end)
128 int len = end - start;
132 /* First, check whether we need to append to an existing line or to
136 /* Create a new line. */
139 if (log_line_current == -1)
140 log_line_current = 0;
142 free_log_line (log_line_current);
143 ln = log_lines + log_line_current;
144 if (len > STATIC_LENGTH)
146 ln->malloced_line = strdupdelim (start, end);
147 ln->content = ln->malloced_line;
151 memcpy (ln->static_line, start, len);
152 ln->static_line[len] = '\0';
153 ln->content = ln->static_line;
158 /* Append to the last line. If the line is malloc'ed, we just
159 call realloc and append the new string. If the line is
160 static, we have to check whether appending the new string
161 would make it exceed STATIC_LENGTH characters, and if so,
162 convert it to malloc(). */
163 struct log_ln *ln = log_lines + log_line_current;
164 if (ln->malloced_line)
166 /* Resize malloc'ed line and append. */
167 int old_len = strlen (ln->malloced_line);
168 ln->malloced_line = xrealloc (ln->malloced_line, old_len + len + 1);
169 memcpy (ln->malloced_line + old_len, start, len);
170 ln->malloced_line[old_len + len] = '\0';
171 /* might have changed due to realloc */
172 ln->content = ln->malloced_line;
176 int old_len = strlen (ln->static_line);
177 if (old_len + len > STATIC_LENGTH)
179 /* Allocate memory and concatenate the old and the new
181 ln->malloced_line = xmalloc (old_len + len + 1);
182 memcpy (ln->malloced_line, ln->static_line,
184 memcpy (ln->malloced_line + old_len, start, len);
185 ln->malloced_line[old_len + len] = '\0';
186 ln->content = ln->malloced_line;
190 /* Just append to the old, statically allocated
192 memcpy (ln->static_line + old_len, start, len);
193 ln->static_line[old_len + len] = '\0';
194 ln->content = ln->static_line;
198 trailing_line = !(end[-1] == '\n');
200 ROT_ADVANCE (log_line_current);
203 /* Log the contents of S, as explained above. If S consists of
204 multiple lines, they are logged separately. If S does not end with
205 a newline, it will form a "trailing" line, to which things will get
206 appended the next time this function is called. */
209 saved_append (const char *s)
213 const char *end = strchr (s, '\n');
215 end = s + strlen (s);
218 saved_append_1 (s, end);
223 /* Check X against opt.verbose and opt.quiet. The semantics is as
226 * LOG_ALWAYS - print the message unconditionally;
228 * LOG_NOTQUIET - print the message if opt.quiet is non-zero;
230 * LOG_NONVERBOSE - print the message if opt.verbose is zero;
232 * LOG_VERBOSE - print the message if opt.verbose is non-zero. */
233 #define CHECK_VERBOSE(x) \
242 case LOG_NONVERBOSE: \
243 if (opt.verbose || opt.quiet) \
251 #define CANONICALIZE_LOGFP_OR_RETURN do { \
252 if (logfp == stdin) \
255 /* This might happen if somebody calls a */ \
256 /* log* function before log_init(). */ \
261 /* Log a literal string S. The string is logged as-is, without a
265 logputs (enum log_options o, const char *s)
268 CANONICALIZE_LOGFP_OR_RETURN;
277 /* Print a message to the log. A copy of message will be saved to
278 saved_log, for later reusal by log_dump(). */
281 logvprintf (enum log_options o, const char *fmt, va_list args)
284 CANONICALIZE_LOGFP_OR_RETURN;
286 /* Originally, we first used vfprintf(), and then checked whether
287 the message needs to be stored with vsprintf(). However, Watcom
288 C didn't like ARGS being used twice, so now we first vsprintf()
289 the message, and then fwrite() it to LOGFP. */
293 /* In the simple case just call vfprintf(), to avoid needless
294 allocation and games with vsnprintf(). */
295 vfprintf (logfp, fmt, args);
301 int available_size = sizeof (smallmsg);
302 char *write_ptr = smallmsg;
306 /* The GNU coding standards advise not to rely on the return
307 value of sprintf(). However, vsnprintf() is a relatively
308 new function missing from legacy systems. Therefore it's
309 safe to assume that its return value is meaningful. On
310 the systems where vsnprintf() is not available, we use
311 the implementation from snprintf.c which does return the
313 int numwritten = vsnprintf (write_ptr, available_size, fmt, args);
315 /* vsnprintf() will not step over the limit given by
316 available_size. If it fails, it will return either -1
317 (POSIX?) or the number of characters that *would have*
318 been written, if there had been enough room. In the
319 former case, we double the available_size and malloc() to
320 get a larger buffer, and try again. In the latter case,
321 we use the returned information to build a buffer of the
324 if (numwritten == -1)
326 /* Writing failed, and we don't know the needed size.
327 Try again with doubled size. */
328 available_size <<= 1;
329 bigmsg = xrealloc (bigmsg, available_size);
332 else if (numwritten >= available_size)
334 /* Writing failed, but we know exactly how much space we
336 available_size = numwritten + 1;
337 bigmsg = xrealloc (bigmsg, available_size);
342 /* Writing succeeded. */
346 saved_append (write_ptr);
347 fputs (write_ptr, logfp);
359 CANONICALIZE_LOGFP_OR_RETURN;
363 /* Portability with pre-ANSI compilers makes these two functions look
366 #ifdef WGET_USE_STDARG
368 logprintf (enum log_options o, const char *fmt, ...)
369 #else /* not WGET_USE_STDARG */
373 #endif /* not WGET_USE_STDARG */
376 #ifndef WGET_USE_STDARG
381 #ifdef WGET_USE_STDARG
382 va_start (args, fmt);
385 o = va_arg (args, enum log_options);
386 fmt = va_arg (args, char *);
388 logvprintf (o, fmt, args);
393 /* The same as logprintf(), but does anything only if opt.debug is
395 #ifdef WGET_USE_STDARG
397 debug_logprintf (const char *fmt, ...)
398 #else /* not WGET_USE_STDARG */
400 debug_logprintf (va_alist)
402 #endif /* not WGET_USE_STDARG */
407 #ifndef WGET_USE_STDARG
411 #ifdef WGET_USE_STDARG
412 va_start (args, fmt);
415 fmt = va_arg (args, char *);
417 logvprintf (LOG_ALWAYS, fmt, args);
423 /* Open FILE and set up a logging stream. If FILE cannot be opened,
424 exit with status of 1. */
426 log_init (const char *file, int appendp)
430 logfp = fopen (file, appendp ? "a" : "w");
433 perror (opt.lfilename);
439 /* The log goes to stderr to avoid collisions with the output if
440 the user specifies `-O -'. #### Francois Pinard suggests
441 that it's a better idea to print to stdout by default, and to
442 stderr only if the user actually specifies `-O -'. He says
443 this inconsistency is harder to document, but is overall
444 easier on the user. */
447 /* If the output is a TTY, enable logging, which will make Wget
448 remember all the printed messages, to be able to dump them to
449 a log file in case SIGHUP or SIGUSR1 is received (or
450 Ctrl+Break is pressed under Windows). */
453 && isatty (fileno (logfp))
462 /* Close LOGFP, inhibit further logging and free the memory associated
472 for (i = 0; i < SAVED_LOG_LINES; i++)
474 log_line_current = -1;
478 /* Dump saved lines to logfp. */
482 int num = log_line_current;
491 struct log_ln *ln = log_lines + num;
493 fputs (ln->content, fp);
496 while (num != log_line_current);
498 if (log_lines[log_line_current].content)
499 fputs (log_lines[log_line_current].content, fp);
503 /* Redirect output to `wget-log'. MESSIJ is printed on stdout, and
504 should contain *exactly one* `%s', which will be replaced by the
507 If logging was not enabled, MESSIJ will not be printed. */
509 redirect_output (const char *messij)
516 logfile = unique_name (DEFAULT_LOGFILE);
517 logfp = fopen (logfile, "w");
520 /* Eek! Opening the alternate log file has failed. Nothing we
521 can do but disable printing completely. */
522 fprintf (stderr, "%s: %s: %s\n", exec_name, logfile, strerror (errno));
523 /* `stdin' is magic to not print anything, ever. */
526 fprintf (stderr, messij, logfile);
528 /* Dump the previous screenful of output to LOGFILE. */