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