]> sjero.net Git - wget/blob - src/main.c
Silent compiler warning.
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3    2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
4    Inc.
5
6 This file is part of GNU Wget.
7
8 GNU Wget is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 GNU Wget is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
20
21 Additional permission under GNU GPL version 3 section 7
22
23 If you modify this program, or any covered work, by linking or
24 combining it with the OpenSSL project's OpenSSL library (or a
25 modified version of that library), containing parts covered by the
26 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
27 grants you additional permission to convey the resulting work.
28 Corresponding Source for a non-source form of such a combination
29 shall include the source code for the parts of OpenSSL used as well
30 as that of the covered work.  */
31
32 #include "wget.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <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 "exits.h"
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 #include "ptimer.h"
58
59 #include <getopt.h>
60 #include <getpass.h>
61 #include <quote.h>
62
63 #ifdef __VMS
64 #include "vms.h"
65 #endif /* __VMS */
66
67 #ifndef PATH_SEPARATOR
68 # define PATH_SEPARATOR '/'
69 #endif
70
71 #ifndef ENABLE_IRI
72 struct iri dummy_iri;
73 #endif
74
75 struct options opt;
76
77 /* defined in version.c */
78 extern char *version_string;
79 extern char *compilation_string;
80 extern char *system_getrc;
81 extern char *link_string;
82 /* defined in build_info.c */
83 extern const char *compiled_features[];
84 /* Used for --version output in print_version */
85 #define MAX_CHARS_PER_LINE      72
86 #define TABULATION              4
87
88 #if defined(SIGHUP) || defined(SIGUSR1)
89 static void redirect_output_signal (int);
90 #endif
91
92 const char *exec_name;
93
94 /* Number of successfully downloaded URLs */
95 int numurls = 0;
96 \f
97 #ifndef TESTING
98 /* Initialize I18N/L10N.  That amounts to invoking setlocale, and
99    setting up gettext's message catalog using bindtextdomain and
100    textdomain.  Does nothing if NLS is disabled or missing.  */
101
102 static void
103 i18n_initialize (void)
104 {
105   /* ENABLE_NLS implies existence of functions invoked here.  */
106 #ifdef ENABLE_NLS
107   /* Set the current locale.  */
108   setlocale (LC_ALL, "");
109   /* Set the text message domain.  */
110   bindtextdomain ("wget", LOCALEDIR);
111   textdomain ("wget");
112 #endif /* ENABLE_NLS */
113 }
114 \f
115 /* Definition of command-line options. */
116
117 static void print_help (void);
118 static void print_version (void);
119
120 #ifdef HAVE_SSL
121 # define IF_SSL(x) x
122 #else
123 # define IF_SSL(x) NULL
124 #endif
125
126 #ifdef ENABLE_DEBUG
127 # define WHEN_DEBUG(x) x
128 #else
129 # define WHEN_DEBUG(x) NULL
130 #endif
131
132 struct cmdline_option {
133   const char *long_name;
134   char short_name;
135   enum {
136     OPT_VALUE,
137     OPT_BOOLEAN,
138     OPT_FUNCALL,
139     /* Non-standard options that have to be handled specially in
140        main().  */
141     OPT__APPEND_OUTPUT,
142     OPT__CLOBBER,
143     OPT__DONT_REMOVE_LISTING,
144     OPT__EXECUTE,
145     OPT__NO,
146     OPT__PARENT
147   } type;
148   const void *data;             /* for standard options */
149   int argtype;                  /* for non-standard options */
150 };
151
152 static struct cmdline_option option_data[] =
153   {
154     { "accept", 'A', OPT_VALUE, "accept", -1 },
155     { "adjust-extension", 'E', OPT_BOOLEAN, "adjustextension", -1 },
156     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
157     { "ask-password", 0, OPT_BOOLEAN, "askpassword", -1 },
158     { "auth-no-challenge", 0, OPT_BOOLEAN, "authnochallenge", -1 },
159     { "background", 'b', OPT_BOOLEAN, "background", -1 },
160     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
161     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
162     { "base", 'B', OPT_VALUE, "base", -1 },
163     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
164     { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
165     { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
166     { "cache", 0, OPT_BOOLEAN, "cache", -1 },
167     { IF_SSL ("certificate"), 0, OPT_VALUE, "certificate", -1 },
168     { IF_SSL ("certificate-type"), 0, OPT_VALUE, "certificatetype", -1 },
169     { IF_SSL ("check-certificate"), 0, OPT_BOOLEAN, "checkcertificate", -1 },
170     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
171     { "config", 0, OPT_VALUE, "chooseconfig", -1 },
172     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
173     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
174     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
175     { "content-disposition", 0, OPT_BOOLEAN, "contentdisposition", -1 },
176     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
177     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
178     { WHEN_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
179     { "default-page", 0, OPT_VALUE, "defaultpage", -1 },
180     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
181     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
182     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
183     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
184     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
185     { "domains", 'D', OPT_VALUE, "domains", -1 },
186     { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
187     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 }, /* deprecated */
188     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
189     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
190     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
191     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
192     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
193     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
194     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
195     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
196     { "ftp-password", 0, OPT_VALUE, "ftppassword", -1 },
197 #ifdef __VMS
198     { "ftp-stmlf", 0, OPT_BOOLEAN, "ftpstmlf", -1 },
199 #endif /* def __VMS */
200     { "ftp-user", 0, OPT_VALUE, "ftpuser", -1 },
201     { "glob", 0, OPT_BOOLEAN, "glob", -1 },
202     { "header", 0, OPT_VALUE, "header", -1 },
203     { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
204     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
205     { "html-extension", 'E', OPT_BOOLEAN, "adjustextension", -1 }, /* deprecated */
206     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
207     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
208     { "http-passwd", 0, OPT_VALUE, "httppassword", -1 }, /* deprecated */
209     { "http-password", 0, OPT_VALUE, "httppassword", -1 },
210     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
211     { "ignore-case", 0, OPT_BOOLEAN, "ignorecase", -1 },
212     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
213     { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
214     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
215 #ifdef ENABLE_IPV6
216     { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
217     { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
218 #endif
219     { "input-file", 'i', OPT_VALUE, "input", -1 },
220     { "iri", 0, OPT_BOOLEAN, "iri", -1 },
221     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
222     { "level", 'l', OPT_VALUE, "reclevel", -1 },
223     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
224     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
225     { "local-encoding", 0, OPT_VALUE, "localencoding", -1 },
226     { "max-redirect", 0, OPT_VALUE, "maxredirect", -1 },
227     { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
228     { "no", 'n', OPT__NO, NULL, required_argument },
229     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
230     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
231     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
232     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
233     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
234     { "parent", 0, OPT__PARENT, NULL, optional_argument },
235     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
236     { "password", 0, OPT_VALUE, "password", -1 },
237     { "post-data", 0, OPT_VALUE, "postdata", -1 },
238     { "post-file", 0, OPT_VALUE, "postfile", -1 },
239     { "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
240     { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 }, /* deprecated */
241     { IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
242     { IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
243     { "progress", 0, OPT_VALUE, "progress", -1 },
244     { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
245     { "proxy", 0, OPT_BOOLEAN, "useproxy", -1 },
246     { "proxy__compat", 'Y', OPT_VALUE, "useproxy", -1 }, /* back-compatible */
247     { "proxy-passwd", 0, OPT_VALUE, "proxypassword", -1 }, /* deprecated */
248     { "proxy-password", 0, OPT_VALUE, "proxypassword", -1 },
249     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
250     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
251     { "quota", 'Q', OPT_VALUE, "quota", -1 },
252     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
253     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
254     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
255     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
256     { "referer", 0, OPT_VALUE, "referer", -1 },
257     { "reject", 'R', OPT_VALUE, "reject", -1 },
258     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
259     { "remote-encoding", 0, OPT_VALUE, "remoteencoding", -1 },
260     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
261     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
262     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
263     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
264     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
265     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
266     { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
267     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
268     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
269     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
270     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
271     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
272     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
273     { "tries", 't', OPT_VALUE, "tries", -1 },
274     { "unlink", 0, OPT_BOOLEAN, "unlink", -1 },
275     { "trust-server-names", 0, OPT_BOOLEAN, "trustservernames", -1 },
276     { "use-server-timestamps", 0, OPT_BOOLEAN, "useservertimestamps", -1 },
277     { "user", 0, OPT_VALUE, "user", -1 },
278     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
279     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
280     { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
281     { "version", 'V', OPT_FUNCALL, (void *) print_version, no_argument },
282     { "wait", 'w', OPT_VALUE, "wait", -1 },
283     { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
284 #ifdef USE_WATT32
285     { "wdebug", 0, OPT_BOOLEAN, "wdebug", -1 },
286 #endif
287   };
288
289 #undef WHEN_DEBUG
290 #undef IF_SSL
291
292 /* Return a string that contains S with "no-" prepended.  The string
293    is NUL-terminated and allocated off static storage at Wget
294    startup.  */
295
296 static char *
297 no_prefix (const char *s)
298 {
299   static char buffer[1024];
300   static char *p = buffer;
301
302   char *cp = p;
303   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
304   if (p + size >= buffer + sizeof (buffer))
305     abort ();
306
307   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
308   strcpy (cp + 3, s);
309   p += size;
310   return cp;
311 }
312
313 /* The arguments that that main passes to getopt_long. */
314 static struct option long_options[2 * countof (option_data) + 1];
315 static char short_options[128];
316
317 /* Mapping between short option chars and option_data indices. */
318 static unsigned char optmap[96];
319
320 /* Marker for `--no-FOO' values in long_options.  */
321 #define BOOLEAN_NEG_MARKER 1024
322
323 /* Initialize the long_options array used by getopt_long from the data
324    in option_data.  */
325
326 static void
327 init_switches (void)
328 {
329   char *p = short_options;
330   size_t i, o = 0;
331   for (i = 0; i < countof (option_data); i++)
332     {
333       struct cmdline_option *opt = &option_data[i];
334       struct option *longopt;
335
336       if (!opt->long_name)
337         /* The option is disabled. */
338         continue;
339
340       longopt = &long_options[o++];
341       longopt->name = opt->long_name;
342       longopt->val = i;
343       if (opt->short_name)
344         {
345           *p++ = opt->short_name;
346           optmap[opt->short_name - 32] = longopt - long_options;
347         }
348       switch (opt->type)
349         {
350         case OPT_VALUE:
351           longopt->has_arg = required_argument;
352           if (opt->short_name)
353             *p++ = ':';
354           break;
355         case OPT_BOOLEAN:
356           /* Specify an optional argument for long options, so that
357              --option=off works the same as --no-option, for
358              compatibility with pre-1.10 Wget.  However, don't specify
359              optional arguments short-option booleans because they
360              prevent combining of short options.  */
361           longopt->has_arg = optional_argument;
362           /* For Boolean options, add the "--no-FOO" variant, which is
363              identical to "--foo", except it has opposite meaning and
364              it doesn't allow an argument.  */
365           longopt = &long_options[o++];
366           longopt->name = no_prefix (opt->long_name);
367           longopt->has_arg = no_argument;
368           /* Mask the value so we'll be able to recognize that we're
369              dealing with the false value.  */
370           longopt->val = i | BOOLEAN_NEG_MARKER;
371           break;
372         default:
373           assert (opt->argtype != -1);
374           longopt->has_arg = opt->argtype;
375           if (opt->short_name)
376             {
377               if (longopt->has_arg == required_argument)
378                 *p++ = ':';
379               /* Don't handle optional_argument */
380             }
381         }
382     }
383   /* Terminate short_options. */
384   *p = '\0';
385   /* No need for xzero(long_options[o]) because its storage is static
386      and it will be zeroed by default.  */
387   assert (o <= countof (long_options));
388 }
389
390 /* Print the usage message.  */
391 static void
392 print_usage (int error)
393 {
394   fprintf (error ? stderr : stdout, _("Usage: %s [OPTION]... [URL]...\n"),
395            exec_name);
396 }
397
398 /* Print the help message, describing all the available options.  If
399    you add an option, be sure to update this list.  */
400 static void
401 print_help (void)
402 {
403   /* We split the help text this way to ease translation of individual
404      entries.  */
405   static const char *help[] = {
406     "\n",
407     N_("\
408 Mandatory arguments to long options are mandatory for short options too.\n\n"),
409     N_("\
410 Startup:\n"),
411     N_("\
412   -V,  --version           display the version of Wget and exit.\n"),
413     N_("\
414   -h,  --help              print this help.\n"),
415     N_("\
416   -b,  --background        go to background after startup.\n"),
417     N_("\
418   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
419     "\n",
420
421     N_("\
422 Logging and input file:\n"),
423     N_("\
424   -o,  --output-file=FILE    log messages to FILE.\n"),
425     N_("\
426   -a,  --append-output=FILE  append messages to FILE.\n"),
427 #ifdef ENABLE_DEBUG
428     N_("\
429   -d,  --debug               print lots of debugging information.\n"),
430 #endif
431 #ifdef USE_WATT32
432     N_("\
433        --wdebug              print Watt-32 debug output.\n"),
434 #endif
435     N_("\
436   -q,  --quiet               quiet (no output).\n"),
437     N_("\
438   -v,  --verbose             be verbose (this is the default).\n"),
439     N_("\
440   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
441     N_("\
442   -i,  --input-file=FILE     download URLs found in local or external FILE.\n"),
443     N_("\
444   -F,  --force-html          treat input file as HTML.\n"),
445     N_("\
446   -B,  --base=URL            resolves HTML input-file links (-i -F)\n\
447                              relative to URL.\n"),
448     N_("\
449        --config=FILE         Specify config file to use.\n"), 
450     "\n",
451
452     N_("\
453 Download:\n"),
454     N_("\
455   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
456     N_("\
457        --retry-connrefused       retry even if connection is refused.\n"),
458     N_("\
459   -O,  --output-document=FILE    write documents to FILE.\n"),
460     N_("\
461   -nc, --no-clobber              skip downloads that would download to\n\
462                                  existing files (overwriting them).\n"),
463     N_("\
464   -c,  --continue                resume getting a partially-downloaded file.\n"),
465     N_("\
466        --progress=TYPE           select progress gauge type.\n"),
467     N_("\
468   -N,  --timestamping            don't re-retrieve files unless newer than\n\
469                                  local.\n"),
470     N_("\
471   --no-use-server-timestamps     don't set the local file's timestamp by\n\
472                                  the one on the server.\n"),
473     N_("\
474   -S,  --server-response         print server response.\n"),
475     N_("\
476        --spider                  don't download anything.\n"),
477     N_("\
478   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
479     N_("\
480        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
481     N_("\
482        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
483     N_("\
484        --read-timeout=SECS       set the read timeout to SECS.\n"),
485     N_("\
486   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
487     N_("\
488        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
489     N_("\
490        --random-wait             wait from 0.5*WAIT...1.5*WAIT secs between retrievals.\n"),
491     N_("\
492        --no-proxy                explicitly turn off proxy.\n"),
493     N_("\
494   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
495     N_("\
496        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
497     N_("\
498        --limit-rate=RATE         limit download rate to RATE.\n"),
499     N_("\
500        --no-dns-cache            disable caching DNS lookups.\n"),
501     N_("\
502        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
503     N_("\
504        --ignore-case             ignore case when matching files/directories.\n"),
505 #ifdef ENABLE_IPV6
506     N_("\
507   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
508     N_("\
509   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
510     N_("\
511        --prefer-family=FAMILY    connect first to addresses of specified family,\n\
512                                  one of IPv6, IPv4, or none.\n"),
513 #endif
514     N_("\
515        --user=USER               set both ftp and http user to USER.\n"),
516     N_("\
517        --password=PASS           set both ftp and http password to PASS.\n"),
518     N_("\
519        --ask-password            prompt for passwords.\n"),
520     N_("\
521        --no-iri                  turn off IRI support.\n"),
522     N_("\
523        --local-encoding=ENC      use ENC as the local encoding for IRIs.\n"),
524     N_("\
525        --remote-encoding=ENC     use ENC as the default remote encoding.\n"),
526     N_("\
527        --unlink                  remove file before clobber.\n"),
528     "\n",
529
530     N_("\
531 Directories:\n"),
532     N_("\
533   -nd, --no-directories           don't create directories.\n"),
534     N_("\
535   -x,  --force-directories        force creation of directories.\n"),
536     N_("\
537   -nH, --no-host-directories      don't create host directories.\n"),
538     N_("\
539        --protocol-directories     use protocol name in directories.\n"),
540     N_("\
541   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
542     N_("\
543        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
544     "\n",
545
546     N_("\
547 HTTP options:\n"),
548     N_("\
549        --http-user=USER        set http user to USER.\n"),
550     N_("\
551        --http-password=PASS    set http password to PASS.\n"),
552     N_("\
553        --no-cache              disallow server-cached data.\n"),
554     N_ ("\
555        --default-page=NAME     Change the default page name (normally\n\
556                                this is `index.html'.).\n"),
557     N_("\
558   -E,  --adjust-extension      save HTML/CSS documents with proper extensions.\n"),
559     N_("\
560        --ignore-length         ignore `Content-Length' header field.\n"),
561     N_("\
562        --header=STRING         insert STRING among the headers.\n"),
563     N_("\
564        --max-redirect          maximum redirections allowed per page.\n"),
565     N_("\
566        --proxy-user=USER       set USER as proxy username.\n"),
567     N_("\
568        --proxy-password=PASS   set PASS as proxy password.\n"),
569     N_("\
570        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
571     N_("\
572        --save-headers          save the HTTP headers to file.\n"),
573     N_("\
574   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
575     N_("\
576        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
577     N_("\
578        --no-cookies            don't use cookies.\n"),
579     N_("\
580        --load-cookies=FILE     load cookies from FILE before session.\n"),
581     N_("\
582        --save-cookies=FILE     save cookies to FILE after session.\n"),
583     N_("\
584        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
585     N_("\
586        --post-data=STRING      use the POST method; send STRING as the data.\n"),
587     N_("\
588        --post-file=FILE        use the POST method; send contents of FILE.\n"),
589     N_("\
590        --content-disposition   honor the Content-Disposition header when\n\
591                                choosing local file names (EXPERIMENTAL).\n"),
592     N_("\
593        --auth-no-challenge     send Basic HTTP authentication information\n\
594                                without first waiting for the server's\n\
595                                challenge.\n"),
596     "\n",
597
598 #ifdef HAVE_SSL
599     N_("\
600 HTTPS (SSL/TLS) options:\n"),
601     N_("\
602        --secure-protocol=PR     choose secure protocol, one of auto, SSLv2,\n\
603                                 SSLv3, and TLSv1.\n"),
604     N_("\
605        --no-check-certificate   don't validate the server's certificate.\n"),
606     N_("\
607        --certificate=FILE       client certificate file.\n"),
608     N_("\
609        --certificate-type=TYPE  client certificate type, PEM or DER.\n"),
610     N_("\
611        --private-key=FILE       private key file.\n"),
612     N_("\
613        --private-key-type=TYPE  private key type, PEM or DER.\n"),
614     N_("\
615        --ca-certificate=FILE    file with the bundle of CA's.\n"),
616     N_("\
617        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
618     N_("\
619        --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
620     N_("\
621        --egd-file=FILE          file naming the EGD socket with random data.\n"),
622     "\n",
623 #endif /* HAVE_SSL */
624
625     N_("\
626 FTP options:\n"),
627 #ifdef __VMS
628     N_("\
629        --ftp-stmlf             Use Stream_LF format for all binary FTP files.\n"),
630 #endif /* def __VMS */
631     N_("\
632        --ftp-user=USER         set ftp user to USER.\n"),
633     N_("\
634        --ftp-password=PASS     set ftp password to PASS.\n"),
635     N_("\
636        --no-remove-listing     don't remove `.listing' files.\n"),
637     N_("\
638        --no-glob               turn off FTP file name globbing.\n"),
639     N_("\
640        --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
641     N_("\
642        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
643     "\n",
644
645     N_("\
646 Recursive download:\n"),
647     N_("\
648   -r,  --recursive          specify recursive download.\n"),
649     N_("\
650   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
651     N_("\
652        --delete-after       delete files locally after downloading them.\n"),
653     N_("\
654   -k,  --convert-links      make links in downloaded HTML or CSS point to\n\
655                             local files.\n"),
656 #ifdef __VMS
657     N_("\
658   -K,  --backup-converted   before converting file X, back up as X_orig.\n"),
659 #else /* def __VMS */
660     N_("\
661   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
662 #endif /* def __VMS [else] */
663     N_("\
664   -m,  --mirror             shortcut for -N -r -l inf --no-remove-listing.\n"),
665     N_("\
666   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
667     N_("\
668        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
669     "\n",
670
671     N_("\
672 Recursive accept/reject:\n"),
673     N_("\
674   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
675     N_("\
676   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
677     N_("\
678   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
679     N_("\
680        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
681     N_("\
682        --follow-ftp                follow FTP links from HTML documents.\n"),
683     N_("\
684        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
685     N_("\
686        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
687     N_("\
688   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
689     N_("\
690   -L,  --relative                  follow relative links only.\n"),
691     N_("\
692   -I,  --include-directories=LIST  list of allowed directories.\n"),
693     N_("\
694   --trust-server-names             use the name specified by the redirection\n\
695                                    url last component.\n"),
696     N_("\
697   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
698     N_("\
699   -np, --no-parent                 don't ascend to the parent directory.\n"),
700     "\n",
701
702     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
703   };
704
705   size_t i;
706
707   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
708           version_string);
709   print_usage (0);
710
711   for (i = 0; i < countof (help); i++)
712     fputs (_(help[i]), stdout);
713
714   exit (0);
715 }
716
717 /* Return a human-readable printed representation of INTERVAL,
718    measured in seconds.  */
719
720 static char *
721 secs_to_human_time (double interval)
722 {
723   static char buf[32];
724   int secs = (int) (interval + 0.5);
725   int hours, mins, days;
726
727   days = secs / 86400, secs %= 86400;
728   hours = secs / 3600, secs %= 3600;
729   mins = secs / 60, secs %= 60;
730
731   if (days)
732     sprintf (buf, "%dd %dh %dm %ds", days, hours, mins, secs);
733   else if (hours)
734     sprintf (buf, "%dh %dm %ds", hours, mins, secs);
735   else if (mins)
736     sprintf (buf, "%dm %ds", mins, secs);
737   else
738     sprintf (buf, "%ss", print_decimal (interval));
739
740   return buf;
741 }
742
743 static char *
744 prompt_for_password (void)
745 {
746   if (opt.user)
747     fprintf (stderr, _("Password for user %s: "), quote (opt.user));
748   else
749     fprintf (stderr, _("Password: "));
750   return getpass("");
751 }
752
753 /* Function that prints the line argument while limiting it
754    to at most line_length. prefix is printed on the first line
755    and an appropriate number of spaces are added on subsequent
756    lines.*/
757 static void
758 format_and_print_line (const char *prefix, const char *line,
759                        int line_length)
760 {
761   int remaining_chars;
762   char *line_dup, *token;
763
764   assert (prefix != NULL);
765   assert (line != NULL);
766
767   line_dup = xstrdup (line);
768
769   if (line_length <= 0)
770     line_length = MAX_CHARS_PER_LINE - TABULATION;
771
772   printf ("%s", prefix);
773   remaining_chars = line_length;
774   /* We break on spaces. */
775   token = strtok (line_dup, " ");
776   while (token != NULL)
777     {
778       /* If however a token is much larger than the maximum
779          line length, all bets are off and we simply print the
780          token on the next line. */
781       if (remaining_chars <= strlen (token))
782         {
783           printf ("\n%*c", TABULATION, ' ');
784           remaining_chars = line_length - TABULATION;
785         }
786       printf ("%s ", token);
787       remaining_chars -= strlen (token) + 1;  /* account for " " */
788       token = strtok (NULL, " ");
789     }
790
791   printf ("\n");
792
793   xfree (line_dup);
794 }
795
796 static void
797 print_version (void)
798 {
799   const char *wgetrc_title  = _("Wgetrc: ");
800   const char *locale_title  = _("Locale: ");
801   const char *compile_title = _("Compile: ");
802   const char *link_title    = _("Link: ");
803   char *env_wgetrc, *user_wgetrc;
804   int i;
805
806   printf (_("GNU Wget %s built on %s.\n\n"), version_string, OS_TYPE);
807
808   for (i = 0; compiled_features[i] != NULL; )
809     {
810       int line_length = MAX_CHARS_PER_LINE;
811       while ((line_length > 0) && (compiled_features[i] != NULL))
812         {
813           printf ("%s ", compiled_features[i]);
814           line_length -= strlen (compiled_features[i]) + 2;
815           i++;
816         }
817       printf ("\n");
818     }
819   printf ("\n");
820
821   /* Handle the case when $WGETRC is unset and $HOME/.wgetrc is
822      absent. */
823   printf ("%s\n", wgetrc_title);
824   env_wgetrc = wgetrc_env_file_name ();
825   if (env_wgetrc && *env_wgetrc)
826     {
827       printf (_("    %s (env)\n"), env_wgetrc);
828       xfree (env_wgetrc);
829     }
830   user_wgetrc = wgetrc_user_file_name ();
831   if (user_wgetrc)
832     {
833       printf (_("    %s (user)\n"), user_wgetrc);
834       xfree (user_wgetrc);
835     }
836 #ifdef SYSTEM_WGETRC
837   printf (_("    %s (system)\n"), SYSTEM_WGETRC);
838 #endif
839
840 #ifdef ENABLE_NLS
841   format_and_print_line (locale_title,
842                         LOCALEDIR,
843                         MAX_CHARS_PER_LINE);
844 #endif /* def ENABLE_NLS */
845
846   if (compilation_string != NULL)
847     format_and_print_line (compile_title,
848                            compilation_string,
849                            MAX_CHARS_PER_LINE);
850
851   if (link_string != NULL)
852     format_and_print_line (link_title,
853                            link_string,
854                            MAX_CHARS_PER_LINE);
855
856   printf ("\n");
857   /* TRANSLATORS: When available, an actual copyright character
858      (cirle-c) should be used in preference to "(C)". */
859   fputs (_("\
860 Copyright (C) 2009 Free Software Foundation, Inc.\n"), stdout);
861   fputs (_("\
862 License GPLv3+: GNU GPL version 3 or later\n\
863 <http://www.gnu.org/licenses/gpl.html>.\n\
864 This is free software: you are free to change and redistribute it.\n\
865 There is NO WARRANTY, to the extent permitted by law.\n"), stdout);
866   /* TRANSLATORS: When available, please use the proper diacritics for
867      names such as this one. See en_US.po for reference. */
868   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
869          stdout);
870   fputs (_("Please send bug reports and questions to <bug-wget@gnu.org>.\n"),
871          stdout);
872   exit (0);
873 }
874
875 char *program_name; /* Needed by lib/error.c. */
876
877 int
878 main (int argc, char **argv)
879 {
880   char **url, **t;
881   int i, ret, longindex;
882   int nurl;
883   bool append_to_log = false;
884
885   total_downloaded_bytes = 0;
886
887   program_name = argv[0];
888
889   struct ptimer *timer = ptimer_new ();
890   double start_time = ptimer_measure (timer);
891
892   i18n_initialize ();
893
894   /* Construct the name of the executable, without the directory part.  */
895 #ifdef __VMS
896   /* On VMS, lose the "dev:[dir]" prefix and the ".EXE;nnn" suffix. */
897   exec_name = vms_basename (argv[0]);
898 #else /* def __VMS */
899   exec_name = strrchr (argv[0], PATH_SEPARATOR);
900   if (!exec_name)
901     exec_name = argv[0];
902   else
903     ++exec_name;
904 #endif /* def __VMS [else] */
905
906 #ifdef WINDOWS
907   /* Drop extension (typically .EXE) from executable filename. */
908   windows_main ((char **) &exec_name);
909 #endif
910
911   /* Load the hard-coded defaults.  */
912   defaults ();
913
914   init_switches ();
915
916   /* This seperate getopt_long is needed to find the user config
917      and parse it before the other user options. */
918   longindex = -1;
919   int retconf;
920   bool use_userconfig = false;
921
922   while ((retconf = getopt_long (argc, argv,
923                                 short_options, long_options, &longindex)) != -1)
924     {
925       int confval;
926       bool userrc_ret = true;
927       struct cmdline_option *config_opt;
928       confval = long_options[longindex].val;
929       config_opt = &option_data[confval & ~BOOLEAN_NEG_MARKER];
930       if (strcmp (config_opt->long_name, "config") == 0)
931         {
932           userrc_ret &= run_wgetrc (optarg);
933           use_userconfig = true;
934         }
935       if (!userrc_ret)
936         {
937           printf ("Exiting due to error in %s\n", optarg);
938           exit (2);
939         }
940       else
941         break;
942     }
943
944   /* If the user did not specify a config, read the system wgetrc and ~/.wgetrc. */
945   if (use_userconfig == false)
946     initialize ();
947
948   opterr = 0;
949   optind = 0;
950
951   longindex = -1;
952   while ((ret = getopt_long (argc, argv,
953                              short_options, long_options, &longindex)) != -1)
954     {
955       int val;
956       struct cmdline_option *opt;
957
958       /* If LONGINDEX is unchanged, it means RET is referring a short
959          option.  */
960       if (longindex == -1)
961         {
962           if (ret == '?')
963             {
964               print_usage (0);
965               printf ("\n");
966               printf (_("Try `%s --help' for more options.\n"), exec_name);
967               exit (2);
968             }
969           /* Find the short option character in the mapping.  */
970           longindex = optmap[ret - 32];
971         }
972       val = long_options[longindex].val;
973
974       /* Use the retrieved value to locate the option in the
975          option_data array, and to see if we're dealing with the
976          negated "--no-FOO" variant of the boolean option "--foo".  */
977       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
978       switch (opt->type)
979         {
980         case OPT_VALUE:
981           setoptval (opt->data, optarg, opt->long_name);
982           break;
983         case OPT_BOOLEAN:
984           if (optarg)
985             /* The user has specified a value -- use it. */
986             setoptval (opt->data, optarg, opt->long_name);
987           else
988             {
989               /* NEG is true for `--no-FOO' style boolean options. */
990               bool neg = !!(val & BOOLEAN_NEG_MARKER);
991               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
992             }
993           break;
994         case OPT_FUNCALL:
995           {
996             void (*func) (void) = (void (*) (void)) opt->data;
997             func ();
998           }
999           break;
1000         case OPT__APPEND_OUTPUT:
1001           setoptval ("logfile", optarg, opt->long_name);
1002           append_to_log = true;
1003           break;
1004         case OPT__EXECUTE:
1005           run_command (optarg);
1006           break;
1007         case OPT__NO:
1008           {
1009             /* We support real --no-FOO flags now, but keep these
1010                short options for convenience and backward
1011                compatibility.  */
1012             char *p;
1013             for (p = optarg; p && *p; p++)
1014               switch (*p)
1015                 {
1016                 case 'v':
1017                   setoptval ("verbose", "0", opt->long_name);
1018                   break;
1019                 case 'H':
1020                   setoptval ("addhostdir", "0", opt->long_name);
1021                   break;
1022                 case 'd':
1023                   setoptval ("dirstruct", "0", opt->long_name);
1024                   break;
1025                 case 'c':
1026                   setoptval ("noclobber", "1", opt->long_name);
1027                   break;
1028                 case 'p':
1029                   setoptval ("noparent", "1", opt->long_name);
1030                   break;
1031                 default:
1032                   fprintf (stderr, _("%s: illegal option -- `-n%c'\n"),
1033                            exec_name, *p);
1034                   print_usage (1);
1035                   fprintf (stderr, "\n");
1036                   fprintf (stderr, _("Try `%s --help' for more options.\n"),
1037                            exec_name);
1038                   exit (1);
1039                 }
1040             break;
1041           }
1042         case OPT__PARENT:
1043         case OPT__CLOBBER:
1044           {
1045             /* The wgetrc commands are named noparent and noclobber,
1046                so we must revert the meaning of the cmdline options
1047                before passing the value to setoptval.  */
1048             bool flag = true;
1049             if (optarg)
1050               flag = (*optarg == '1' || c_tolower (*optarg) == 'y'
1051                       || (c_tolower (optarg[0]) == 'o'
1052                           && c_tolower (optarg[1]) == 'n'));
1053             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
1054                        flag ? "0" : "1", opt->long_name);
1055             break;
1056           }
1057         case OPT__DONT_REMOVE_LISTING:
1058           setoptval ("removelisting", "0", opt->long_name);
1059           break;
1060         }
1061
1062       longindex = -1;
1063     }
1064
1065   nurl = argc - optind;
1066
1067   /* All user options have now been processed, so it's now safe to do
1068      interoption dependency checks. */
1069
1070   if (opt.noclobber && opt.convert_links)
1071     {
1072       fprintf (stderr,
1073                _("Both --no-clobber and --convert-links were specified,"
1074                  "only --convert-links will be used.\n"));
1075       opt.noclobber = false;
1076     }
1077
1078   if (opt.reclevel == 0)
1079       opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary */
1080
1081   if (opt.spider || opt.delete_after)
1082       opt.no_dirstruct = true;
1083
1084   if (opt.page_requisites && !opt.recursive)
1085     {
1086       /* Don't set opt.recursive here because it would confuse the FTP
1087          code.  Instead, call retrieve_tree below when either
1088          page_requisites or recursive is requested.  */
1089       opt.reclevel = 0;
1090       if (!opt.no_dirstruct)
1091         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
1092     }
1093
1094   if (opt.verbose == -1)
1095     opt.verbose = !opt.quiet;
1096
1097   /* Sanity checks.  */
1098   if (opt.verbose && opt.quiet)
1099     {
1100       fprintf (stderr, _("Can't be verbose and quiet at the same time.\n"));
1101       print_usage (1);
1102       exit (1);
1103     }
1104   if (opt.timestamping && opt.noclobber)
1105     {
1106       fprintf (stderr, _("\
1107 Can't timestamp and not clobber old files at the same time.\n"));
1108       print_usage (1);
1109       exit (1);
1110     }
1111 #ifdef ENABLE_IPV6
1112   if (opt.ipv4_only && opt.ipv6_only)
1113     {
1114       fprintf (stderr,
1115                _("Cannot specify both --inet4-only and --inet6-only.\n"));
1116       print_usage (1);
1117       exit (1);
1118     }
1119 #endif
1120   if (opt.output_document)
1121     {
1122       if (opt.convert_links
1123           && (nurl > 1 || opt.page_requisites || opt.recursive))
1124         {
1125           fputs (_("\
1126 Cannot specify both -k and -O if multiple URLs are given, or in combination\n\
1127 with -p or -r. See the manual for details.\n\n"), stderr);
1128           print_usage (1);
1129           exit (1);
1130         }
1131       if (opt.page_requisites
1132           || opt.recursive)
1133         {
1134           logprintf (LOG_NOTQUIET, "%s", _("\
1135 WARNING: combining -O with -r or -p will mean that all downloaded content\n\
1136 will be placed in the single file you specified.\n\n"));
1137         }
1138       if (opt.timestamping)
1139         {
1140           logprintf (LOG_NOTQUIET, "%s", _("\
1141 WARNING: timestamping does nothing in combination with -O. See the manual\n\
1142 for details.\n\n"));
1143           opt.timestamping = false;
1144         }
1145       if (opt.noclobber && file_exists_p(opt.output_document))
1146            {
1147               /* Check if output file exists; if it does, exit. */
1148               logprintf (LOG_VERBOSE,
1149                          _("File `%s' already there; not retrieving.\n"),
1150                          opt.output_document);
1151               exit(1);
1152            }
1153     }
1154
1155   if (opt.ask_passwd && opt.passwd)
1156     {
1157       fprintf (stderr,
1158                _("Cannot specify both --ask-password and --password.\n"));
1159       print_usage (1);
1160       exit (1);
1161     }
1162
1163   if (!nurl && !opt.input_filename)
1164     {
1165       /* No URL specified.  */
1166       fprintf (stderr, _("%s: missing URL\n"), exec_name);
1167       print_usage (1);
1168       printf ("\n");
1169       /* #### Something nicer should be printed here -- similar to the
1170          pre-1.5 `--help' page.  */
1171       fprintf (stderr, _("Try `%s --help' for more options.\n"), exec_name);
1172       exit (1);
1173     }
1174
1175 #ifdef ENABLE_IRI
1176   if (opt.enable_iri)
1177     {
1178       if (opt.locale && !check_encoding_name (opt.locale))
1179         opt.locale = NULL;
1180
1181       if (!opt.locale)
1182         opt.locale = find_locale ();
1183
1184       if (opt.encoding_remote && !check_encoding_name (opt.encoding_remote))
1185         opt.encoding_remote = NULL;
1186     }
1187 #else
1188   memset (&dummy_iri, 0, sizeof (dummy_iri));
1189   if (opt.enable_iri || opt.locale || opt.encoding_remote)
1190     {
1191       /* sXXXav : be more specific... */
1192       fprintf (stderr, _("This version does not have support for IRIs\n"));
1193       exit(1);
1194     }
1195 #endif
1196
1197   if (opt.ask_passwd)
1198     {
1199       opt.passwd = prompt_for_password ();
1200
1201       if (opt.passwd == NULL || opt.passwd[0] == '\0')
1202         exit (1);
1203     }
1204
1205 #ifdef USE_WATT32
1206   if (opt.wdebug)
1207      dbug_init();
1208   sock_init();
1209 #else
1210   if (opt.background)
1211     fork_to_background ();
1212 #endif
1213
1214   /* Initialize progress.  Have to do this after the options are
1215      processed so we know where the log file is.  */
1216   if (opt.verbose)
1217     set_progress_implementation (opt.progress_type);
1218
1219   /* Fill in the arguments.  */
1220   url = alloca_array (char *, nurl + 1);
1221   for (i = 0; i < nurl; i++, optind++)
1222     {
1223       char *rewritten = rewrite_shorthand_url (argv[optind]);
1224       if (rewritten)
1225         url[i] = rewritten;
1226       else
1227         url[i] = xstrdup (argv[optind]);
1228     }
1229   url[i] = NULL;
1230
1231   /* Initialize logging.  */
1232   log_init (opt.lfilename, append_to_log);
1233
1234   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n",
1235            version_string, OS_TYPE));
1236
1237   /* Open the output filename if necessary.  */
1238
1239 /* 2005-04-17 SMS.
1240    Note that having the output_stream ("-O") file opened here for an FTP
1241    URL rather than in getftp() (ftp.c) (and the http equivalent) rather
1242    limits the ability in VMS to open the file differently for ASCII
1243    versus binary FTP there.  (Of course, doing it here allows a open
1244    failure to be detected immediately, without first connecting to the
1245    server.)
1246 */
1247   if (opt.output_document)
1248     {
1249       if (HYPHENP (opt.output_document))
1250         {
1251 #ifdef WINDOWS
1252           FILE *result;
1253           result = freopen ("CONOUT$", "wb", stdout);
1254           if (result == NULL)
1255             {
1256               logputs (LOG_NOTQUIET, _("\
1257 WARNING: Can't reopen standard output in binary mode;\n\
1258          downloaded file may contain inappropriate line endings.\n"));
1259             }
1260 #endif
1261           output_stream = stdout;
1262         }
1263       else
1264         {
1265           struct_fstat st;
1266
1267 #ifdef __VMS
1268 /* Common fopen() optional arguments:
1269    sequential access only, access callback function.
1270 */
1271 # define FOPEN_OPT_ARGS , "fop=sqo", "acc", acc_cb, &open_id
1272           int open_id = 7;
1273 #else /* def __VMS */
1274 # define FOPEN_OPT_ARGS
1275 #endif /* def __VMS [else] */
1276
1277           output_stream = fopen (opt.output_document,
1278                                  opt.always_rest ? "ab" : "wb"
1279                                  FOPEN_OPT_ARGS);
1280           if (output_stream == NULL)
1281             {
1282               perror (opt.output_document);
1283               exit (1);
1284             }
1285           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
1286             output_stream_regular = true;
1287         }
1288       if (!output_stream_regular && opt.convert_links)
1289         {
1290           fprintf (stderr, _("-k can be used together with -O only if \
1291 outputting to a regular file.\n"));
1292           print_usage (1);
1293           exit(1);
1294         }
1295     }
1296
1297 #ifdef __VMS
1298   /* Set global ODS5 flag according to the specified destination (if
1299      any), otherwise according to the current default device.
1300   */
1301   if (output_stream == NULL)
1302     set_ods5_dest( "SYS$DISK");
1303   else if (output_stream != stdout)
1304     set_ods5_dest( opt.output_document);
1305 #endif /* def __VMS */
1306
1307 #ifdef WINDOWS
1308   ws_startup ();
1309 #endif
1310
1311 #ifdef SIGHUP
1312   /* Setup the signal handler to redirect output when hangup is
1313      received.  */
1314   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1315     signal(SIGHUP, redirect_output_signal);
1316 #endif
1317   /* ...and do the same for SIGUSR1.  */
1318 #ifdef SIGUSR1
1319   signal (SIGUSR1, redirect_output_signal);
1320 #endif
1321 #ifdef SIGPIPE
1322   /* Writing to a closed socket normally signals SIGPIPE, and the
1323      process exits.  What we want is to ignore SIGPIPE and just check
1324      for the return value of write().  */
1325   signal (SIGPIPE, SIG_IGN);
1326 #endif
1327 #ifdef SIGWINCH
1328   signal (SIGWINCH, progress_handle_sigwinch);
1329 #endif
1330
1331   /* Retrieve the URLs from argument list.  */
1332   for (t = url; *t; t++)
1333     {
1334       char *filename = NULL, *redirected_URL = NULL;
1335       int dt, url_err;
1336       /* Need to do a new struct iri every time, because
1337        * retrieve_url may modify it in some circumstances,
1338        * currently. */
1339       struct iri *iri = iri_new ();
1340       struct url *url_parsed;
1341
1342       set_uri_encoding (iri, opt.locale, true);
1343       url_parsed = url_parse (*t, &url_err, iri, true);
1344
1345       if (!url_parsed)
1346         {
1347           char *error = url_error (*t, url_err);
1348           logprintf (LOG_NOTQUIET, "%s: %s.\n",*t, error);
1349           xfree (error);
1350         }
1351       else
1352         {
1353           if ((opt.recursive || opt.page_requisites)
1354               && (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (url_parsed)))
1355             {
1356               int old_follow_ftp = opt.follow_ftp;
1357
1358               /* Turn opt.follow_ftp on in case of recursive FTP retrieval */
1359               if (url_scheme (*t) == SCHEME_FTP)
1360                 opt.follow_ftp = 1;
1361
1362               retrieve_tree (url_parsed, NULL);
1363
1364               opt.follow_ftp = old_follow_ftp;
1365             }
1366           else
1367           {
1368             retrieve_url (url_parsed, *t, &filename, &redirected_URL, NULL,
1369                           &dt, opt.recursive, iri, true);
1370           }
1371
1372           if (opt.delete_after && file_exists_p(filename))
1373             {
1374               DEBUGP (("Removing file due to --delete-after in main():\n"));
1375               logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
1376               if (unlink (filename))
1377                 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1378             }
1379           xfree_null (redirected_URL);
1380           xfree_null (filename);
1381           url_free (url_parsed);
1382         }
1383       iri_free (iri);
1384     }
1385
1386   /* And then from the input file, if any.  */
1387   if (opt.input_filename)
1388     {
1389       int count;
1390       retrieve_from_file (opt.input_filename, opt.force_html, &count);
1391       if (!count)
1392         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
1393                    opt.input_filename);
1394     }
1395
1396   /* Print broken links. */
1397   if (opt.recursive && opt.spider)
1398     print_broken_links ();
1399
1400   /* Print the downloaded sum.  */
1401   if ((opt.recursive || opt.page_requisites
1402        || nurl > 1
1403        || (opt.input_filename && total_downloaded_bytes != 0))
1404       &&
1405       total_downloaded_bytes != 0)
1406     {
1407       double end_time = ptimer_measure (timer);
1408       ptimer_destroy (timer);
1409
1410       char *wall_time = xstrdup (secs_to_human_time (end_time - start_time));
1411       char *download_time = xstrdup (secs_to_human_time (total_download_time));
1412       logprintf (LOG_NOTQUIET,
1413                  _("FINISHED --%s--\nTotal wall clock time: %s\n"
1414                    "Downloaded: %d files, %s in %s (%s)\n"),
1415                  datetime_str (time (NULL)),
1416                  wall_time,
1417                  numurls,
1418                  human_readable (total_downloaded_bytes),
1419                  download_time,
1420                  retr_rate (total_downloaded_bytes, total_download_time));
1421       xfree (wall_time);
1422       xfree (download_time);
1423
1424       /* Print quota warning, if exceeded.  */
1425       if (opt.quota && total_downloaded_bytes > opt.quota)
1426         logprintf (LOG_NOTQUIET,
1427                    _("Download quota of %s EXCEEDED!\n"),
1428                    human_readable (opt.quota));
1429     }
1430
1431   if (opt.cookies_output)
1432     save_cookies ();
1433
1434   if (opt.convert_links && !opt.delete_after)
1435     convert_all_links ();
1436
1437   log_close ();
1438   for (i = 0; i < nurl; i++)
1439     xfree (url[i]);
1440   cleanup ();
1441
1442   return get_exit_status ();
1443 }
1444 #endif /* TESTING */
1445 \f
1446 #if defined(SIGHUP) || defined(SIGUSR1)
1447
1448 /* So the signal_name check doesn't blow when only one is available. */
1449 #ifndef SIGHUP
1450 # define SIGHUP -1
1451 #endif
1452 #ifndef SIGUSR1
1453 # define SIGUSR1 -1
1454 #endif
1455
1456 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1457    will proceed operation as usual, trying to write into a log file.
1458    If that is impossible, the output will be turned off.  */
1459
1460 static void
1461 redirect_output_signal (int sig)
1462 {
1463   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1464                              (sig == SIGUSR1 ? "SIGUSR1" :
1465                               "WTF?!"));
1466   log_request_redirect_output (signal_name);
1467   progress_schedule_redirect ();
1468   signal (sig, redirect_output_signal);
1469 }
1470 #endif
1471
1472 /*
1473  * vim: et ts=2 sw=2
1474  */