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