]> sjero.net Git - wget/blob - src/main.c
Move numurls out of options struct.
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3    2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
5 This file is part of GNU Wget.
6
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a
24 modified version of that library), containing parts covered by the
25 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
26 grants you additional permission to convey the resulting work.
27 Corresponding Source for a non-source form of such a combination
28 shall include the source code for the parts of OpenSSL used as well
29 as that of the covered work.  */
30
31 #include "wget.h"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif /* HAVE_UNISTD_H */
38 #include <string.h>
39 #include <signal.h>
40 #ifdef ENABLE_NLS
41 # include <locale.h>
42 #endif
43 #include <assert.h>
44 #include <errno.h>
45 #include <time.h>
46
47 #include "utils.h"
48 #include "init.h"
49 #include "retr.h"
50 #include "recur.h"
51 #include "host.h"
52 #include "url.h"
53 #include "progress.h"           /* for progress_handle_sigwinch */
54 #include "convert.h"
55 #include "spider.h"
56 #include "http.h"               /* for save_cookies */
57
58 #include <getopt.h>
59 #include <getpass.h>
60 #include <quote.h>
61
62 #ifndef PATH_SEPARATOR
63 # define PATH_SEPARATOR '/'
64 #endif
65
66 struct options opt;
67
68 /* defined in version.c */
69 extern char *version_string;
70 extern char *compilation_string;
71 extern char *system_getrc;
72 extern char *link_string;
73 /* defined in build_info.c */
74 extern char *compiled_features[];
75 /* Used for --version output in print_version */
76 static const int max_chars_per_line = 72;
77
78 #if defined(SIGHUP) || defined(SIGUSR1)
79 static void redirect_output_signal (int);
80 #endif
81
82 const char *exec_name;
83
84 /* Number of successfully downloaded URLs */
85 int numurls = 0;
86 \f
87 #ifndef TESTING
88 /* Initialize I18N/L10N.  That amounts to invoking setlocale, and
89    setting up gettext's message catalog using bindtextdomain and
90    textdomain.  Does nothing if NLS is disabled or missing.  */
91
92 static void
93 i18n_initialize (void)
94 {
95   /* ENABLE_NLS implies existence of functions invoked here.  */
96 #ifdef ENABLE_NLS
97   /* Set the current locale.  */
98   setlocale (LC_ALL, "");
99   /* Set the text message domain.  */
100   bindtextdomain ("wget", LOCALEDIR);
101   textdomain ("wget");
102 #endif /* ENABLE_NLS */
103 }
104 \f
105 /* Definition of command-line options. */
106
107 static void print_help (void);
108 static void print_version (void);
109
110 #ifdef HAVE_SSL
111 # define IF_SSL(x) x
112 #else
113 # define IF_SSL(x) NULL
114 #endif
115
116 #ifdef ENABLE_DEBUG
117 # define WHEN_DEBUG(x) x
118 #else
119 # define WHEN_DEBUG(x) NULL
120 #endif
121
122 struct cmdline_option {
123   const char *long_name;
124   char short_name;
125   enum {
126     OPT_VALUE,
127     OPT_BOOLEAN,
128     OPT_FUNCALL,
129     /* Non-standard options that have to be handled specially in
130        main().  */
131     OPT__APPEND_OUTPUT,
132     OPT__CLOBBER,
133     OPT__DONT_REMOVE_LISTING,
134     OPT__EXECUTE,
135     OPT__NO,
136     OPT__PARENT
137   } type;
138   const void *data;             /* for standard options */
139   int argtype;                  /* for non-standard options */
140 };
141
142 static struct cmdline_option option_data[] =
143   {
144     { "accept", 'A', OPT_VALUE, "accept", -1 },
145     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
146     { "ask-password", 0, OPT_BOOLEAN, "askpassword", -1 },
147     { "auth-no-challenge", 0, OPT_BOOLEAN, "authnochallenge", -1 },
148     { "background", 'b', OPT_BOOLEAN, "background", -1 },
149     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
150     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
151     { "base", 'B', OPT_VALUE, "base", -1 },
152     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
153     { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
154     { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
155     { "cache", 0, OPT_BOOLEAN, "cache", -1 },
156     { IF_SSL ("certificate"), 0, OPT_VALUE, "certificate", -1 },
157     { IF_SSL ("certificate-type"), 0, OPT_VALUE, "certificatetype", -1 },
158     { IF_SSL ("check-certificate"), 0, OPT_BOOLEAN, "checkcertificate", -1 },
159     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
160     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
161     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
162     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
163     { "content-disposition", 0, OPT_BOOLEAN, "contentdisposition", -1 },
164     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
165     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
166     { WHEN_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
167     { "default-page", 0, OPT_VALUE, "defaultpage", -1 },
168     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
169     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
170     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
171     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
172     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
173     { "domains", 'D', OPT_VALUE, "domains", -1 },
174     { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
175     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 },
176     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
177     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
178     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
179     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
180     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
181     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
182     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
183     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
184     { "ftp-password", 0, OPT_VALUE, "ftppassword", -1 },
185     { "ftp-user", 0, OPT_VALUE, "ftpuser", -1 },
186     { "glob", 0, OPT_BOOLEAN, "glob", -1 },
187     { "header", 0, OPT_VALUE, "header", -1 },
188     { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
189     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
190     { "html-extension", 'E', OPT_BOOLEAN, "htmlextension", -1 },
191     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
192     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
193     { "http-passwd", 0, OPT_VALUE, "httppassword", -1 }, /* deprecated */
194     { "http-password", 0, OPT_VALUE, "httppassword", -1 },
195     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
196     { "ignore-case", 0, OPT_BOOLEAN, "ignorecase", -1 },
197     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
198     { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
199     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
200 #ifdef ENABLE_IPV6
201     { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
202     { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
203 #endif
204     { "input-file", 'i', OPT_VALUE, "input", -1 },
205     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
206     { "level", 'l', OPT_VALUE, "reclevel", -1 },
207     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
208     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
209     { "max-redirect", 0, OPT_VALUE, "maxredirect", -1 },
210     { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
211     { "no", 'n', OPT__NO, NULL, required_argument },
212     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
213     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
214     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
215     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
216     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
217     { "parent", 0, OPT__PARENT, NULL, optional_argument },
218     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
219     { "password", 0, OPT_VALUE, "password", -1 },
220     { "post-data", 0, OPT_VALUE, "postdata", -1 },
221     { "post-file", 0, OPT_VALUE, "postfile", -1 },
222     { "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
223     { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
224     { IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
225     { IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
226     { "progress", 0, OPT_VALUE, "progress", -1 },
227     { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
228     { "proxy", 0, OPT_BOOLEAN, "useproxy", -1 },
229     { "proxy__compat", 'Y', OPT_VALUE, "useproxy", -1 }, /* back-compatible */
230     { "proxy-passwd", 0, OPT_VALUE, "proxypassword", -1 }, /* deprecated */
231     { "proxy-password", 0, OPT_VALUE, "proxypassword", -1 },
232     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
233     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
234     { "quota", 'Q', OPT_VALUE, "quota", -1 },
235     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
236     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
237     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
238     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
239     { "referer", 0, OPT_VALUE, "referer", -1 },
240     { "reject", 'R', OPT_VALUE, "reject", -1 },
241     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
242     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
243     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
244     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
245     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
246     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
247     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
248     { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
249     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
250     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
251     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
252     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
253     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
254     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
255     { "tries", 't', OPT_VALUE, "tries", -1 },
256     { "user", 0, OPT_VALUE, "user", -1 },
257     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
258     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
259     { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
260     { "version", 'V', OPT_FUNCALL, (void *) print_version, no_argument },
261     { "wait", 'w', OPT_VALUE, "wait", -1 },
262     { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
263 #ifdef MSDOS
264     { "wdebug", 0, OPT_BOOLEAN, "wdebug", -1 },
265 #endif
266   };
267
268 #undef WHEN_DEBUG
269 #undef IF_SSL
270
271 /* Return a string that contains S with "no-" prepended.  The string
272    is NUL-terminated and allocated off static storage at Wget
273    startup.  */
274
275 static char *
276 no_prefix (const char *s)
277 {
278   static char buffer[1024];
279   static char *p = buffer;
280
281   char *cp = p;
282   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
283   if (p + size >= buffer + sizeof (buffer))
284     abort ();
285
286   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
287   strcpy (cp + 3, s);
288   p += size;
289   return cp;
290 }
291
292 /* The arguments that that main passes to getopt_long. */
293 static struct option long_options[2 * countof (option_data) + 1];
294 static char short_options[128];
295
296 /* Mapping between short option chars and option_data indices. */
297 static unsigned char optmap[96];
298
299 /* Marker for `--no-FOO' values in long_options.  */
300 #define BOOLEAN_NEG_MARKER 1024
301
302 /* Initialize the long_options array used by getopt_long from the data
303    in option_data.  */
304
305 static void
306 init_switches (void)
307 {
308   char *p = short_options;
309   size_t i, o = 0;
310   for (i = 0; i < countof (option_data); i++)
311     {
312       struct cmdline_option *opt = &option_data[i];
313       struct option *longopt;
314
315       if (!opt->long_name)
316         /* The option is disabled. */
317         continue;
318
319       longopt = &long_options[o++];
320       longopt->name = opt->long_name;
321       longopt->val = i;
322       if (opt->short_name)
323         {
324           *p++ = opt->short_name;
325           optmap[opt->short_name - 32] = longopt - long_options;
326         }
327       switch (opt->type)
328         {
329         case OPT_VALUE:
330           longopt->has_arg = required_argument;
331           if (opt->short_name)
332             *p++ = ':';
333           break;
334         case OPT_BOOLEAN:
335           /* Specify an optional argument for long options, so that
336              --option=off works the same as --no-option, for
337              compatibility with pre-1.10 Wget.  However, don't specify
338              optional arguments short-option booleans because they
339              prevent combining of short options.  */
340           longopt->has_arg = optional_argument;
341           /* For Boolean options, add the "--no-FOO" variant, which is
342              identical to "--foo", except it has opposite meaning and
343              it doesn't allow an argument.  */
344           longopt = &long_options[o++];
345           longopt->name = no_prefix (opt->long_name);
346           longopt->has_arg = no_argument;
347           /* Mask the value so we'll be able to recognize that we're
348              dealing with the false value.  */
349           longopt->val = i | BOOLEAN_NEG_MARKER;
350           break;
351         default:
352           assert (opt->argtype != -1);
353           longopt->has_arg = opt->argtype;
354           if (opt->short_name)
355             {
356               if (longopt->has_arg == required_argument)
357                 *p++ = ':';
358               /* Don't handle optional_argument */
359             }
360         }
361     }
362   /* Terminate short_options. */
363   *p = '\0';
364   /* No need for xzero(long_options[o]) because its storage is static
365      and it will be zeroed by default.  */
366   assert (o <= countof (long_options));
367 }
368
369 /* Print the usage message.  */
370 static void
371 print_usage (void)
372 {
373   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
374 }
375
376 /* Print the help message, describing all the available options.  If
377    you add an option, be sure to update this list.  */
378 static void
379 print_help (void)
380 {
381   /* We split the help text this way to ease translation of individual
382      entries.  */
383   static const char *help[] = {
384     "\n",
385     N_("\
386 Mandatory arguments to long options are mandatory for short options too.\n\n"),
387     N_("\
388 Startup:\n"),
389     N_("\
390   -V,  --version           display the version of Wget and exit.\n"),
391     N_("\
392   -h,  --help              print this help.\n"),
393     N_("\
394   -b,  --background        go to background after startup.\n"),
395     N_("\
396   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
397     "\n",
398
399     N_("\
400 Logging and input file:\n"),
401     N_("\
402   -o,  --output-file=FILE    log messages to FILE.\n"),
403     N_("\
404   -a,  --append-output=FILE  append messages to FILE.\n"),
405 #ifdef ENABLE_DEBUG
406     N_("\
407   -d,  --debug               print lots of debugging information.\n"),
408 #endif
409 #ifdef MSDOS
410     N_("\
411        --wdebug              print Watt-32 debug output.\n"),
412 #endif
413     N_("\
414   -q,  --quiet               quiet (no output).\n"),
415     N_("\
416   -v,  --verbose             be verbose (this is the default).\n"),
417     N_("\
418   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
419     N_("\
420   -i,  --input-file=FILE     download URLs found in local or external FILE.\n"),
421     N_("\
422   -F,  --force-html          treat input file as HTML.\n"),
423     N_("\
424   -B,  --base=URL            prepends URL to relative links in -F -i file.\n"),
425     "\n",
426
427     N_("\
428 Download:\n"),
429     N_("\
430   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
431     N_("\
432        --retry-connrefused       retry even if connection is refused.\n"),
433     N_("\
434   -O,  --output-document=FILE    write documents to FILE.\n"),
435     N_("\
436   -nc, --no-clobber              skip downloads that would download to\n\
437                                  existing files.\n"),
438     N_("\
439   -c,  --continue                resume getting a partially-downloaded file.\n"),
440     N_("\
441        --progress=TYPE           select progress gauge type.\n"),
442     N_("\
443   -N,  --timestamping            don't re-retrieve files unless newer than\n\
444                                  local.\n"),
445     N_("\
446   -S,  --server-response         print server response.\n"),
447     N_("\
448        --spider                  don't download anything.\n"),
449     N_("\
450   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
451     N_("\
452        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
453     N_("\
454        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
455     N_("\
456        --read-timeout=SECS       set the read timeout to SECS.\n"),
457     N_("\
458   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
459     N_("\
460        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
461     N_("\
462        --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
463     N_("\
464        --no-proxy                explicitly turn off proxy.\n"),
465     N_("\
466   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
467     N_("\
468        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
469     N_("\
470        --limit-rate=RATE         limit download rate to RATE.\n"),
471     N_("\
472        --no-dns-cache            disable caching DNS lookups.\n"),
473     N_("\
474        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
475     N_("\
476        --ignore-case             ignore case when matching files/directories.\n"),
477 #ifdef ENABLE_IPV6
478     N_("\
479   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
480     N_("\
481   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
482     N_("\
483        --prefer-family=FAMILY    connect first to addresses of specified family,\n\
484                                  one of IPv6, IPv4, or none.\n"),
485 #endif
486     N_("\
487        --user=USER               set both ftp and http user to USER.\n"),
488     N_("\
489        --password=PASS           set both ftp and http password to PASS.\n"),
490     N_("\
491        --ask-password            prompt for passwords.\n"),
492     "\n",
493
494     N_("\
495 Directories:\n"),
496     N_("\
497   -nd, --no-directories           don't create directories.\n"),
498     N_("\
499   -x,  --force-directories        force creation of directories.\n"),
500     N_("\
501   -nH, --no-host-directories      don't create host directories.\n"),
502     N_("\
503        --protocol-directories     use protocol name in directories.\n"),
504     N_("\
505   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
506     N_("\
507        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
508     "\n",
509
510     N_("\
511 HTTP options:\n"),
512     N_("\
513        --http-user=USER        set http user to USER.\n"),
514     N_("\
515        --http-password=PASS    set http password to PASS.\n"),
516     N_("\
517        --no-cache              disallow server-cached data.\n"),
518     N_ ("\
519        --default-page=NAME     Change the default page name (normally\n\
520                                this is `index.html'.).\n"),
521     N_("\
522   -E,  --html-extension        save HTML documents with `.html' extension.\n"),
523     N_("\
524        --ignore-length         ignore `Content-Length' header field.\n"),
525     N_("\
526        --header=STRING         insert STRING among the headers.\n"),
527     N_("\
528        --max-redirect          maximum redirections allowed per page.\n"),
529     N_("\
530        --proxy-user=USER       set USER as proxy username.\n"),
531     N_("\
532        --proxy-password=PASS   set PASS as proxy password.\n"),
533     N_("\
534        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
535     N_("\
536        --save-headers          save the HTTP headers to file.\n"),
537     N_("\
538   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
539     N_("\
540        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
541     N_("\
542        --no-cookies            don't use cookies.\n"),
543     N_("\
544        --load-cookies=FILE     load cookies from FILE before session.\n"),
545     N_("\
546        --save-cookies=FILE     save cookies to FILE after session.\n"),
547     N_("\
548        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
549     N_("\
550        --post-data=STRING      use the POST method; send STRING as the data.\n"),
551     N_("\
552        --post-file=FILE        use the POST method; send contents of FILE.\n"),
553     N_("\
554        --content-disposition   honor the Content-Disposition header when\n\
555                                choosing local file names (EXPERIMENTAL).\n"),
556     N_("\
557        --auth-no-challenge     Send Basic HTTP authentication information\n\
558                                without first waiting for the server's\n\
559                                challenge.\n"),
560     "\n",
561
562 #ifdef HAVE_SSL
563     N_("\
564 HTTPS (SSL/TLS) options:\n"),
565     N_("\
566        --secure-protocol=PR     choose secure protocol, one of auto, SSLv2,\n\
567                                 SSLv3, and TLSv1.\n"),
568     N_("\
569        --no-check-certificate   don't validate the server's certificate.\n"),
570     N_("\
571        --certificate=FILE       client certificate file.\n"),
572     N_("\
573        --certificate-type=TYPE  client certificate type, PEM or DER.\n"),
574     N_("\
575        --private-key=FILE       private key file.\n"),
576     N_("\
577        --private-key-type=TYPE  private key type, PEM or DER.\n"),
578     N_("\
579        --ca-certificate=FILE    file with the bundle of CA's.\n"),
580     N_("\
581        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
582     N_("\
583        --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
584     N_("\
585        --egd-file=FILE          file naming the EGD socket with random data.\n"),
586     "\n",
587 #endif /* HAVE_SSL */
588
589     N_("\
590 FTP options:\n"),
591     N_("\
592        --ftp-user=USER         set ftp user to USER.\n"),
593     N_("\
594        --ftp-password=PASS     set ftp password to PASS.\n"),
595     N_("\
596        --no-remove-listing     don't remove `.listing' files.\n"),
597     N_("\
598        --no-glob               turn off FTP file name globbing.\n"),
599     N_("\
600        --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
601     N_("\
602        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
603     N_("\
604        --preserve-permissions  preserve remote file permissions.\n"),
605     "\n",
606
607     N_("\
608 Recursive download:\n"),
609     N_("\
610   -r,  --recursive          specify recursive download.\n"),
611     N_("\
612   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
613     N_("\
614        --delete-after       delete files locally after downloading them.\n"),
615     N_("\
616   -k,  --convert-links      make links in downloaded HTML or CSS point to\n\
617                             local files.\n"),
618     N_("\
619   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
620     N_("\
621   -m,  --mirror             shortcut for -N -r -l inf --no-remove-listing.\n"),
622     N_("\
623   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
624     N_("\
625        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
626     "\n",
627
628     N_("\
629 Recursive accept/reject:\n"),
630     N_("\
631   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
632     N_("\
633   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
634     N_("\
635   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
636     N_("\
637        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
638     N_("\
639        --follow-ftp                follow FTP links from HTML documents.\n"),
640     N_("\
641        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
642     N_("\
643        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
644     N_("\
645   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
646     N_("\
647   -L,  --relative                  follow relative links only.\n"),
648     N_("\
649   -I,  --include-directories=LIST  list of allowed directories.\n"),
650     N_("\
651   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
652     N_("\
653   -np, --no-parent                 don't ascend to the parent directory.\n"),
654     "\n",
655
656     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
657   };
658
659   size_t i;
660
661   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
662           version_string);
663   print_usage ();
664
665   for (i = 0; i < countof (help); i++)
666     fputs (_(help[i]), stdout);
667
668   exit (0);
669 }
670
671 /* Return a human-readable printed representation of INTERVAL,
672    measured in seconds.  */
673
674 static char *
675 secs_to_human_time (double interval)
676 {
677   static char buf[32];
678   int secs = (int) (interval + 0.5);
679   int hours, mins, days;
680
681   days = secs / 86400, secs %= 86400;
682   hours = secs / 3600, secs %= 3600;
683   mins = secs / 60, secs %= 60;
684
685   if (days)
686     sprintf (buf, "%dd %dh %dm %ds", days, hours, mins, secs);
687   else if (hours)
688     sprintf (buf, "%dh %dm %ds", hours, mins, secs);
689   else if (mins)
690     sprintf (buf, "%dm %ds", mins, secs);
691   else
692     sprintf (buf, "%ss", print_decimal (interval));
693
694   return buf;
695 }
696
697 static char *
698 prompt_for_password (void)
699 {
700   if (opt.user)
701     printf (_("Password for user %s: "), quote (opt.user));
702   else
703     printf (_("Password: "));
704   return getpass("");
705 }
706
707 /* Function that prints the line argument while limiting it
708    to at most line_length. prefix is printed on the first line
709    and an appropriate number of spaces are added on subsequent
710    lines.*/
711 static void
712 format_and_print_line (const char *prefix, const char *line,
713                        int line_length) 
714 {
715   int leading_spaces;
716   int remaining_chars;
717   char *line_dup, *token;
718   
719   assert (prefix != NULL);
720   assert (line != NULL);
721
722   line_dup = xstrdup (line);
723
724   if (line_length <= 0)
725     line_length = max_chars_per_line;
726
727   leading_spaces = strlen (prefix);
728   printf ("%s", prefix);
729   remaining_chars = line_length - leading_spaces;
730   /* We break on spaces. */
731   token = strtok (line_dup, " ");
732   while (token != NULL) 
733     {
734       /* If however a token is much larger than the maximum
735          line length, all bets are off and we simply print the
736          token on the next line. */
737       if (remaining_chars <= strlen (token)) 
738         {
739           printf ("\n%*c", leading_spaces, ' ');
740           remaining_chars = line_length - leading_spaces;
741         }
742       printf ("%s ", token);
743       remaining_chars -= strlen (token) + 1;  // account for " "
744       token = strtok (NULL, " ");
745     }
746
747   printf ("\n");
748
749   xfree (line_dup);
750 }
751
752 static void
753 print_version (void)
754 {
755   const char *options_title = "Options    : ";
756   const char *wgetrc_title  = "Wgetrc     : ";
757   const char *locale_title  = "Locale     : ";
758   const char *compile_title = "Compile    : ";
759   const char *link_title    = "Link       : ";
760   const char *prefix_spaces = "             ";
761   const int prefix_space_length = strlen (prefix_spaces);
762   char *line;
763   char *env_wgetrc, *user_wgetrc;
764   int i;
765
766   printf ("GNU Wget %s\n", version_string);
767   printf (options_title);
768   /* compiled_features is a char*[]. We limit the characters per
769      line to max_chars_per_line and prefix each line with a constant
770      number of spaces for proper alignment. */
771   for (i = 0; compiled_features[i] != NULL; ) 
772     {
773       int line_length = max_chars_per_line - prefix_space_length;
774       while ((line_length > 0) && (compiled_features[i] != NULL)) 
775         {
776           printf ("%s ", compiled_features[i]);
777           line_length -= strlen (compiled_features[i]) + 2;
778           i++;
779         }
780       printf ("\n");
781       if (compiled_features[i] != NULL) 
782         {
783           printf (prefix_spaces);
784         }
785     }
786   /* Handle the case when $WGETRC is unset and $HOME/.wgetrc is 
787      absent. */
788   printf (wgetrc_title);
789   env_wgetrc = wgetrc_env_file_name ();
790   if (env_wgetrc && *env_wgetrc) 
791     {
792       printf ("%s (env)\n%s", env_wgetrc, prefix_spaces);
793       xfree (env_wgetrc);
794     }
795   user_wgetrc = wgetrc_user_file_name ();
796   if (user_wgetrc) 
797     {
798       printf ("%s (user)\n%s", user_wgetrc, prefix_spaces);
799       xfree (user_wgetrc);
800     }
801 #ifdef SYSTEM_WGETRC
802   printf ("%s (system)\n", SYSTEM_WGETRC);
803 #else
804   putchar ('\n');
805 #endif
806
807   format_and_print_line (locale_title,
808                          LOCALEDIR, 
809                          max_chars_per_line);
810   
811   format_and_print_line (compile_title,
812                          compilation_string,
813                          max_chars_per_line);
814
815   format_and_print_line (link_title,
816                          link_string,
817                          max_chars_per_line);
818
819   printf ("\n");
820   /* TRANSLATORS: When available, an actual copyright character
821      (cirle-c) should be used in preference to "(C)". */
822   fputs (_("\
823 Copyright (C) 2008 Free Software Foundation, Inc.\n"), stdout);
824   fputs (_("\
825 License GPLv3+: GNU GPL version 3 or later\n\
826 <http://www.gnu.org/licenses/gpl.html>.\n\
827 This is free software: you are free to change and redistribute it.\n\
828 There is NO WARRANTY, to the extent permitted by law.\n"), stdout);
829   /* TRANSLATORS: When available, please use the proper diacritics for
830      names such as this one. See en_US.po for reference. */
831   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
832          stdout);
833   fputs (_("Currently maintained by Micah Cowan <micah@cowan.name>.\n"),
834          stdout);
835   fputs (_("Please send bug reports and questions to <bug-wget@gnu.org>.\n"),
836          stdout);
837   exit (0);
838 }
839
840 char *program_name; /* Needed by lib/error.c. */
841
842 int
843 main (int argc, char **argv)
844 {
845   char **url, **t;
846   int i, ret, longindex;
847   int nurl, status;
848   bool append_to_log = false;
849
850   program_name = argv[0];
851
852   i18n_initialize ();
853
854   /* Construct the name of the executable, without the directory part.  */
855   exec_name = strrchr (argv[0], PATH_SEPARATOR);
856   if (!exec_name)
857     exec_name = argv[0];
858   else
859     ++exec_name;
860
861 #ifdef WINDOWS
862   /* Drop extension (typically .EXE) from executable filename. */
863   windows_main ((char **) &exec_name);
864 #endif
865
866   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
867   initialize ();
868
869   init_switches ();
870   longindex = -1;
871   while ((ret = getopt_long (argc, argv,
872                              short_options, long_options, &longindex)) != -1)
873     {
874       int val;
875       struct cmdline_option *opt;
876
877       /* If LONGINDEX is unchanged, it means RET is referring a short
878          option.  */
879       if (longindex == -1)
880         {
881           if (ret == '?')
882             {
883               print_usage ();
884               printf ("\n");
885               printf (_("Try `%s --help' for more options.\n"), exec_name);
886               exit (2);
887             }
888           /* Find the short option character in the mapping.  */
889           longindex = optmap[ret - 32];
890         }
891       val = long_options[longindex].val;
892
893       /* Use the retrieved value to locate the option in the
894          option_data array, and to see if we're dealing with the
895          negated "--no-FOO" variant of the boolean option "--foo".  */
896       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
897       switch (opt->type)
898         {
899         case OPT_VALUE:
900           setoptval (opt->data, optarg, opt->long_name);
901           break;
902         case OPT_BOOLEAN:
903           if (optarg)
904             /* The user has specified a value -- use it. */
905             setoptval (opt->data, optarg, opt->long_name);
906           else
907             {
908               /* NEG is true for `--no-FOO' style boolean options. */
909               bool neg = !!(val & BOOLEAN_NEG_MARKER);
910               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
911             }
912           break;
913         case OPT_FUNCALL:
914           {
915             void (*func) (void) = (void (*) (void)) opt->data;
916             func ();
917           }
918           break;
919         case OPT__APPEND_OUTPUT:
920           setoptval ("logfile", optarg, opt->long_name);
921           append_to_log = true;
922           break;
923         case OPT__EXECUTE:
924           run_command (optarg);
925           break;
926         case OPT__NO:
927           {
928             /* We support real --no-FOO flags now, but keep these
929                short options for convenience and backward
930                compatibility.  */
931             char *p;
932             for (p = optarg; *p; p++)
933               switch (*p)
934                 {
935                 case 'v':
936                   setoptval ("verbose", "0", opt->long_name);
937                   break;
938                 case 'H':
939                   setoptval ("addhostdir", "0", opt->long_name);
940                   break;
941                 case 'd':
942                   setoptval ("dirstruct", "0", opt->long_name);
943                   break;
944                 case 'c':
945                   setoptval ("noclobber", "1", opt->long_name);
946                   break;
947                 case 'p':
948                   setoptval ("noparent", "1", opt->long_name);
949                   break;
950                 default:
951                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
952                   print_usage ();
953                   printf ("\n");
954                   printf (_("Try `%s --help' for more options.\n"), exec_name);
955                   exit (1);
956                 }
957             break;
958           }
959         case OPT__PARENT:
960         case OPT__CLOBBER:
961           {
962             /* The wgetrc commands are named noparent and noclobber,
963                so we must revert the meaning of the cmdline options
964                before passing the value to setoptval.  */
965             bool flag = true;
966             if (optarg)
967               flag = (*optarg == '1' || c_tolower (*optarg) == 'y'
968                       || (c_tolower (optarg[0]) == 'o'
969                           && c_tolower (optarg[1]) == 'n'));
970             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
971                        flag ? "0" : "1", opt->long_name);
972             break;
973           }
974         case OPT__DONT_REMOVE_LISTING:
975           setoptval ("removelisting", "0", opt->long_name);
976           break;
977         }
978
979       longindex = -1;
980     }
981
982   nurl = argc - optind;
983
984   /* All user options have now been processed, so it's now safe to do
985      interoption dependency checks. */
986
987   if (opt.reclevel == 0)
988       opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary */
989
990   if (opt.spider || opt.delete_after)
991       opt.no_dirstruct = true;
992
993   if (opt.page_requisites && !opt.recursive)
994     {
995       /* Don't set opt.recursive here because it would confuse the FTP
996          code.  Instead, call retrieve_tree below when either
997          page_requisites or recursive is requested.  */
998       opt.reclevel = 0;
999       if (!opt.no_dirstruct)
1000         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
1001     }
1002
1003   if (opt.verbose == -1)
1004     opt.verbose = !opt.quiet;
1005
1006   /* Sanity checks.  */
1007   if (opt.verbose && opt.quiet)
1008     {
1009       printf (_("Can't be verbose and quiet at the same time.\n"));
1010       print_usage ();
1011       exit (1);
1012     }
1013   if (opt.timestamping && opt.noclobber)
1014     {
1015       printf (_("\
1016 Can't timestamp and not clobber old files at the same time.\n"));
1017       print_usage ();
1018       exit (1);
1019     }
1020 #ifdef ENABLE_IPV6
1021   if (opt.ipv4_only && opt.ipv6_only)
1022     {
1023       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
1024       print_usage ();
1025       exit (1);
1026     }
1027 #endif
1028   if (opt.output_document)
1029     {
1030       if (opt.convert_links 
1031           && (nurl > 1 || opt.page_requisites || opt.recursive))
1032         {
1033           fputs (_("\
1034 Cannot specify both -k and -O if multiple URLs are given, or in combination\n\
1035 with -p or -r. See the manual for details.\n\n"), stdout);
1036           print_usage ();
1037           exit (1);
1038         }
1039       if (opt.page_requisites
1040           || opt.recursive)
1041         {
1042           logprintf (LOG_NOTQUIET, "%s", _("\
1043 WARNING: combining -O with -r or -p will mean that all downloaded content\n\
1044 will be placed in the single file you specified.\n\n"));
1045         }
1046       if (opt.timestamping)
1047         {
1048           logprintf (LOG_NOTQUIET, "%s", _("\
1049 WARNING: timestamping does nothing in combination with -O. See the manual\n\
1050 for details.\n\n"));
1051           opt.timestamping = false;
1052         }
1053       if (opt.noclobber && file_exists_p(opt.output_document)) 
1054            { 
1055               /* Check if output file exists; if it does, exit. */
1056               logprintf (LOG_VERBOSE, _("File `%s' already there; not retrieving.\n"), opt.output_document);
1057               exit(1);
1058            }  
1059     }
1060
1061   if (opt.ask_passwd && opt.passwd)
1062     {
1063       printf (_("Cannot specify both --ask-password and --password.\n"));
1064       print_usage ();
1065       exit (1);
1066     }
1067
1068   if (!nurl && !opt.input_filename)
1069     {
1070       /* No URL specified.  */
1071       printf (_("%s: missing URL\n"), exec_name);
1072       print_usage ();
1073       printf ("\n");
1074       /* #### Something nicer should be printed here -- similar to the
1075          pre-1.5 `--help' page.  */
1076       printf (_("Try `%s --help' for more options.\n"), exec_name);
1077       exit (1);
1078     }
1079
1080   if (opt.ask_passwd)
1081     {
1082       opt.passwd = prompt_for_password ();
1083
1084       if (opt.passwd == NULL || opt.passwd[0] == '\0')
1085         exit (1);
1086     }
1087
1088 #ifdef MSDOS
1089   if (opt.wdebug)
1090      dbug_init();
1091   sock_init();
1092 #else
1093   if (opt.background)
1094     fork_to_background ();
1095 #endif
1096
1097   /* Initialize progress.  Have to do this after the options are
1098      processed so we know where the log file is.  */
1099   if (opt.verbose)
1100     set_progress_implementation (opt.progress_type);
1101
1102   /* Fill in the arguments.  */
1103   url = alloca_array (char *, nurl + 1);
1104   for (i = 0; i < nurl; i++, optind++)
1105     {
1106       char *rewritten = rewrite_shorthand_url (argv[optind]);
1107       if (rewritten)
1108         url[i] = rewritten;
1109       else
1110         url[i] = xstrdup (argv[optind]);
1111     }
1112   url[i] = NULL;
1113
1114   /* Initialize logging.  */
1115   log_init (opt.lfilename, append_to_log);
1116
1117   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
1118            OS_TYPE));
1119
1120   /* Open the output filename if necessary.  */
1121   if (opt.output_document)
1122     {
1123       if (HYPHENP (opt.output_document))
1124         {
1125 #ifdef WINDOWS
1126           FILE *result;
1127           result = freopen (NULL, "wb", stdout);
1128           if (result == NULL)
1129             {
1130               logputs (LOG_NOTQUIET, _("\
1131 WARNING: Can't reopen standard output in binary mode;\n\
1132          downloaded file may contain inappropriate line endings.\n"));
1133             }
1134 #endif
1135           output_stream = stdout;
1136         }
1137       else
1138         {
1139           struct_fstat st;
1140           output_stream = fopen (opt.output_document,
1141                                  opt.always_rest ? "ab" : "wb");
1142           if (output_stream == NULL)
1143             {
1144               perror (opt.output_document);
1145               exit (1);
1146             }
1147           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
1148             output_stream_regular = true;
1149         }
1150     }
1151
1152 #ifdef WINDOWS
1153   ws_startup ();
1154 #endif
1155
1156 #ifdef SIGHUP
1157   /* Setup the signal handler to redirect output when hangup is
1158      received.  */
1159   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1160     signal(SIGHUP, redirect_output_signal);
1161 #endif
1162   /* ...and do the same for SIGUSR1.  */
1163 #ifdef SIGUSR1
1164   signal (SIGUSR1, redirect_output_signal);
1165 #endif
1166 #ifdef SIGPIPE
1167   /* Writing to a closed socket normally signals SIGPIPE, and the
1168      process exits.  What we want is to ignore SIGPIPE and just check
1169      for the return value of write().  */
1170   signal (SIGPIPE, SIG_IGN);
1171 #endif
1172 #ifdef SIGWINCH
1173   signal (SIGWINCH, progress_handle_sigwinch);
1174 #endif
1175
1176   status = RETROK;              /* initialize it, just-in-case */
1177   /* Retrieve the URLs from argument list.  */
1178   for (t = url; *t; t++)
1179     {
1180       char *filename = NULL, *redirected_URL = NULL;
1181       int dt;
1182
1183       if ((opt.recursive || opt.page_requisites)
1184           && (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (*t)))
1185         {
1186           int old_follow_ftp = opt.follow_ftp;
1187
1188           /* Turn opt.follow_ftp on in case of recursive FTP retrieval */
1189           if (url_scheme (*t) == SCHEME_FTP) 
1190             opt.follow_ftp = 1;
1191           
1192           status = retrieve_tree (*t);
1193
1194           opt.follow_ftp = old_follow_ftp;
1195         }
1196       else
1197         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt, opt.recursive);
1198
1199       if (opt.delete_after && file_exists_p(filename))
1200         {
1201           DEBUGP (("Removing file due to --delete-after in main():\n"));
1202           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
1203           if (unlink (filename))
1204             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1205         }
1206
1207       xfree_null (redirected_URL);
1208       xfree_null (filename);
1209     }
1210
1211   /* And then from the input file, if any.  */
1212   if (opt.input_filename)
1213     {
1214       int count;
1215       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
1216       if (!count)
1217         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
1218                    opt.input_filename);
1219     }
1220
1221   /* Print broken links. */
1222   if (opt.recursive && opt.spider)
1223     {
1224       print_broken_links();
1225     }
1226   
1227   /* Print the downloaded sum.  */
1228   if ((opt.recursive || opt.page_requisites
1229        || nurl > 1
1230        || (opt.input_filename && total_downloaded_bytes != 0))
1231       &&
1232       total_downloaded_bytes != 0)
1233     {
1234       logprintf (LOG_NOTQUIET,
1235                  _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
1236                  datetime_str (time (NULL)),
1237                  numurls,
1238                  human_readable (total_downloaded_bytes),
1239                  secs_to_human_time (total_download_time),
1240                  retr_rate (total_downloaded_bytes, total_download_time));
1241       /* Print quota warning, if exceeded.  */
1242       if (opt.quota && total_downloaded_bytes > opt.quota)
1243         logprintf (LOG_NOTQUIET,
1244                    _("Download quota of %s EXCEEDED!\n"),
1245                    human_readable (opt.quota));
1246     }
1247
1248   if (opt.cookies_output)
1249     save_cookies ();
1250
1251   if (opt.convert_links && !opt.delete_after)
1252     convert_all_links ();
1253
1254   log_close ();
1255   for (i = 0; i < nurl; i++)
1256     xfree (url[i]);
1257   cleanup ();
1258
1259   if (status == RETROK)
1260     return 0;
1261   else
1262     return 1;
1263 }
1264 #endif /* TESTING */
1265 \f
1266 #if defined(SIGHUP) || defined(SIGUSR1)
1267
1268 /* So the signal_name check doesn't blow when only one is available. */
1269 #ifndef SIGHUP
1270 # define SIGHUP -1
1271 #endif
1272 #ifndef SIGUSR1
1273 # define SIGUSR1 -1
1274 #endif
1275
1276 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1277    will proceed operation as usual, trying to write into a log file.
1278    If that is impossible, the output will be turned off.  */
1279
1280 static void
1281 redirect_output_signal (int sig)
1282 {
1283   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1284                              (sig == SIGUSR1 ? "SIGUSR1" :
1285                               "WTF?!"));
1286   log_request_redirect_output (signal_name);
1287   progress_schedule_redirect ();
1288   signal (sig, redirect_output_signal);
1289 }
1290 #endif
1291
1292 /*
1293  * vim: et ts=2 sw=2
1294  */