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