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