]> sjero.net Git - wget/blob - src/main.c
Notes to translators re (C) and diacritics in names.
[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 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a
24 modified version of that library), containing parts covered by the
25 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
26 grants you additional permission to convey the resulting work.
27 Corresponding Source for a non-source form of such a combination
28 shall include the source code for the parts of OpenSSL used as well
29 as that of the covered work.  */
30
31 #include "wget.h"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif /* HAVE_UNISTD_H */
38 #include <string.h>
39 #include <signal.h>
40 #ifdef ENABLE_NLS
41 # include <locale.h>
42 #endif
43 #include <assert.h>
44 #include <errno.h>
45 #include <time.h>
46
47 #include "utils.h"
48 #include "init.h"
49 #include "retr.h"
50 #include "recur.h"
51 #include "host.h"
52 #include "url.h"
53 #include "progress.h"           /* for progress_handle_sigwinch */
54 #include "convert.h"
55 #include "spider.h"
56 #include "http.h"               /* for save_cookies */
57
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   /* ENABLE_NLS implies existence of functions invoked here.  */
83 #ifdef ENABLE_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 /* ENABLE_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 #ifdef MSDOS
248     { "wdebug", 0, OPT_BOOLEAN, "wdebug", -1 },
249 #endif
250   };
251
252 #undef WHEN_DEBUG
253 #undef IF_SSL
254
255 /* Return a string that contains S with "no-" prepended.  The string
256    is NUL-terminated and allocated off static storage at Wget
257    startup.  */
258
259 static char *
260 no_prefix (const char *s)
261 {
262   static char buffer[1024];
263   static char *p = buffer;
264
265   char *cp = p;
266   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
267   if (p + size >= buffer + sizeof (buffer))
268     abort ();
269
270   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
271   strcpy (cp + 3, s);
272   p += size;
273   return cp;
274 }
275
276 /* The arguments that that main passes to getopt_long. */
277 static struct option long_options[2 * countof (option_data) + 1];
278 static char short_options[128];
279
280 /* Mapping between short option chars and option_data indices. */
281 static unsigned char optmap[96];
282
283 /* Marker for `--no-FOO' values in long_options.  */
284 #define BOOLEAN_NEG_MARKER 1024
285
286 /* Initialize the long_options array used by getopt_long from the data
287    in option_data.  */
288
289 static void
290 init_switches (void)
291 {
292   char *p = short_options;
293   int i, o = 0;
294   for (i = 0; i < countof (option_data); i++)
295     {
296       struct cmdline_option *opt = &option_data[i];
297       struct option *longopt;
298
299       if (!opt->long_name)
300         /* The option is disabled. */
301         continue;
302
303       longopt = &long_options[o++];
304       longopt->name = opt->long_name;
305       longopt->val = i;
306       if (opt->short_name)
307         {
308           *p++ = opt->short_name;
309           optmap[opt->short_name - 32] = longopt - long_options;
310         }
311       switch (opt->type)
312         {
313         case OPT_VALUE:
314           longopt->has_arg = required_argument;
315           if (opt->short_name)
316             *p++ = ':';
317           break;
318         case OPT_BOOLEAN:
319           /* Specify an optional argument for long options, so that
320              --option=off works the same as --no-option, for
321              compatibility with pre-1.10 Wget.  However, don't specify
322              optional arguments short-option booleans because they
323              prevent combining of short options.  */
324           longopt->has_arg = optional_argument;
325           /* For Boolean options, add the "--no-FOO" variant, which is
326              identical to "--foo", except it has opposite meaning and
327              it doesn't allow an argument.  */
328           longopt = &long_options[o++];
329           longopt->name = no_prefix (opt->long_name);
330           longopt->has_arg = no_argument;
331           /* Mask the value so we'll be able to recognize that we're
332              dealing with the false value.  */
333           longopt->val = i | BOOLEAN_NEG_MARKER;
334           break;
335         default:
336           assert (opt->argtype != -1);
337           longopt->has_arg = opt->argtype;
338           if (opt->short_name)
339             {
340               if (longopt->has_arg == required_argument)
341                 *p++ = ':';
342               /* Don't handle optional_argument */
343             }
344         }
345     }
346   /* Terminate short_options. */
347   *p = '\0';
348   /* No need for xzero(long_options[o]) because its storage is static
349      and it will be zeroed by default.  */
350   assert (o <= countof (long_options));
351 }
352
353 /* Print the usage message.  */
354 static void
355 print_usage (void)
356 {
357   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
358 }
359
360 /* Print the help message, describing all the available options.  If
361    you add an option, be sure to update this list.  */
362 static void
363 print_help (void)
364 {
365   /* We split the help text this way to ease translation of individual
366      entries.  */
367   static const char *help[] = {
368     "\n",
369     N_("\
370 Mandatory arguments to long options are mandatory for short options too.\n\n"),
371     N_("\
372 Startup:\n"),
373     N_("\
374   -V,  --version           display the version of Wget and exit.\n"),
375     N_("\
376   -h,  --help              print this help.\n"),
377     N_("\
378   -b,  --background        go to background after startup.\n"),
379     N_("\
380   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
381     "\n",
382
383     N_("\
384 Logging and input file:\n"),
385     N_("\
386   -o,  --output-file=FILE    log messages to FILE.\n"),
387     N_("\
388   -a,  --append-output=FILE  append messages to FILE.\n"),
389 #ifdef ENABLE_DEBUG
390     N_("\
391   -d,  --debug               print lots of debugging information.\n"),
392 #endif
393 #ifdef MSDOS
394     N_("\
395        --wdebug              print Watt-32 debug output.\n"),
396 #endif
397     N_("\
398   -q,  --quiet               quiet (no output).\n"),
399     N_("\
400   -v,  --verbose             be verbose (this is the default).\n"),
401     N_("\
402   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
403     N_("\
404   -i,  --input-file=FILE     download URLs found in FILE.\n"),
405     N_("\
406   -F,  --force-html          treat input file as HTML.\n"),
407     N_("\
408   -B,  --base=URL            prepends URL to relative links in -F -i file.\n"),
409     "\n",
410
411     N_("\
412 Download:\n"),
413     N_("\
414   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
415     N_("\
416        --retry-connrefused       retry even if connection is refused.\n"),
417     N_("\
418   -O,  --output-document=FILE    write documents to FILE.\n"),
419     N_("\
420   -nc, --no-clobber              skip downloads that would download to\n\
421                                  existing files.\n"),
422     N_("\
423   -c,  --continue                resume getting a partially-downloaded file.\n"),
424     N_("\
425        --progress=TYPE           select progress gauge type.\n"),
426     N_("\
427   -N,  --timestamping            don't re-retrieve files unless newer than\n\
428                                  local.\n"),
429     N_("\
430   -S,  --server-response         print server response.\n"),
431     N_("\
432        --spider                  don't download anything.\n"),
433     N_("\
434   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
435     N_("\
436        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
437     N_("\
438        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
439     N_("\
440        --read-timeout=SECS       set the read timeout to SECS.\n"),
441     N_("\
442   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
443     N_("\
444        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
445     N_("\
446        --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
447     N_("\
448        --no-proxy                explicitly turn off proxy.\n"),
449     N_("\
450   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
451     N_("\
452        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
453     N_("\
454        --limit-rate=RATE         limit download rate to RATE.\n"),
455     N_("\
456        --no-dns-cache            disable caching DNS lookups.\n"),
457     N_("\
458        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
459     N_("\
460        --ignore-case             ignore case when matching files/directories.\n"),
461 #ifdef ENABLE_IPV6
462     N_("\
463   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
464     N_("\
465   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
466     N_("\
467        --prefer-family=FAMILY    connect first to addresses of specified family,\n\
468                                  one of IPv6, IPv4, or none.\n"),
469 #endif
470     N_("\
471        --user=USER               set both ftp and http user to USER.\n"),
472     N_("\
473        --password=PASS           set both ftp and http password to PASS.\n"),
474     "\n",
475
476     N_("\
477 Directories:\n"),
478     N_("\
479   -nd, --no-directories           don't create directories.\n"),
480     N_("\
481   -x,  --force-directories        force creation of directories.\n"),
482     N_("\
483   -nH, --no-host-directories      don't create host directories.\n"),
484     N_("\
485        --protocol-directories     use protocol name in directories.\n"),
486     N_("\
487   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
488     N_("\
489        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
490     "\n",
491
492     N_("\
493 HTTP options:\n"),
494     N_("\
495        --http-user=USER        set http user to USER.\n"),
496     N_("\
497        --http-password=PASS    set http password to PASS.\n"),
498     N_("\
499        --no-cache              disallow server-cached data.\n"),
500     N_("\
501   -E,  --html-extension        save HTML documents with `.html' extension.\n"),
502     N_("\
503        --ignore-length         ignore `Content-Length' header field.\n"),
504     N_("\
505        --header=STRING         insert STRING among the headers.\n"),
506     N_("\
507        --max-redirect          maximum redirections allowed per page.\n"),
508     N_("\
509        --proxy-user=USER       set USER as proxy username.\n"),
510     N_("\
511        --proxy-password=PASS   set PASS as proxy password.\n"),
512     N_("\
513        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
514     N_("\
515        --save-headers          save the HTTP headers to file.\n"),
516     N_("\
517   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
518     N_("\
519        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
520     N_("\
521        --no-cookies            don't use cookies.\n"),
522     N_("\
523        --load-cookies=FILE     load cookies from FILE before session.\n"),
524     N_("\
525        --save-cookies=FILE     save cookies to FILE after session.\n"),
526     N_("\
527        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
528     N_("\
529        --post-data=STRING      use the POST method; send STRING as the data.\n"),
530     N_("\
531        --post-file=FILE        use the POST method; send contents of FILE.\n"),
532     N_("\
533        --content-disposition   honor the Content-Disposition header when\n\
534                                choosing local file names (EXPERIMENTAL).\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   /* TRANSLATORS: When available, an actual copyright character
676      (cirle-c) should be used in preference to "(C)". */
677   fputs (_("\
678 Copyright (C) 2007 Free Software Foundation, Inc.\n"), stdout);
679   fputs (_("\
680 License GPLv3+: GNU GPL version 3 or later\n\
681 <http://www.gnu.org/licenses/gpl.html>.\n\
682 This is free software: you are free to change and redistribute it.\n\
683 There is NO WARRANTY, to the extent permitted by law.\n"), stdout);
684   /* TRANSLATORS: When available, please use the proper diacritics for
685      names such as this one. See en_US.po for reference. */
686   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
687          stdout);
688   fputs (_("Currently maintained by Micah Cowan <micah@cowan.name>.\n"),
689          stdout);
690   exit (0);
691 }
692 \f
693
694 int
695 main (int argc, char **argv)
696 {
697   char **url, **t;
698   int i, ret, longindex;
699   int nurl, status;
700   bool append_to_log = false;
701
702   i18n_initialize ();
703
704   /* Construct the name of the executable, without the directory part.  */
705   exec_name = strrchr (argv[0], PATH_SEPARATOR);
706   if (!exec_name)
707     exec_name = argv[0];
708   else
709     ++exec_name;
710
711 #ifdef WINDOWS
712   /* Drop extension (typically .EXE) from executable filename. */
713   windows_main ((char **) &exec_name);
714 #endif
715
716   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
717   initialize ();
718
719   init_switches ();
720   longindex = -1;
721   while ((ret = getopt_long (argc, argv,
722                              short_options, long_options, &longindex)) != -1)
723     {
724       int val;
725       struct cmdline_option *opt;
726
727       /* If LONGINDEX is unchanged, it means RET is referring a short
728          option.  */
729       if (longindex == -1)
730         {
731           if (ret == '?')
732             {
733               print_usage ();
734               printf ("\n");
735               printf (_("Try `%s --help' for more options.\n"), exec_name);
736               exit (2);
737             }
738           /* Find the short option character in the mapping.  */
739           longindex = optmap[ret - 32];
740         }
741       val = long_options[longindex].val;
742
743       /* Use the retrieved value to locate the option in the
744          option_data array, and to see if we're dealing with the
745          negated "--no-FOO" variant of the boolean option "--foo".  */
746       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
747       switch (opt->type)
748         {
749         case OPT_VALUE:
750           setoptval (opt->data, optarg, opt->long_name);
751           break;
752         case OPT_BOOLEAN:
753           if (optarg)
754             /* The user has specified a value -- use it. */
755             setoptval (opt->data, optarg, opt->long_name);
756           else
757             {
758               /* NEG is true for `--no-FOO' style boolean options. */
759               bool neg = !!(val & BOOLEAN_NEG_MARKER);
760               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
761             }
762           break;
763         case OPT_FUNCALL:
764           {
765             void (*func) (void) = (void (*) (void)) opt->data;
766             func ();
767           }
768           break;
769         case OPT__APPEND_OUTPUT:
770           setoptval ("logfile", optarg, opt->long_name);
771           append_to_log = true;
772           break;
773         case OPT__EXECUTE:
774           run_command (optarg);
775           break;
776         case OPT__NO:
777           {
778             /* We support real --no-FOO flags now, but keep these
779                short options for convenience and backward
780                compatibility.  */
781             char *p;
782             for (p = optarg; *p; p++)
783               switch (*p)
784                 {
785                 case 'v':
786                   setoptval ("verbose", "0", opt->long_name);
787                   break;
788                 case 'H':
789                   setoptval ("addhostdir", "0", opt->long_name);
790                   break;
791                 case 'd':
792                   setoptval ("dirstruct", "0", opt->long_name);
793                   break;
794                 case 'c':
795                   setoptval ("noclobber", "1", opt->long_name);
796                   break;
797                 case 'p':
798                   setoptval ("noparent", "1", opt->long_name);
799                   break;
800                 default:
801                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
802                   print_usage ();
803                   printf ("\n");
804                   printf (_("Try `%s --help' for more options.\n"), exec_name);
805                   exit (1);
806                 }
807             break;
808           }
809         case OPT__PARENT:
810         case OPT__CLOBBER:
811           {
812             /* The wgetrc commands are named noparent and noclobber,
813                so we must revert the meaning of the cmdline options
814                before passing the value to setoptval.  */
815             bool flag = true;
816             if (optarg)
817               flag = (*optarg == '1' || c_tolower (*optarg) == 'y'
818                       || (c_tolower (optarg[0]) == 'o'
819                           && c_tolower (optarg[1]) == 'n'));
820             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
821                        flag ? "0" : "1", opt->long_name);
822             break;
823           }
824         case OPT__DONT_REMOVE_LISTING:
825           setoptval ("removelisting", "0", opt->long_name);
826           break;
827         }
828
829       longindex = -1;
830     }
831
832   nurl = argc - optind;
833
834   /* All user options have now been processed, so it's now safe to do
835      interoption dependency checks. */
836
837   if (opt.reclevel == 0)
838       opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary */
839
840   if (opt.spider || opt.delete_after)
841       opt.no_dirstruct = true;
842
843   if (opt.page_requisites && !opt.recursive)
844     {
845       /* Don't set opt.recursive here because it would confuse the FTP
846          code.  Instead, call retrieve_tree below when either
847          page_requisites or recursive is requested.  */
848       opt.reclevel = 0;
849       if (!opt.no_dirstruct)
850         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
851     }
852
853   if (opt.verbose == -1)
854     opt.verbose = !opt.quiet;
855
856   /* Sanity checks.  */
857   if (opt.verbose && opt.quiet)
858     {
859       printf (_("Can't be verbose and quiet at the same time.\n"));
860       print_usage ();
861       exit (1);
862     }
863   if (opt.timestamping && opt.noclobber)
864     {
865       printf (_("\
866 Can't timestamp and not clobber old files at the same time.\n"));
867       print_usage ();
868       exit (1);
869     }
870 #ifdef ENABLE_IPV6
871   if (opt.ipv4_only && opt.ipv6_only)
872     {
873       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
874       print_usage ();
875       exit (1);
876     }
877 #endif
878   if (opt.output_document
879       && (opt.page_requisites
880           || opt.recursive
881           || opt.timestamping))
882     {
883           printf (_("Cannot specify -r, -p or -N if -O is given.\n"));
884           print_usage ();
885           exit (1);
886     }
887   if (opt.output_document
888       && opt.convert_links 
889       && nurl > 1)
890     {
891           printf (_("Cannot specify both -k and -O if multiple URLs are given.\n"));
892           print_usage ();
893           exit (1);
894     }
895
896   if (!nurl && !opt.input_filename)
897     {
898       /* No URL specified.  */
899       printf (_("%s: missing URL\n"), exec_name);
900       print_usage ();
901       printf ("\n");
902       /* #### Something nicer should be printed here -- similar to the
903          pre-1.5 `--help' page.  */
904       printf (_("Try `%s --help' for more options.\n"), exec_name);
905       exit (1);
906     }
907
908 #ifdef MSDOS
909   if (opt.wdebug)
910      dbug_init();
911   sock_init();
912 #else
913   if (opt.background)
914     fork_to_background ();
915 #endif
916
917   /* Initialize progress.  Have to do this after the options are
918      processed so we know where the log file is.  */
919   if (opt.verbose)
920     set_progress_implementation (opt.progress_type);
921
922   /* Fill in the arguments.  */
923   url = alloca_array (char *, nurl + 1);
924   for (i = 0; i < nurl; i++, optind++)
925     {
926       char *rewritten = rewrite_shorthand_url (argv[optind]);
927       if (rewritten)
928         url[i] = rewritten;
929       else
930         url[i] = xstrdup (argv[optind]);
931     }
932   url[i] = NULL;
933
934   /* Initialize logging.  */
935   log_init (opt.lfilename, append_to_log);
936
937   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
938            OS_TYPE));
939
940   /* Open the output filename if necessary.  */
941   if (opt.output_document)
942     {
943       if (HYPHENP (opt.output_document))
944         output_stream = stdout;
945       else
946         {
947           struct_fstat st;
948           output_stream = fopen (opt.output_document,
949                                  opt.always_rest ? "ab" : "wb");
950           if (output_stream == NULL)
951             {
952               perror (opt.output_document);
953               exit (1);
954             }
955           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
956             output_stream_regular = true;
957         }
958     }
959
960 #ifdef WINDOWS
961   ws_startup ();
962 #endif
963
964 #ifdef SIGHUP
965   /* Setup the signal handler to redirect output when hangup is
966      received.  */
967   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
968     signal(SIGHUP, redirect_output_signal);
969 #endif
970   /* ...and do the same for SIGUSR1.  */
971 #ifdef SIGUSR1
972   signal (SIGUSR1, redirect_output_signal);
973 #endif
974 #ifdef SIGPIPE
975   /* Writing to a closed socket normally signals SIGPIPE, and the
976      process exits.  What we want is to ignore SIGPIPE and just check
977      for the return value of write().  */
978   signal (SIGPIPE, SIG_IGN);
979 #endif
980 #ifdef SIGWINCH
981   signal (SIGWINCH, progress_handle_sigwinch);
982 #endif
983
984   status = RETROK;              /* initialize it, just-in-case */
985   /* Retrieve the URLs from argument list.  */
986   for (t = url; *t; t++)
987     {
988       char *filename = NULL, *redirected_URL = NULL;
989       int dt;
990
991       if ((opt.recursive || opt.page_requisites)
992           && (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (*t)))
993         {
994           int old_follow_ftp = opt.follow_ftp;
995
996           /* Turn opt.follow_ftp on in case of recursive FTP retrieval */
997           if (url_scheme (*t) == SCHEME_FTP) 
998             opt.follow_ftp = 1;
999           
1000           status = retrieve_tree (*t);
1001
1002           opt.follow_ftp = old_follow_ftp;
1003         }
1004       else
1005         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt, opt.recursive);
1006
1007       if (opt.delete_after && file_exists_p(filename))
1008         {
1009           DEBUGP (("Removing file due to --delete-after in main():\n"));
1010           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
1011           if (unlink (filename))
1012             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1013         }
1014
1015       xfree_null (redirected_URL);
1016       xfree_null (filename);
1017     }
1018
1019   /* And then from the input file, if any.  */
1020   if (opt.input_filename)
1021     {
1022       int count;
1023       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
1024       if (!count)
1025         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
1026                    opt.input_filename);
1027     }
1028
1029   /* Print broken links. */
1030   if (opt.recursive && opt.spider)
1031     {
1032       print_broken_links();
1033     }
1034   
1035   /* Print the downloaded sum.  */
1036   if ((opt.recursive || opt.page_requisites
1037        || nurl > 1
1038        || (opt.input_filename && total_downloaded_bytes != 0))
1039       &&
1040       total_downloaded_bytes != 0)
1041     {
1042       logprintf (LOG_NOTQUIET,
1043                  _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
1044                  datetime_str (time (NULL)),
1045                  opt.numurls,
1046                  human_readable (total_downloaded_bytes),
1047                  secs_to_human_time (total_download_time),
1048                  retr_rate (total_downloaded_bytes, total_download_time));
1049       /* Print quota warning, if exceeded.  */
1050       if (opt.quota && total_downloaded_bytes > opt.quota)
1051         logprintf (LOG_NOTQUIET,
1052                    _("Download quota of %s EXCEEDED!\n"),
1053                    human_readable (opt.quota));
1054     }
1055
1056   if (opt.cookies_output)
1057     save_cookies ();
1058
1059   if (opt.convert_links && !opt.delete_after)
1060     convert_all_links ();
1061
1062   log_close ();
1063   for (i = 0; i < nurl; i++)
1064     xfree (url[i]);
1065   cleanup ();
1066
1067 #ifdef DEBUG_MALLOC
1068   print_malloc_debug_stats ();
1069 #endif
1070   if (status == RETROK)
1071     return 0;
1072   else
1073     return 1;
1074 }
1075 #endif /* TESTING */
1076 \f
1077 #if defined(SIGHUP) || defined(SIGUSR1)
1078
1079 /* So the signal_name check doesn't blow when only one is available. */
1080 #ifndef SIGHUP
1081 # define SIGHUP -1
1082 #endif
1083 #ifndef SIGUSR1
1084 # define SIGUSR1 -1
1085 #endif
1086
1087 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1088    will proceed operation as usual, trying to write into a log file.
1089    If that is impossible, the output will be turned off.  */
1090
1091 static void
1092 redirect_output_signal (int sig)
1093 {
1094   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1095                              (sig == SIGUSR1 ? "SIGUSR1" :
1096                               "WTF?!"));
1097   log_request_redirect_output (signal_name);
1098   progress_schedule_redirect ();
1099   signal (sig, redirect_output_signal);
1100 }
1101 #endif
1102
1103 /*
1104  * vim: et ts=2 sw=2
1105  */