]> sjero.net Git - wget/blob - src/log.c
[svn] Initial revision
[wget] / src / log.c
1 /* Messages logging.
2    Copyright (C) 1998 Free Software Foundation, Inc.
3
4 This file is part of Wget.
5
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.
10
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.
15
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.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #ifdef HAVE_STRING_H
24 # include <string.h>
25 #else
26 # include <strings.h>
27 #endif
28 #include <stdlib.h>
29 #if defined(__STDC__) && defined(HAVE_STDARG_H)
30 /* If we have __STDC__ and stdarg.h, we'll assume it's an ANSI system.  */
31 # define USE_STDARG
32 # include <stdarg.h>
33 #else
34 # include <varargs.h>
35 #endif
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #include <assert.h>
40 #include <errno.h>
41
42 #include "wget.h"
43 #include "utils.h"
44
45 #ifndef errno
46 extern int errno;
47 #endif
48
49 /* We expect no message passed to logprintf() to be bigger than this.
50    Before a message is printed, we make sure that at least this much
51    room is left for printing it.  */
52 #define SAVED_LOG_MAXMSG 32768
53
54 /* Maximum allowed growing size.  */
55 #define SAVED_LOG_MAXSIZE (10 * 1L << 20)
56
57 static char *saved_log;
58 /* Size of the current log.  */
59 static long saved_log_size;
60 /* Offset into the log where we are about to print (size of the
61    used-up part of SAVED_LOG).  */
62 static long saved_log_offset;
63 /* Whether logging is saved at all.  */
64 int save_log_p;
65
66 static FILE *logfp;
67
68 /* Check X against opt.verbose and opt.quiet.  The semantics is as
69    follows:
70
71    * LOG_ALWAYS - print the message unconditionally;
72
73    * LOG_NOTQUIET - print the message if opt.quiet is non-zero;
74
75    * LOG_NONVERBOSE - print the message if opt.verbose is zero;
76
77    * LOG_VERBOSE - print the message if opt.verbose is non-zero.  */
78 #define CHECK_VERBOSE(x)                        \
79   switch (x)                                    \
80     {                                           \
81     case LOG_ALWAYS:                            \
82       break;                                    \
83     case LOG_NOTQUIET:                          \
84       if (opt.quiet)                            \
85         return;                                 \
86       break;                                    \
87     case LOG_NONVERBOSE:                        \
88       if (opt.verbose || opt.quiet)             \
89         return;                                 \
90       break;                                    \
91     case LOG_VERBOSE:                           \
92       if (!opt.verbose)                         \
93         return;                                 \
94     }
95
96 #define CANONICALIZE_LOGFP_OR_RETURN do {       \
97   if (logfp == stdin)                           \
98     return;                                     \
99   else if (!logfp)                              \
100     /* #### Should this ever happen?  */        \
101     logfp = stderr;                             \
102 } while (0)
103
104 \f
105 void
106 logputs (enum log_options o, const char *s)
107 {
108   CHECK_VERBOSE (o);
109   CANONICALIZE_LOGFP_OR_RETURN;
110
111   fputs (s, logfp);
112   if (!opt.no_flush)
113     fflush (logfp);
114
115   if (save_log_p && saved_log_size < SAVED_LOG_MAXSIZE)
116     {
117       int len = strlen (s);
118
119       /* Increase size of SAVED_LOG exponentially.  */
120       DO_REALLOC (saved_log, saved_log_size,
121                   saved_log_offset + len + 1, char);
122       memcpy (saved_log + saved_log_offset, s, len + 1);
123       saved_log_offset += len;
124     }
125 }
126
127 /* Print a message to the log file logfp.  If logfp is NULL, print to
128    stderr.  If logfp is stdin, don't print at all.  A copy of message
129    will be saved to saved_log, for later reusal by dump_log().  */
130 static void
131 logvprintf (enum log_options o, const char *fmt, va_list args)
132 {
133   CHECK_VERBOSE (o);
134   CANONICALIZE_LOGFP_OR_RETURN;
135
136   /* Originally, we first used vfprintf(), and then checked whether
137      the message needs to be stored with vsprintf().  However, Watcom
138      C didn't like ARGS being used twice, so now we first vsprintf()
139      the message, and then fwrite() it to LOGFP.  */
140   if (save_log_p && saved_log_size < SAVED_LOG_MAXSIZE)
141     {
142       int len;
143       /* Increase size of `saved_log' exponentially.  */
144       DO_REALLOC (saved_log, saved_log_size,
145                   saved_log_offset + SAVED_LOG_MAXMSG, char);
146       /* Print the message to the log saver...  */
147 #ifdef HAVE_VSNPRINTF
148       vsnprintf (saved_log + saved_log_offset, SAVED_LOG_MAXMSG, fmt, args);
149 #else  /* not HAVE_VSNPRINTF */
150       vsprintf (saved_log + saved_log_offset, fmt, args);
151 #endif /* not HAVE_VSNPRINTF */
152       /* ...and then dump it to LOGFP.  */
153       len = strlen (saved_log + saved_log_offset);
154       fwrite (saved_log + saved_log_offset, len, 1, logfp);
155       saved_log_offset += len;
156       /* If we ran off the limits and corrupted something, bail out
157          immediately.  */
158       assert (saved_log_size >= saved_log_offset);
159     }
160   else
161     vfprintf (logfp, fmt, args);
162
163   if (!opt.no_flush)
164     fflush (logfp);
165 }
166
167 /* Flush LOGFP.  */
168 void
169 logflush (void)
170 {
171   CANONICALIZE_LOGFP_OR_RETURN;
172   fflush (logfp);
173 }
174
175 /* Portability makes these two functions look like @#%#@$@#$.  */
176
177 #ifdef USE_STDARG
178 void
179 logprintf (enum log_options o, const char *fmt, ...)
180 #else  /* not USE_STDARG */
181 void
182 logprintf (va_alist)
183      va_dcl
184 #endif /* not USE_STDARG */
185 {
186   va_list args;
187 #ifndef USE_STDARG
188   enum log_options o;
189   const char *fmt;
190 #endif
191
192 #ifdef USE_STDARG
193   va_start (args, fmt);
194 #else
195   va_start (args);
196   o = va_arg (args, enum log_options);
197   fmt = va_arg (args, char *);
198 #endif
199   logvprintf (o, fmt, args);
200   va_end (args);
201 }
202
203 #ifdef DEBUG
204 /* The same as logprintf(), but does anything only if opt.debug is
205    non-zero.  */
206 #ifdef USE_STDARG
207 void
208 debug_logprintf (const char *fmt, ...)
209 #else  /* not USE_STDARG */
210 void
211 debug_logprintf (va_alist)
212      va_dcl
213 #endif /* not USE_STDARG */
214 {
215   if (opt.debug)
216     {
217       va_list args;
218 #ifndef USE_STDARG
219       const char *fmt;
220 #endif
221
222 #ifdef USE_STDARG
223       va_start (args, fmt);
224 #else
225       va_start (args);
226       fmt = va_arg (args, char *);
227 #endif
228       logvprintf (LOG_ALWAYS, fmt, args);
229       va_end (args);
230     }
231 }
232 #endif /* DEBUG */
233 \f
234 /* Open FILE and set up a logging stream.  If FILE cannot be opened,
235    exit with status of 1.  */
236 void
237 log_init (const char *file, int appendp)
238 {
239   if (file)
240     {
241       logfp = fopen (file, appendp ? "a" : "w");
242       if (!logfp)
243         {
244           perror (opt.lfilename);
245           exit (1);
246         }
247     }
248   else
249     {
250       logfp = stderr;
251       /* If the output is a TTY, enable logging, which will make Wget
252          remember all the printed messages, to be able to dump them to
253          a log file in case SIGHUP or SIGUSR1 is received (or
254          Ctrl+Break is pressed under Windows).  */
255       if (1
256 #ifdef HAVE_ISATTY
257           && isatty (fileno (logfp))
258 #endif
259           )
260         {
261           save_log_p = 1;
262         }
263     }
264 }
265
266 /* Close LOGFP, inhibit further logging and free the memory associated
267    with it.  */
268 void
269 log_close (void)
270 {
271   fclose (logfp);
272   save_log_p = 0;
273   FREE_MAYBE (saved_log);
274   saved_log = NULL;
275   saved_log_size = saved_log_offset = 0;
276 }
277
278 /* Dump SAVED_LOG using logprintf(), but quit further logging to memory.
279    Also, free the memory occupied by saved_log.  */
280 static void
281 log_dump (void)
282 {
283   save_log_p = 0;
284   if (!saved_log)
285     return;
286   logputs (LOG_ALWAYS, saved_log);
287   free (saved_log);
288   saved_log = NULL;
289   saved_log_size = saved_log_offset = 0;
290 }
291
292 /* Redirect output to `wget-log' if opt.lfile is stdout.  MESSIJ is
293    printed on stdout, and should contain *exactly one* `%s', which
294    will be replaced by the log file name.
295
296    If logging was not enabled, MESSIJ will not be printed.  */
297 void
298 redirect_output (const char *messij)
299 {
300   char *logfile;
301
302   if (!save_log_p)
303     return;
304
305   logfile = unique_name (DEFAULT_LOGFILE);
306   logfp = fopen (logfile, "w");
307   if (!logfp)
308     {
309       printf ("%s: %s: %s\n", exec_name, logfile, strerror (errno));
310       /* `stdin' is magic to not print anything.  */
311       logfp = stdin;
312     }
313   printf (messij, logfile);
314   free (logfile);
315   /* Dump all the previous messages to LOGFILE.  */
316   log_dump ();
317 }