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