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