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