]> sjero.net Git - wget/blob - src/main.c
51209a66071a23e5b28de9fb0900904e7fdf83a9
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1996-2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget 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 GNU Wget 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 Wget; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif /* HAVE_UNISTD_H */
37 #include <string.h>
38 #include <signal.h>
39 #ifdef HAVE_NLS
40 # include <locale.h>
41 #endif
42 #include <assert.h>
43 #include <errno.h>
44
45 #include "wget.h"
46 #include "utils.h"
47 #include "init.h"
48 #include "retr.h"
49 #include "recur.h"
50 #include "host.h"
51 #include "url.h"
52 #include "progress.h"           /* for progress_handle_sigwinch */
53 #include "convert.h"
54 #include "http.h"               /* for save_cookies */
55
56 /* On GNU system this will include system-wide getopt.h. */
57 #include "getopt.h"
58
59 #ifndef PATH_SEPARATOR
60 # define PATH_SEPARATOR '/'
61 #endif
62
63 struct options opt;
64
65 extern char *version_string;
66
67 #if defined(SIGHUP) || defined(SIGUSR1)
68 static void redirect_output_signal (int);
69 #endif
70
71 const char *exec_name;
72 \f
73 /* Initialize I18N/L10N.  That amounts to invoking setlocale, and
74    setting up gettext's message catalog using bindtextdomain and
75    textdomain.  Does nothing if NLS is disabled or missing.  */
76
77 static void
78 i18n_initialize (void)
79 {
80   /* HAVE_NLS implies existence of functions invoked here.  */
81 #ifdef HAVE_NLS
82   /* Set the current locale.  */
83   setlocale (LC_ALL, "");
84   /* Set the text message domain.  */
85   bindtextdomain ("wget", LOCALEDIR);
86   textdomain ("wget");
87 #endif /* HAVE_NLS */
88 }
89 \f
90 /* Definition of command-line options. */
91
92 static void print_help (void);
93 static void print_version (void);
94
95 #ifdef HAVE_SSL
96 # define IF_SSL(x) x
97 #else
98 # define IF_SSL(x) NULL
99 #endif
100
101 #ifdef ENABLE_DEBUG
102 # define WHEN_DEBUG(x) x
103 #else
104 # define WHEN_DEBUG(x) NULL
105 #endif
106
107 struct cmdline_option {
108   const char *long_name;
109   char short_name;
110   enum {
111     OPT_VALUE,
112     OPT_BOOLEAN,
113     OPT_FUNCALL,
114     /* Non-standard options that have to be handled specially in
115        main().  */
116     OPT__APPEND_OUTPUT,
117     OPT__CLOBBER,
118     OPT__DONT_REMOVE_LISTING,
119     OPT__EXECUTE,
120     OPT__NO,
121     OPT__PARENT
122   } type;
123   const void *data;             /* for standard options */
124   int argtype;                  /* for non-standard options */
125 };
126
127 static struct cmdline_option option_data[] =
128   {
129     { "accept", 'A', OPT_VALUE, "accept", -1 },
130     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
131     { "background", 'b', OPT_BOOLEAN, "background", -1 },
132     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
133     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
134     { "base", 'B', OPT_VALUE, "base", -1 },
135     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
136     { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
137     { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
138     { "cache", 0, OPT_BOOLEAN, "cache", -1 },
139     { IF_SSL ("certificate"), 0, OPT_VALUE, "certificate", -1 },
140     { IF_SSL ("certificate-type"), 0, OPT_VALUE, "certificatetype", -1 },
141     { IF_SSL ("check-certificate"), 0, OPT_BOOLEAN, "checkcertificate", -1 },
142     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
143     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
144     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
145     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
146     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
147     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
148     { WHEN_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
149     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
150     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
151     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
152     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
153     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
154     { "domains", 'D', OPT_VALUE, "domains", -1 },
155     { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
156     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 },
157     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
158     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
159     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
160     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
161     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
162     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
163     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
164     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
165     { "ftp-password", 0, OPT_VALUE, "ftppassword", -1 },
166     { "ftp-user", 0, OPT_VALUE, "ftpuser", -1 },
167     { "glob", 0, OPT_BOOLEAN, "glob", -1 },
168     { "header", 0, OPT_VALUE, "header", -1 },
169     { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
170     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
171     { "html-extension", 'E', OPT_BOOLEAN, "htmlextension", -1 },
172     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
173     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
174     { "http-passwd", 0, OPT_VALUE, "httppassword", -1 }, /* deprecated */
175     { "http-password", 0, OPT_VALUE, "httppassword", -1 },
176     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
177     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
178     { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
179     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
180 #ifdef ENABLE_IPV6
181     { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
182     { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
183 #endif
184     { "input-file", 'i', OPT_VALUE, "input", -1 },
185     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
186     { "level", 'l', OPT_VALUE, "reclevel", -1 },
187     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
188     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
189     { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
190     { "no", 'n', OPT__NO, NULL, required_argument },
191     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
192     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
193     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
194     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
195     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
196     { "parent", 0, OPT__PARENT, NULL, optional_argument },
197     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
198     { "password", 0, OPT_VALUE, "password", -1 },
199     { "post-data", 0, OPT_VALUE, "postdata", -1 },
200     { "post-file", 0, OPT_VALUE, "postfile", -1 },
201     { "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
202     { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
203     { IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
204     { IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
205     { "progress", 0, OPT_VALUE, "progress", -1 },
206     { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
207     { "proxy", 0, OPT_BOOLEAN, "useproxy", -1 },
208     { "proxy__compat", 'Y', OPT_VALUE, "useproxy", -1 }, /* back-compatible */
209     { "proxy-passwd", 0, OPT_VALUE, "proxypassword", -1 }, /* deprecated */
210     { "proxy-password", 0, OPT_VALUE, "proxypassword", -1 },
211     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
212     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
213     { "quota", 'Q', OPT_VALUE, "quota", -1 },
214     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
215     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
216     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
217     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
218     { "referer", 0, OPT_VALUE, "referer", -1 },
219     { "reject", 'R', OPT_VALUE, "reject", -1 },
220     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
221     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
222     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
223     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
224     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
225     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
226     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
227     { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
228     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
229     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
230     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
231     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
232     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
233     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
234     { "tries", 't', OPT_VALUE, "tries", -1 },
235     { "user", 0, OPT_VALUE, "user", -1 },
236     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
237     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
238     { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
239     { "version", 'V', OPT_FUNCALL, (void *) print_version, no_argument },
240     { "wait", 'w', OPT_VALUE, "wait", -1 },
241     { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
242   };
243
244 #undef WHEN_DEBUG
245 #undef IF_SSL
246
247 /* Return a string that contains S with "no-" prepended.  The string
248    is NUL-terminated and allocated off static storage at Wget
249    startup.  */
250
251 static char *
252 no_prefix (const char *s)
253 {
254   static char buffer[1024];
255   static char *p = buffer;
256
257   char *cp = p;
258   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
259   if (p + size >= buffer + sizeof (buffer))
260     abort ();
261
262   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
263   strcpy (cp + 3, s);
264   p += size;
265   return cp;
266 }
267
268 /* The arguments that that main passes to getopt_long. */
269 static struct option long_options[2 * countof (option_data) + 1];
270 static char short_options[128];
271
272 /* Mapping between short option chars and option_data indices. */
273 static unsigned char optmap[96];
274
275 /* Marker for `--no-FOO' values in long_options.  */
276 #define BOOLEAN_NEG_MARKER 1024
277
278 /* Initialize the long_options array used by getopt_long from the data
279    in option_data.  */
280
281 static void
282 init_switches (void)
283 {
284   char *p = short_options;
285   int i, o = 0;
286   for (i = 0; i < countof (option_data); i++)
287     {
288       struct cmdline_option *opt = &option_data[i];
289       struct option *longopt;
290
291       if (!opt->long_name)
292         /* The option is disabled. */
293         continue;
294
295       longopt = &long_options[o++];
296       longopt->name = opt->long_name;
297       longopt->val = i;
298       if (opt->short_name)
299         {
300           *p++ = opt->short_name;
301           optmap[opt->short_name - 32] = longopt - long_options;
302         }
303       switch (opt->type)
304         {
305         case OPT_VALUE:
306           longopt->has_arg = required_argument;
307           if (opt->short_name)
308             *p++ = ':';
309           break;
310         case OPT_BOOLEAN:
311           /* Specify an optional argument for long options, so that
312              --option=off works the same as --no-option, for
313              compatibility with pre-1.10 Wget.  However, don't specify
314              optional arguments short-option booleans because they
315              prevent combining of short options.  */
316           longopt->has_arg = optional_argument;
317           /* For Boolean options, add the "--no-FOO" variant, which is
318              identical to "--foo", except it has opposite meaning and
319              it doesn't allow an argument.  */
320           longopt = &long_options[o++];
321           longopt->name = no_prefix (opt->long_name);
322           longopt->has_arg = no_argument;
323           /* Mask the value so we'll be able to recognize that we're
324              dealing with the false value.  */
325           longopt->val = i | BOOLEAN_NEG_MARKER;
326           break;
327         default:
328           assert (opt->argtype != -1);
329           longopt->has_arg = opt->argtype;
330           if (opt->short_name)
331             {
332               if (longopt->has_arg == required_argument)
333                 *p++ = ':';
334               /* Don't handle optional_argument */
335             }
336         }
337     }
338   /* Terminate short_options. */
339   *p = '\0';
340   /* No need for xzero(long_options[o]) because its storage is static
341      and it will be zeroed by default.  */
342   assert (o <= countof (long_options));
343 }
344
345 /* Print the usage message.  */
346 static void
347 print_usage (void)
348 {
349   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
350 }
351
352 /* Print the help message, describing all the available options.  If
353    you add an option, be sure to update this list.  */
354 static void
355 print_help (void)
356 {
357   /* We split the help text this way to ease translation of individual
358      entries.  */
359   static const char *help[] = {
360     "\n",
361     N_("\
362 Mandatory arguments to long options are mandatory for short options too.\n\n"),
363     N_("\
364 Startup:\n"),
365     N_("\
366   -V,  --version           display the version of Wget and exit.\n"),
367     N_("\
368   -h,  --help              print this help.\n"),
369     N_("\
370   -b,  --background        go to background after startup.\n"),
371     N_("\
372   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
373     "\n",
374
375     N_("\
376 Logging and input file:\n"),
377     N_("\
378   -o,  --output-file=FILE    log messages to FILE.\n"),
379     N_("\
380   -a,  --append-output=FILE  append messages to FILE.\n"),
381 #ifdef ENABLE_DEBUG
382     N_("\
383   -d,  --debug               print lots of debugging information.\n"),
384 #endif
385     N_("\
386   -q,  --quiet               quiet (no output).\n"),
387     N_("\
388   -v,  --verbose             be verbose (this is the default).\n"),
389     N_("\
390   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
391     N_("\
392   -i,  --input-file=FILE     download URLs found in FILE.\n"),
393     N_("\
394   -F,  --force-html          treat input file as HTML.\n"),
395     N_("\
396   -B,  --base=URL            prepends URL to relative links in -F -i file.\n"),
397     "\n",
398
399     N_("\
400 Download:\n"),
401     N_("\
402   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
403     N_("\
404        --retry-connrefused       retry even if connection is refused.\n"),
405     N_("\
406   -O,  --output-document=FILE    write documents to FILE.\n"),
407     N_("\
408   -nc, --no-clobber              skip downloads that would download to\n\
409                                  existing files.\n"),
410     N_("\
411   -c,  --continue                resume getting a partially-downloaded file.\n"),
412     N_("\
413        --progress=TYPE           select progress gauge type.\n"),
414     N_("\
415   -N,  --timestamping            don't re-retrieve files unless newer than\n\
416                                  local.\n"),
417     N_("\
418   -S,  --server-response         print server response.\n"),
419     N_("\
420        --spider                  don't download anything.\n"),
421     N_("\
422   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
423     N_("\
424        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
425     N_("\
426        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
427     N_("\
428        --read-timeout=SECS       set the read timeout to SECS.\n"),
429     N_("\
430   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
431     N_("\
432        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
433     N_("\
434        --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
435     N_("\
436   -Y,  --proxy                   explicitly turn on proxy.\n"),
437     N_("\
438        --no-proxy                explicitly turn off proxy.\n"),
439     N_("\
440   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
441     N_("\
442        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
443     N_("\
444        --limit-rate=RATE         limit download rate to RATE.\n"),
445     N_("\
446        --no-dns-cache            disable caching DNS lookups.\n"),
447     N_("\
448        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
449 #ifdef ENABLE_IPV6
450     N_("\
451   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
452     N_("\
453   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
454     N_("\
455        --prefer-family=FAMILY    connect first to addresses of specified family,\n\
456                                  one of IPv6, IPv4, or none.\n"),
457 #endif
458     N_("\
459        --user=USER               set both ftp and http user to USER.\n"),
460     N_("\
461        --password=PASS           set both ftp and http password to PASS.\n"),
462     "\n",
463
464     N_("\
465 Directories:\n"),
466     N_("\
467   -nd, --no-directories           don't create directories.\n"),
468     N_("\
469   -x,  --force-directories        force creation of directories.\n"),
470     N_("\
471   -nH, --no-host-directories      don't create host directories.\n"),
472     N_("\
473        --protocol-directories     use protocol name in directories.\n"),
474     N_("\
475   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
476     N_("\
477        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
478     "\n",
479
480     N_("\
481 HTTP options:\n"),
482     N_("\
483        --http-user=USER        set http user to USER.\n"),
484     N_("\
485        --http-password=PASS    set http password to PASS.\n"),
486     N_("\
487        --no-cache              disallow server-cached data.\n"),
488     N_("\
489   -E,  --html-extension        save HTML documents with `.html' extension.\n"),
490     N_("\
491        --ignore-length         ignore `Content-Length' header field.\n"),
492     N_("\
493        --header=STRING         insert STRING among the headers.\n"),
494     N_("\
495        --proxy-user=USER       set USER as proxy username.\n"),
496     N_("\
497        --proxy-password=PASS   set PASS as proxy password.\n"),
498     N_("\
499        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
500     N_("\
501        --save-headers          save the HTTP headers to file.\n"),
502     N_("\
503   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
504     N_("\
505        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
506     N_("\
507        --no-cookies            don't use cookies.\n"),
508     N_("\
509        --load-cookies=FILE     load cookies from FILE before session.\n"),
510     N_("\
511        --save-cookies=FILE     save cookies to FILE after session.\n"),
512     N_("\
513        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
514     N_("\
515        --post-data=STRING      use the POST method; send STRING as the data.\n"),
516     N_("\
517        --post-file=FILE        use the POST method; send contents of FILE.\n"),
518     "\n",
519
520 #ifdef HAVE_SSL
521     N_("\
522 HTTPS (SSL/TLS) options:\n"),
523     N_("\
524        --secure-protocol=PR     choose secure protocol, one of auto, SSLv2,\n\
525                                 SSLv3, and TLSv1.\n"),
526     N_("\
527        --no-check-certificate   don't validate the server's certificate.\n"),
528     N_("\
529        --certificate=FILE       client certificate file.\n"),
530     N_("\
531        --certificate-type=TYPE  client certificate type, PEM or DER.\n"),
532     N_("\
533        --private-key=FILE       private key file.\n"),
534     N_("\
535        --private-key-type=TYPE  private key type, PEM or DER.\n"),
536     N_("\
537        --ca-certificate=FILE    file with the bundle of CA's.\n"),
538     N_("\
539        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
540     N_("\
541        --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
542     N_("\
543        --egd-file=FILE          file naming the EGD socket with random data.\n"),
544     "\n",
545 #endif /* HAVE_SSL */
546
547     N_("\
548 FTP options:\n"),
549     N_("\
550        --ftp-user=USER         set ftp user to USER.\n"),
551     N_("\
552        --ftp-password=PASS     set ftp password to PASS.\n"),
553     N_("\
554        --no-remove-listing     don't remove `.listing' files.\n"),
555     N_("\
556        --no-glob               turn off FTP file name globbing.\n"),
557     N_("\
558        --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
559     N_("\
560        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
561     N_("\
562        --preserve-permissions  preserve remote file permissions.\n"),
563     "\n",
564
565     N_("\
566 Recursive download:\n"),
567     N_("\
568   -r,  --recursive          specify recursive download.\n"),
569     N_("\
570   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
571     N_("\
572        --delete-after       delete files locally after downloading them.\n"),
573     N_("\
574   -k,  --convert-links      make links in downloaded HTML point to local files.\n"),
575     N_("\
576   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
577     N_("\
578   -m,  --mirror             shortcut for -N -r -l inf --no-remove-listing.\n"),
579     N_("\
580   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
581     N_("\
582        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
583     "\n",
584
585     N_("\
586 Recursive accept/reject:\n"),
587     N_("\
588   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
589     N_("\
590   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
591     N_("\
592   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
593     N_("\
594        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
595     N_("\
596        --follow-ftp                follow FTP links from HTML documents.\n"),
597     N_("\
598        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
599     N_("\
600        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
601     N_("\
602   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
603     N_("\
604   -L,  --relative                  follow relative links only.\n"),
605     N_("\
606   -I,  --include-directories=LIST  list of allowed directories.\n"),
607     N_("\
608   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
609     N_("\
610   -np, --no-parent                 don't ascend to the parent directory.\n"),
611     "\n",
612
613     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
614   };
615
616   int i;
617
618   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
619           version_string);
620   print_usage ();
621
622   for (i = 0; i < countof (help); i++)
623     fputs (_(help[i]), stdout);
624
625   exit (0);
626 }
627
628 /* Return a human-readable printed representation of INTERVAL,
629    measured in seconds.  */
630
631 static char *
632 secs_to_human_time (double interval)
633 {
634   static char buf[32];
635   int secs = (int) (interval + 0.5);
636   int hours, mins, days;
637
638   days = secs / 86400, secs %= 86400;
639   hours = secs / 3600, secs %= 3600;
640   mins = secs / 60, secs %= 60;
641
642   if (days)
643     sprintf (buf, "%dd %dh %dm %ds", days, hours, mins, secs);
644   else if (hours)
645     sprintf (buf, "%dh %dm %ds", hours, mins, secs);
646   else if (mins)
647     sprintf (buf, "%dm %ds", mins, secs);
648   else
649     sprintf (buf, "%ss", print_decimal (interval));
650
651   return buf;
652 }
653
654 static void
655 print_version (void)
656 {
657   printf ("GNU Wget %s\n\n", version_string);
658   fputs (_("\
659 Copyright (C) 2005 Free Software Foundation, Inc.\n"), stdout);
660   fputs (_("\
661 This program is distributed in the hope that it will be useful,\n\
662 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
663 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
664 GNU General Public License for more details.\n"), stdout);
665   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
666          stdout);
667   exit (0);
668 }
669 \f
670 int
671 main (int argc, char *const *argv)
672 {
673   char **url, **t;
674   int i, ret, longindex;
675   int nurl, status;
676   bool append_to_log = false;
677
678   i18n_initialize ();
679
680   /* Construct the name of the executable, without the directory part.  */
681   exec_name = strrchr (argv[0], PATH_SEPARATOR);
682   if (!exec_name)
683     exec_name = argv[0];
684   else
685     ++exec_name;
686
687 #ifdef WINDOWS
688   /* Drop extension (typically .EXE) from executable filename. */
689   windows_main (&argc, (char **) argv, (char **) &exec_name);
690 #endif
691
692   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
693   initialize ();
694
695   init_switches ();
696   longindex = -1;
697   while ((ret = getopt_long (argc, argv,
698                              short_options, long_options, &longindex)) != -1)
699     {
700       int val;
701       struct cmdline_option *opt;
702
703       /* If LONGINDEX is unchanged, it means RET is referring a short
704          option.  */
705       if (longindex == -1)
706         {
707           if (ret == '?')
708             {
709               print_usage ();
710               printf ("\n");
711               printf (_("Try `%s --help' for more options.\n"), exec_name);
712               exit (2);
713             }
714           /* Find the short option character in the mapping.  */
715           longindex = optmap[ret - 32];
716         }
717       val = long_options[longindex].val;
718
719       /* Use the retrieved value to locate the option in the
720          option_data array, and to see if we're dealing with the
721          negated "--no-FOO" variant of the boolean option "--foo".  */
722       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
723       switch (opt->type)
724         {
725         case OPT_VALUE:
726           setoptval (opt->data, optarg, opt->long_name);
727           break;
728         case OPT_BOOLEAN:
729           if (optarg)
730             /* The user has specified a value -- use it. */
731             setoptval (opt->data, optarg, opt->long_name);
732           else
733             {
734               /* NEG is true for `--no-FOO' style boolean options. */
735               bool neg = !!(val & BOOLEAN_NEG_MARKER);
736               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
737             }
738           break;
739         case OPT_FUNCALL:
740           {
741             void (*func) (void) = (void (*) (void)) opt->data;
742             func ();
743           }
744           break;
745         case OPT__APPEND_OUTPUT:
746           setoptval ("logfile", optarg, opt->long_name);
747           append_to_log = true;
748           break;
749         case OPT__EXECUTE:
750           run_command (optarg);
751           break;
752         case OPT__NO:
753           {
754             /* We support real --no-FOO flags now, but keep these
755                short options for convenience and backward
756                compatibility.  */
757             char *p;
758             for (p = optarg; *p; p++)
759               switch (*p)
760                 {
761                 case 'v':
762                   setoptval ("verbose", "0", opt->long_name);
763                   break;
764                 case 'H':
765                   setoptval ("addhostdir", "0", opt->long_name);
766                   break;
767                 case 'd':
768                   setoptval ("dirstruct", "0", opt->long_name);
769                   break;
770                 case 'c':
771                   setoptval ("noclobber", "1", opt->long_name);
772                   break;
773                 case 'p':
774                   setoptval ("noparent", "1", opt->long_name);
775                   break;
776                 default:
777                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
778                   print_usage ();
779                   printf ("\n");
780                   printf (_("Try `%s --help' for more options.\n"), exec_name);
781                   exit (1);
782                 }
783             break;
784           }
785         case OPT__PARENT:
786         case OPT__CLOBBER:
787           {
788             /* The wgetrc commands are named noparent and noclobber,
789                so we must revert the meaning of the cmdline options
790                before passing the value to setoptval.  */
791             bool flag = true;
792             if (optarg)
793               flag = (*optarg == '1' || TOLOWER (*optarg) == 'y'
794                       || (TOLOWER (optarg[0]) == 'o'
795                           && TOLOWER (optarg[1]) == 'n'));
796             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
797                        flag ? "0" : "1", opt->long_name);
798             break;
799           }
800         case OPT__DONT_REMOVE_LISTING:
801           setoptval ("removelisting", "0", opt->long_name);
802           break;
803         }
804
805       longindex = -1;
806     }
807
808   /* All user options have now been processed, so it's now safe to do
809      interoption dependency checks. */
810
811   if (opt.reclevel == 0)
812     opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary on this */
813
814   if (opt.page_requisites && !opt.recursive)
815     {
816       /* Don't set opt.recursive here because it would confuse the FTP
817          code.  Instead, call retrieve_tree below when either
818          page_requisites or recursive is requested.  */
819       opt.reclevel = 0;
820       if (!opt.no_dirstruct)
821         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
822     }
823
824   if (opt.verbose == -1)
825     opt.verbose = !opt.quiet;
826
827   /* Sanity checks.  */
828   if (opt.verbose && opt.quiet)
829     {
830       printf (_("Can't be verbose and quiet at the same time.\n"));
831       print_usage ();
832       exit (1);
833     }
834   if (opt.timestamping && opt.noclobber)
835     {
836       printf (_("\
837 Can't timestamp and not clobber old files at the same time.\n"));
838       print_usage ();
839       exit (1);
840     }
841 #ifdef ENABLE_IPV6
842   if (opt.ipv4_only && opt.ipv6_only)
843     {
844       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
845       print_usage ();
846       exit (1);
847     }
848 #endif
849
850   nurl = argc - optind;
851   if (!nurl && !opt.input_filename)
852     {
853       /* No URL specified.  */
854       printf (_("%s: missing URL\n"), exec_name);
855       print_usage ();
856       printf ("\n");
857       /* #### Something nicer should be printed here -- similar to the
858          pre-1.5 `--help' page.  */
859       printf (_("Try `%s --help' for more options.\n"), exec_name);
860       exit (1);
861     }
862
863   if (opt.background)
864     fork_to_background ();
865
866   /* Initialize progress.  Have to do this after the options are
867      processed so we know where the log file is.  */
868   if (opt.verbose)
869     set_progress_implementation (opt.progress_type);
870
871   /* Fill in the arguments.  */
872   url = alloca_array (char *, nurl + 1);
873   for (i = 0; i < nurl; i++, optind++)
874     {
875       char *rewritten = rewrite_shorthand_url (argv[optind]);
876       if (rewritten)
877         url[i] = rewritten;
878       else
879         url[i] = xstrdup (argv[optind]);
880     }
881   url[i] = NULL;
882
883   /* Initialize logging.  */
884   log_init (opt.lfilename, append_to_log);
885
886   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
887            OS_TYPE));
888
889   /* Open the output filename if necessary.  */
890   if (opt.output_document)
891     {
892       if (HYPHENP (opt.output_document))
893         output_stream = stdout;
894       else
895         {
896           struct_fstat st;
897           output_stream = fopen (opt.output_document,
898                                  opt.always_rest ? "ab" : "wb");
899           if (output_stream == NULL)
900             {
901               perror (opt.output_document);
902               exit (1);
903             }
904           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
905             output_stream_regular = true;
906         }
907     }
908
909 #ifdef WINDOWS
910   ws_startup ();
911 #endif
912
913 #ifdef SIGHUP
914   /* Setup the signal handler to redirect output when hangup is
915      received.  */
916   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
917     signal(SIGHUP, redirect_output_signal);
918 #endif
919   /* ...and do the same for SIGUSR1.  */
920 #ifdef SIGUSR1
921   signal (SIGUSR1, redirect_output_signal);
922 #endif
923 #ifdef SIGPIPE
924   /* Writing to a closed socket normally signals SIGPIPE, and the
925      process exits.  What we want is to ignore SIGPIPE and just check
926      for the return value of write().  */
927   signal (SIGPIPE, SIG_IGN);
928 #endif
929 #ifdef SIGWINCH
930   signal (SIGWINCH, progress_handle_sigwinch);
931 #endif
932
933   status = RETROK;              /* initialize it, just-in-case */
934   /* Retrieve the URLs from argument list.  */
935   for (t = url; *t; t++)
936     {
937       char *filename = NULL, *redirected_URL = NULL;
938       int dt;
939
940       if ((opt.recursive || opt.page_requisites)
941           && url_scheme (*t) != SCHEME_FTP)
942         status = retrieve_tree (*t);
943       else
944         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
945
946       if (opt.delete_after && file_exists_p(filename))
947         {
948           DEBUGP (("Removing file due to --delete-after in main():\n"));
949           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
950           if (unlink (filename))
951             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
952         }
953
954       xfree_null (redirected_URL);
955       xfree_null (filename);
956     }
957
958   /* And then from the input file, if any.  */
959   if (opt.input_filename)
960     {
961       int count;
962       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
963       if (!count)
964         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
965                    opt.input_filename);
966     }
967   /* Print the downloaded sum.  */
968   if (opt.recursive || opt.page_requisites
969       || nurl > 1
970       || (opt.input_filename && total_downloaded_bytes != 0))
971     {
972       logprintf (LOG_NOTQUIET,
973                  _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
974                  time_str (NULL),
975                  opt.numurls,
976                  human_readable (total_downloaded_bytes),
977                  secs_to_human_time (total_download_time / 1000),
978                  retr_rate (total_downloaded_bytes, total_download_time));
979       /* Print quota warning, if exceeded.  */
980       if (opt.quota && total_downloaded_bytes > opt.quota)
981         logprintf (LOG_NOTQUIET,
982                    _("Download quota of %s EXCEEDED!\n"),
983                    human_readable (opt.quota));
984     }
985
986   if (opt.cookies_output)
987     save_cookies ();
988
989   if (opt.convert_links && !opt.delete_after)
990     convert_all_links ();
991
992   log_close ();
993   for (i = 0; i < nurl; i++)
994     xfree (url[i]);
995   cleanup ();
996
997 #ifdef DEBUG_MALLOC
998   print_malloc_debug_stats ();
999 #endif
1000   if (status == RETROK)
1001     return 0;
1002   else
1003     return 1;
1004 }
1005 \f
1006 #if defined(SIGHUP) || defined(SIGUSR1)
1007
1008 /* So the signal_name check doesn't blow when only one is available. */
1009 #ifndef SIGHUP
1010 # define SIGHUP -1
1011 #endif
1012 #ifndef SIGUSR1
1013 # define SIGUSR1 -1
1014 #endif
1015
1016 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1017    will proceed operation as usual, trying to write into a log file.
1018    If that is impossible, the output will be turned off.  */
1019
1020 static void
1021 redirect_output_signal (int sig)
1022 {
1023   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1024                              (sig == SIGUSR1 ? "SIGUSR1" :
1025                               "WTF?!"));
1026   log_request_redirect_output (signal_name);
1027   progress_schedule_redirect ();
1028   signal (sig, redirect_output_signal);
1029 }
1030 #endif