]> sjero.net Git - wget/blob - src/main.c
[svn] Remove ws_help; it doesn't make sense to invoke the help browser for
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 2003 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif /* HAVE_UNISTD_H */
37 #include <sys/types.h>
38 #ifdef HAVE_STRING_H
39 # include <string.h>
40 #else
41 # include <strings.h>
42 #endif /* HAVE_STRING_H */
43 #ifdef HAVE_SIGNAL_H
44 # include <signal.h>
45 #endif
46 #ifdef HAVE_NLS
47 #ifdef HAVE_LOCALE_H
48 # include <locale.h>
49 #endif /* HAVE_LOCALE_H */
50 #endif /* HAVE_NLS */
51 #include <assert.h>
52
53 #include <errno.h>
54 #ifndef errno
55 extern int errno;
56 #endif
57
58 #include "wget.h"
59 #include "utils.h"
60 #include "init.h"
61 #include "retr.h"
62 #include "recur.h"
63 #include "host.h"
64 #include "cookies.h"
65 #include "url.h"
66 #include "progress.h"           /* for progress_handle_sigwinch */
67 #include "convert.h"
68
69 /* On GNU system this will include system-wide getopt.h. */
70 #include "getopt.h"
71
72 #ifndef PATH_SEPARATOR
73 # define PATH_SEPARATOR '/'
74 #endif
75
76 struct options opt;
77
78 extern LARGE_INT total_downloaded_bytes;
79 extern char *version_string;
80
81 extern struct cookie_jar *wget_cookie_jar;
82
83 static RETSIGTYPE redirect_output_signal PARAMS ((int));
84
85 const char *exec_name;
86 \f
87 /* Initialize I18N.  The initialization amounts to invoking
88    setlocale(), bindtextdomain() and textdomain().
89    Does nothing if NLS is disabled or missing.  */
90 static void
91 i18n_initialize (void)
92 {
93   /* If HAVE_NLS is defined, assume the existence of the three
94      functions invoked here.  */
95 #ifdef HAVE_NLS
96   /* Set the current locale.  */
97   /* Here we use LC_MESSAGES instead of LC_ALL, for two reasons.
98      First, message catalogs are all of I18N Wget uses anyway.
99      Second, setting LC_ALL has a dangerous potential of messing
100      things up.  For example, when in a foreign locale, Solaris
101      strptime() fails to handle international dates correctly, which
102      makes http_atotm() malfunction.  */
103 #ifdef LC_MESSAGES
104   setlocale (LC_MESSAGES, "");
105   setlocale (LC_CTYPE, "");
106 #else
107   setlocale (LC_ALL, "");
108 #endif
109   /* Set the text message domain.  */
110   bindtextdomain ("wget", LOCALEDIR);
111   textdomain ("wget");
112 #endif /* HAVE_NLS */
113 }
114 \f
115 /* Definition of command-line options. */
116
117 static void print_help PARAMS ((void));
118 static void print_version PARAMS ((void));
119
120 #ifdef HAVE_SSL
121 # define IF_SSL(x) x
122 #else
123 # define IF_SSL(x) NULL
124 #endif
125
126 #ifdef ENABLE_DEBUG
127 # define IF_DEBUG(x) x
128 #else
129 # define IF_DEBUG(x) NULL
130 #endif
131
132 struct cmdline_option {
133   const char *long_name;
134   char short_name;
135   enum {
136     OPT_VALUE,
137     OPT_BOOLEAN,
138     OPT_FUNCALL,
139     /* Non-standard options that have to be handled specially in
140        main().  */
141     OPT__APPEND_OUTPUT,
142     OPT__CLOBBER,
143     OPT__DONT_REMOVE_LISTING,
144     OPT__EXECUTE,
145     OPT__NO,
146     OPT__PARENT,
147   } type;
148   const void *data;             /* for standard options */
149   int argtype;                  /* for non-standard options */
150 };
151
152 struct cmdline_option option_data[] =
153   {
154     { "accept", 'A', OPT_VALUE, "accept", -1 },
155     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
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     { "cache", 0, OPT_BOOLEAN, "cache", -1 },
162     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
163     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
164     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
165     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
166     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
167     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
168     { IF_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
169     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
170     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
171     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
172     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
173     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
174     { "domains", 'D', OPT_VALUE, "domains", -1 },
175     { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
176     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 },
177     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
178     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
179     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
180     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
181     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
182     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
183     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
184     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
185     { "glob", 0, OPT_BOOLEAN, "glob", -1 },
186     { "header", 0, OPT_VALUE, "header", -1 },
187     { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
188     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
189     { "html-extension", 'E', OPT_BOOLEAN, "htmlextension", -1 },
190     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
191     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
192     { "http-passwd", 0, OPT_VALUE, "httppasswd", -1 },
193     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
194     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
195     { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
196     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
197 #ifdef ENABLE_IPV6
198     { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
199     { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
200 #endif
201     { "input-file", 'i', OPT_VALUE, "input", -1 },
202     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
203     { "level", 'l', OPT_VALUE, "reclevel", -1 },
204     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
205     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
206     { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
207     { "no", 'n', OPT__NO, NULL, required_argument },
208     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
209     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
210     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
211     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
212     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
213     { "parent", 0, OPT__PARENT, NULL, optional_argument },
214     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
215     { "post-data", 0, OPT_VALUE, "postdata", -1 },
216     { "post-file", 0, OPT_VALUE, "postfile", -1 },
217     { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
218     { "progress", 0, OPT_VALUE, "progress", -1 },
219     { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
220     { "proxy", 'Y', OPT_BOOLEAN, "useproxy", -1 },
221     { "proxy-passwd", 0, OPT_VALUE, "proxypasswd", -1 },
222     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
223     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
224     { "quota", 'Q', OPT_VALUE, "quota", -1 },
225     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
226     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
227     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
228     { "referer", 0, OPT_VALUE, "referer", -1 },
229     { "reject", 'R', OPT_VALUE, "reject", -1 },
230     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
231     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
232     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
233     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
234     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
235     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
236     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
237     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
238     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
239     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
240     { IF_SSL ("sslcadir"), 0, OPT_VALUE, "sslcadir", -1 },
241     { IF_SSL ("sslcafile"), 0, OPT_VALUE, "sslcafile", -1 },
242     { IF_SSL ("sslcertfile"), 0, OPT_VALUE, "sslcertfile", -1 },
243     { IF_SSL ("sslcertkey"), 0, OPT_VALUE, "sslcertkey", -1 },
244     { IF_SSL ("sslcerttype"), 0, OPT_VALUE, "sslcerttype", -1 },
245     { IF_SSL ("sslcheckcert"), 0, OPT_VALUE, "sslcheckcert", -1 },
246     { IF_SSL ("sslprotocol"), 0, OPT_VALUE, "sslprotocol", -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     { "use-proxy", 'Y', OPT_BOOLEAN, "useproxy", -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   };
259
260 #undef IF_DEBUG
261 #undef IF_SSL
262
263 /* Return a string that contains S with "no-" prepended.  The string
264    is NUL-terminated and allocated off static storage at Wget
265    startup.  */
266
267 static char *
268 no_prefix (const char *s)
269 {
270   static char buffer[1024];
271   static char *p = buffer;
272
273   char *cp = p;
274   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
275   if (p + size >= buffer + sizeof (buffer))
276     abort ();
277
278   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
279   strcpy (cp + 3, s);
280   p += size;
281   return cp;
282 }
283
284 /* The arguments that that main passes to getopt_long. */
285 static struct option long_options[2 * countof (option_data) + 1];
286 static char short_options[128];
287
288 /* Mapping between short option chars and option_data indices. */
289 static unsigned char optmap[96];
290
291 /* Marker for `--no-FOO' values in long_options.  */
292 #define BOOLEAN_NEG_MARKER 1024
293
294 /* Initialize the long_options array used by getopt_long from the data
295    in option_data.  */
296
297 static void
298 init_switches (void)
299 {
300   char *p = short_options;
301   int i, o = 0;
302   for (i = 0; i < countof (option_data); i++)
303     {
304       struct cmdline_option *opt = &option_data[i];
305       struct option *longopt;
306
307       if (!opt->long_name)
308         /* The option is disabled. */
309         continue;
310
311       longopt = &long_options[o++];
312       longopt->name = opt->long_name;
313       longopt->val = i;
314       if (opt->short_name)
315         {
316           *p++ = opt->short_name;
317           optmap[opt->short_name - 32] = longopt - long_options;
318         }
319       switch (opt->type)
320         {
321         case OPT_VALUE:
322           longopt->has_arg = required_argument;
323           if (opt->short_name)
324             *p++ = ':';
325           break;
326         case OPT_BOOLEAN:
327           /* Don't specify optional arguments for boolean short
328              options.  They are evil because they prevent combining of
329              short options.  */
330           longopt->has_arg = optional_argument;
331           /* For Boolean options, add the "--no-FOO" variant, which is
332              identical to "--foo", except it has opposite meaning and
333              it doesn't allow an argument.  */
334           longopt = &long_options[o++];
335           longopt->name = no_prefix (opt->long_name);
336           longopt->has_arg = no_argument;
337           /* Mask the value so we'll be able to recognize that we're
338              dealing with the false value.  */
339           longopt->val = i | BOOLEAN_NEG_MARKER;
340           break;
341         default:
342           assert (opt->argtype != -1);
343           longopt->has_arg = opt->argtype;
344           if (opt->short_name)
345             {
346               if (longopt->has_arg == required_argument)
347                 *p++ = ':';
348               /* Don't handle optional_argument */
349             }
350         }
351     }
352   /* Terminate short_options. */
353   *p = '\0';
354   /* No need for xzero(long_options[o]) because its storage is static
355      and it will be zeroed by default.  */
356   assert (o <= countof (long_options));
357 }
358
359 /* Print the usage message.  */
360 static void
361 print_usage (void)
362 {
363   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
364 }
365
366 /* Print the help message, describing all the available options.  If
367    you add an option, be sure to update this list.  */
368 static void
369 print_help (void)
370 {
371   /* We split the help text this way to ease translation of individual
372      entries.  */
373   static const char *help[] = {
374     "\n",
375     N_("\
376 Mandatory arguments to long options are mandatory for short options too.\n\n"),
377     N_("\
378 Startup:\n"),
379     N_("\
380   -V,  --version           display the version of Wget and exit.\n"),
381     N_("\
382   -h,  --help              print this help.\n"),
383     N_("\
384   -b,  --background        go to background after startup.\n"),
385     N_("\
386   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
387     "\n",
388
389     N_("\
390 Logging and input file:\n"),
391     N_("\
392   -o,  --output-file=FILE    log messages to FILE.\n"),
393     N_("\
394   -a,  --append-output=FILE  append messages to FILE.\n"),
395 #ifdef ENABLE_DEBUG
396     N_("\
397   -d,  --debug               print lots of debugging information.\n"),
398 #endif
399     N_("\
400   -q,  --quiet               quiet (no output).\n"),
401     N_("\
402   -v,  --verbose             be verbose (this is the default).\n"),
403     N_("\
404   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
405     N_("\
406   -i,  --input-file=FILE     download URLs found in FILE.\n"),
407     N_("\
408   -F,  --force-html          treat input file as HTML.\n"),
409     N_("\
410   -B,  --base=URL            prepends URL to relative links in -F -i file.\n"),
411     "\n",
412
413     N_("\
414 Download:\n"),
415     N_("\
416   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
417     N_("\
418        --retry-connrefused       retry even if connection is refused.\n"),
419     N_("\
420   -O,  --output-document=FILE    write documents to FILE.\n"),
421     N_("\
422   -nc, --no-clobber              skip downloads that would download to\n\
423                                  existing files.\n"),
424     N_("\
425   -c,  --continue                resume getting a partially-downloaded file.\n"),
426     N_("\
427        --progress=TYPE           select progress gauge type.\n"),
428     N_("\
429   -N,  --timestamping            don't re-retrieve files unless newer than\n\
430                                  local.\n"),
431     N_("\
432   -S,  --server-response         print server response.\n"),
433     N_("\
434        --spider                  don't download anything.\n"),
435     N_("\
436   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
437     N_("\
438        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
439     N_("\
440        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
441     N_("\
442        --read-timeout=SECS       set the read timeout to SECS.\n"),
443     N_("\
444   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
445     N_("\
446        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
447     N_("\
448        --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
449     N_("\
450   -Y,  --proxy                   explicitly turn on proxy.\n"),
451     N_("\
452        --no-proxy                explicitly turn off proxy.\n"),
453     N_("\
454   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
455     N_("\
456        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
457     N_("\
458        --limit-rate=RATE         limit download rate to RATE.\n"),
459     N_("\
460        --no-dns-cache            disable caching DNS lookups.\n"),
461     N_("\
462        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
463 #ifdef ENABLE_IPV6
464     N_("\
465   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
466     N_("\
467   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
468 #endif
469     "\n",
470
471     N_("\
472 Directories:\n"),
473     N_("\
474   -nd, --no-directories           don't create directories.\n"),
475     N_("\
476   -x,  --force-directories        force creation of directories.\n"),
477     N_("\
478   -nH, --no-host-directories      don't create host directories.\n"),
479     N_("\
480        --protocol-directories     use protocol name in directories.\n"),
481     N_("\
482   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
483     N_("\
484        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
485     "\n",
486
487     N_("\
488 HTTP options:\n"),
489     N_("\
490        --http-user=USER        set http user to USER.\n"),
491     N_("\
492        --http-passwd=PASS      set http password to PASS.\n"),
493     N_("\
494        --no-cache              disallow server-cached data.\n"),
495     N_("\
496   -E,  --html-extension        save HTML documents with `.html' extension.\n"),
497     N_("\
498        --ignore-length         ignore `Content-Length' header field.\n"),
499     N_("\
500        --header=STRING         insert STRING among the headers.\n"),
501     N_("\
502        --proxy-user=USER       set USER as proxy username.\n"),
503     N_("\
504        --proxy-passwd=PASS     set PASS as proxy password.\n"),
505     N_("\
506        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
507     N_("\
508        --save-headers          save the HTTP headers to file.\n"),
509     N_("\
510   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
511     N_("\
512        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
513     N_("\
514        --no-cookies            don't use cookies.\n"),
515     N_("\
516        --load-cookies=FILE     load cookies from FILE before session.\n"),
517     N_("\
518        --save-cookies=FILE     save cookies to FILE after session.\n"),
519     N_("\
520        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
521     N_("\
522        --post-data=STRING      use the POST method; send STRING as the data.\n"),
523     N_("\
524        --post-file=FILE        use the POST method; send contents of FILE.\n"),
525     "\n",
526
527 #ifdef HAVE_SSL
528     N_("\
529 HTTPS (SSL) options:\n"),
530     N_("\
531        --sslcertfile=FILE    optional client certificate.\n"),
532     N_("\
533        --sslcertkey=KEYFILE  optional keyfile for this certificate.\n"),
534     N_("\
535        --egd-file=FILE       file name of the EGD socket.\n"),
536     N_("\
537        --sslcadir=DIR        dir where hash list of CA's are stored.\n"),
538     N_("\
539        --sslcafile=FILE      file with bundle of CA's.\n"),
540     N_("\
541        --sslcerttype=0/1     Client-Cert type 0=PEM (default) / 1=ASN1 (DER).\n"),
542     N_("\
543        --sslcheckcert=0/1    Check the server cert against given CA.\n"),
544     N_("\
545        --sslprotocol=0-3     choose SSL protocol; 0=automatic,\n\
546                              1=SSLv2 2=SSLv3 3=TLSv1.\n"),
547     "\n",
548 #endif /* HAVE_SSL */
549
550     N_("\
551 FTP options:\n"),
552     N_("\
553        --no-remove-listing     don't remove `.listing' files.\n"),
554     N_("\
555        --no-glob               turn off FTP file name globbing.\n"),
556     N_("\
557        --passive-ftp           use the \"passive\" transfer mode.\n"),
558     N_("\
559        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
560     N_("\
561        --preserve-permissions  preserve remote file permissions.\n"),
562     "\n",
563
564     N_("\
565 Recursive download:\n"),
566     N_("\
567   -r,  --recursive          specify recursive download.\n"),
568     N_("\
569   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
570     N_("\
571        --delete-after       delete files locally after downloading them.\n"),
572     N_("\
573   -k,  --convert-links      make links in downloaded HTML point to local files.\n"),
574     N_("\
575   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
576     N_("\
577   -m,  --mirror             shortcut option equivalent to -r -N -l inf -nr.\n"),
578     N_("\
579   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
580     N_("\
581        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
582     "\n",
583
584     N_("\
585 Recursive accept/reject:\n"),
586     N_("\
587   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
588     N_("\
589   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
590     N_("\
591   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
592     N_("\
593        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
594     N_("\
595        --follow-ftp                follow FTP links from HTML documents.\n"),
596     N_("\
597        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
598     N_("\
599        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
600     N_("\
601   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
602     N_("\
603   -L,  --relative                  follow relative links only.\n"),
604     N_("\
605   -I,  --include-directories=LIST  list of allowed directories.\n"),
606     N_("\
607   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
608     N_("\
609   -np, --no-parent                 don't ascend to the parent directory.\n"),
610     "\n",
611
612     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
613   };
614
615   int i;
616
617   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
618           version_string);
619   print_usage ();
620
621   for (i = 0; i < countof (help); i++)
622     fputs (_(help[i]), stdout);
623
624   exit (0);
625 }
626
627 static void
628 print_version (void)
629 {
630   printf ("GNU Wget %s\n\n", version_string);
631   fputs (_("\
632 Copyright (C) 2003 Free Software Foundation, Inc.\n"), stdout);
633   fputs (_("\
634 This program is distributed in the hope that it will be useful,\n\
635 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
636 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
637 GNU General Public License for more details.\n"), stdout);
638   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
639          stdout);
640   exit (0);
641 }
642 \f
643 int
644 main (int argc, char *const *argv)
645 {
646   char **url, **t;
647   int i, ret, longindex;
648   int nurl, status;
649   int append_to_log = 0;
650
651   i18n_initialize ();
652
653   /* Construct the name of the executable, without the directory part.  */
654   exec_name = strrchr (argv[0], PATH_SEPARATOR);
655   if (!exec_name)
656     exec_name = argv[0];
657   else
658     ++exec_name;
659
660 #ifdef WINDOWS
661   windows_main_junk (&argc, (char **) argv, (char **) &exec_name);
662 #endif
663
664   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
665   initialize ();
666
667   init_switches ();
668   longindex = -1;
669   while ((ret = getopt_long (argc, argv,
670                              short_options, long_options, &longindex)) != -1)
671     {
672       int val;
673       struct cmdline_option *opt;
674
675       /* If LONGINDEX is unchanged, it means RET is referring a short
676          option.  */
677       if (longindex == -1)
678         {
679           if (ret == '?')
680             {
681               print_usage ();
682               printf ("\n");
683               printf (_("Try `%s --help' for more options.\n"), exec_name);
684               exit (2);
685             }
686           /* Find the short option character in the mapping.  */
687           longindex = optmap[ret - 32];
688         }
689       val = long_options[longindex].val;
690
691       /* Use the retrieved value to locate the option in the
692          option_data array, and to see if we're dealing with the
693          negated "--no-FOO" variant of the boolean option "--foo".  */
694       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
695       switch (opt->type)
696         {
697         case OPT_VALUE:
698           setoptval (opt->data, optarg);
699           break;
700         case OPT_BOOLEAN:
701           if (optarg)
702             /* The user has specified a value -- use it. */
703             setoptval (opt->data, optarg);
704           else
705             {
706               /* NEG is true for `--no-FOO' style boolean options. */
707               int neg = val & BOOLEAN_NEG_MARKER;
708               setoptval (opt->data, neg ? "0" : "1");
709             }
710           break;
711         case OPT_FUNCALL:
712           {
713             void (*func) PARAMS ((void)) = opt->data;
714             func ();
715           }
716           break;
717         case OPT__APPEND_OUTPUT:
718           setoptval ("logfile", optarg);
719           append_to_log = 1;
720           break;
721         case OPT__EXECUTE:
722           run_command (optarg);
723           break;
724         case OPT__NO:
725           {
726             /* We support real --no-FOO flags now, but keep these
727                short options for convenience and backward
728                compatibility.  */
729             char *p;
730             for (p = optarg; *p; p++)
731               switch (*p)
732                 {
733                 case 'v':
734                   setoptval ("verbose", "0");
735                   break;
736                 case 'H':
737                   setoptval ("addhostdir", "0");
738                   break;
739                 case 'd':
740                   setoptval ("dirstruct", "0");
741                   break;
742                 case 'c':
743                   setoptval ("noclobber", "1");
744                   break;
745                 case 'p':
746                   setoptval ("noparent", "1");
747                   break;
748                 default:
749                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
750                   print_usage ();
751                   printf ("\n");
752                   printf (_("Try `%s --help' for more options.\n"), exec_name);
753                   exit (1);
754                 }
755             break;
756           }
757         case OPT__PARENT:
758         case OPT__CLOBBER:
759           {
760             /* The wgetrc commands are named noparent and noclobber,
761                so we must revert the meaning of the cmdline options
762                before passing the value to setoptval.  */
763             int flag = 1;
764             if (optarg)
765               flag = (*optarg == '1' || TOLOWER (*optarg) == 'y'
766                       || (TOLOWER (optarg[0]) == 'o'
767                           && TOLOWER (optarg[1]) == 'n'));
768             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
769                        flag ? "0" : "1");
770             break;
771           }
772         case OPT__DONT_REMOVE_LISTING:
773           setoptval ("removelisting", "0");
774           break;
775         }
776
777       longindex = -1;
778     }
779
780   /* All user options have now been processed, so it's now safe to do
781      interoption dependency checks. */
782
783   if (opt.reclevel == 0)
784     opt.reclevel = INFINITE_RECURSION;  /* see wget.h for commentary on this */
785
786   if (opt.page_requisites && !opt.recursive)
787     {
788       /* Don't set opt.recursive here because it would confuse the FTP
789          code.  Instead, call retrieve_tree below when either
790          page_requisites or recursive is requested.  */
791       opt.reclevel = 0;
792       if (!opt.no_dirstruct)
793         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
794     }
795
796   if (opt.verbose == -1)
797     opt.verbose = !opt.quiet;
798
799   /* Sanity checks.  */
800   if (opt.verbose && opt.quiet)
801     {
802       printf (_("Can't be verbose and quiet at the same time.\n"));
803       print_usage ();
804       exit (1);
805     }
806   if (opt.timestamping && opt.noclobber)
807     {
808       printf (_("\
809 Can't timestamp and not clobber old files at the same time.\n"));
810       print_usage ();
811       exit (1);
812     }
813 #ifdef ENABLE_IPV6
814   if (opt.ipv4_only && opt.ipv6_only)
815     {
816       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
817       print_usage ();
818       exit (1);
819     }
820 #endif
821
822   nurl = argc - optind;
823   if (!nurl && !opt.input_filename)
824     {
825       /* No URL specified.  */
826       printf (_("%s: missing URL\n"), exec_name);
827       print_usage ();
828       printf ("\n");
829       /* #### Something nicer should be printed here -- similar to the
830          pre-1.5 `--help' page.  */
831       printf (_("Try `%s --help' for more options.\n"), exec_name);
832       exit (1);
833     }
834
835   if (opt.background)
836     fork_to_background ();
837
838   /* Initialize progress.  Have to do this after the options are
839      processed so we know where the log file is.  */
840   if (opt.verbose)
841     set_progress_implementation (opt.progress_type);
842
843   /* Fill in the arguments.  */
844   url = alloca_array (char *, nurl + 1);
845   for (i = 0; i < nurl; i++, optind++)
846     {
847       char *rewritten = rewrite_shorthand_url (argv[optind]);
848       if (rewritten)
849         url[i] = rewritten;
850       else
851         url[i] = xstrdup (argv[optind]);
852     }
853   url[i] = NULL;
854
855   /* Change the title of console window on Windows.  #### I think this
856      statement should belong to retrieve_url().  --hniksic.  */
857 #ifdef WINDOWS
858   ws_changetitle (*url, nurl);
859 #endif
860
861   /* Initialize logging.  */
862   log_init (opt.lfilename, append_to_log);
863
864   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
865            OS_TYPE));
866
867   /* Open the output filename if necessary.  */
868   if (opt.output_document)
869     {
870       extern FILE *output_stream;
871       extern int output_stream_regular;
872
873       if (HYPHENP (opt.output_document))
874         output_stream = stdout;
875       else
876         {
877           struct stat st;
878           output_stream = fopen (opt.output_document,
879                                  opt.always_rest ? "ab" : "wb");
880           if (output_stream == NULL)
881             {
882               perror (opt.output_document);
883               exit (1);
884             }
885           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
886             output_stream_regular = 1;
887         }
888     }
889
890 #ifdef WINDOWS
891   ws_startup ();
892 #endif
893
894   /* Setup the signal handler to redirect output when hangup is
895      received.  */
896 #ifdef HAVE_SIGNAL
897   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
898     signal(SIGHUP, redirect_output_signal);
899   /* ...and do the same for SIGUSR1.  */
900   signal (SIGUSR1, redirect_output_signal);
901   /* Writing to a closed socket normally signals SIGPIPE, and the
902      process exits.  What we want is to ignore SIGPIPE and just check
903      for the return value of write().  */
904   signal (SIGPIPE, SIG_IGN);
905 #ifdef SIGWINCH
906   signal (SIGWINCH, progress_handle_sigwinch);
907 #endif
908 #endif /* HAVE_SIGNAL */
909
910   status = RETROK;              /* initialize it, just-in-case */
911   /* Retrieve the URLs from argument list.  */
912   for (t = url; *t; t++)
913     {
914       char *filename = NULL, *redirected_URL = NULL;
915       int dt;
916
917       if ((opt.recursive || opt.page_requisites)
918           && url_scheme (*t) != SCHEME_FTP)
919         status = retrieve_tree (*t);
920       else
921         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
922
923       if (opt.delete_after && file_exists_p(filename))
924         {
925           DEBUGP (("Removing file due to --delete-after in main():\n"));
926           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
927           if (unlink (filename))
928             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
929         }
930
931       xfree_null (redirected_URL);
932       xfree_null (filename);
933     }
934
935   /* And then from the input file, if any.  */
936   if (opt.input_filename)
937     {
938       int count;
939       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
940       if (!count)
941         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
942                    opt.input_filename);
943     }
944   /* Print the downloaded sum.  */
945   if (opt.recursive || opt.page_requisites
946       || nurl > 1
947       || (opt.input_filename && total_downloaded_bytes != 0))
948     {
949       logprintf (LOG_NOTQUIET,
950                  _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
951                  time_str (NULL), legible_large_int (total_downloaded_bytes),
952                  opt.numurls);
953       /* Print quota warning, if exceeded.  */
954       if (opt.quota && total_downloaded_bytes > opt.quota)
955         logprintf (LOG_NOTQUIET,
956                    _("Download quota (%s bytes) EXCEEDED!\n"),
957                    legible (opt.quota));
958     }
959
960   if (opt.cookies_output && wget_cookie_jar)
961     cookie_jar_save (wget_cookie_jar, opt.cookies_output);
962
963   if (opt.convert_links && !opt.delete_after)
964     convert_all_links ();
965
966   log_close ();
967   for (i = 0; i < nurl; i++)
968     xfree (url[i]);
969   cleanup ();
970
971 #ifdef DEBUG_MALLOC
972   print_malloc_debug_stats ();
973 #endif
974   if (status == RETROK)
975     return 0;
976   else
977     return 1;
978 }
979 \f
980 #ifdef HAVE_SIGNAL
981 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
982    will proceed operation as usual, trying to write into a log file.
983    If that is impossible, the output will be turned off.
984
985    #### It is unsafe to do call libc functions from a signal handler.
986    What we should do is, set a global variable, and have the code in
987    log.c pick it up.  */
988
989 static RETSIGTYPE
990 redirect_output_signal (int sig)
991 {
992   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
993                              (sig == SIGUSR1 ? "SIGUSR1" :
994                               "WTF?!"));
995   log_request_redirect_output (signal_name);
996   progress_schedule_redirect ();
997   signal (sig, redirect_output_signal);
998 }
999 #endif /* HAVE_SIGNAL */