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