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