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