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