]> sjero.net Git - wget/blob - src/main.c
6391ebf2cbd34ad3483d1c87d5b7ff774ac84f3c
[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   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 #ifdef WINDOWS
625   ws_help (exec_name);
626 #endif
627   exit (0);
628 }
629
630 static void
631 print_version (void)
632 {
633   printf ("GNU Wget %s\n\n", version_string);
634   fputs (_("\
635 Copyright (C) 2003 Free Software Foundation, Inc.\n"), stdout);
636   fputs (_("\
637 This program is distributed in the hope that it will be useful,\n\
638 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
639 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
640 GNU General Public License for more details.\n"), stdout);
641   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
642          stdout);
643   exit (0);
644 }
645 \f
646 int
647 main (int argc, char *const *argv)
648 {
649   char **url, **t;
650   int i, ret, longindex;
651   int nurl, status;
652   int append_to_log = 0;
653
654   i18n_initialize ();
655
656   /* Construct the name of the executable, without the directory part.  */
657   exec_name = strrchr (argv[0], PATH_SEPARATOR);
658   if (!exec_name)
659     exec_name = argv[0];
660   else
661     ++exec_name;
662
663 #ifdef WINDOWS
664   windows_main_junk (&argc, (char **) argv, (char **) &exec_name);
665 #endif
666
667   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
668   initialize ();
669
670   init_switches ();
671   longindex = -1;
672   while ((ret = getopt_long (argc, argv,
673                              short_options, long_options, &longindex)) != -1)
674     {
675       int val;
676       struct cmdline_option *opt;
677
678       /* If LONGINDEX is unchanged, it means RET is referring a short
679          option.  */
680       if (longindex == -1)
681         {
682           if (ret == '?')
683             {
684               print_usage ();
685               printf ("\n");
686               printf (_("Try `%s --help' for more options.\n"), exec_name);
687               exit (2);
688             }
689           /* Find the short option character in the mapping.  */
690           longindex = optmap[ret - 32];
691         }
692       val = long_options[longindex].val;
693
694       /* Use the retrieved value to locate the option in the
695          option_data array, and to see if we're dealing with the
696          negated "--no-FOO" variant of the boolean option "--foo".  */
697       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
698       switch (opt->type)
699         {
700         case OPT_VALUE:
701           setoptval (opt->data, optarg);
702           break;
703         case OPT_BOOLEAN:
704           if (optarg)
705             /* The user has specified a value -- use it. */
706             setoptval (opt->data, optarg);
707           else
708             {
709               /* NEG is true for `--no-FOO' style boolean options. */
710               int neg = val & BOOLEAN_NEG_MARKER;
711               setoptval (opt->data, neg ? "0" : "1");
712             }
713           break;
714         case OPT_FUNCALL:
715           {
716             void (*func) PARAMS ((void)) = opt->data;
717             func ();
718           }
719           break;
720         case OPT__APPEND_OUTPUT:
721           setoptval ("logfile", optarg);
722           append_to_log = 1;
723           break;
724         case OPT__EXECUTE:
725           run_command (optarg);
726           break;
727         case OPT__NO:
728           {
729             /* We support real --no-FOO flags now, but keep these
730                short options for convenience and backward
731                compatibility.  */
732             char *p;
733             for (p = optarg; *p; p++)
734               switch (*p)
735                 {
736                 case 'v':
737                   setoptval ("verbose", "0");
738                   break;
739                 case 'H':
740                   setoptval ("addhostdir", "0");
741                   break;
742                 case 'd':
743                   setoptval ("dirstruct", "0");
744                   break;
745                 case 'c':
746                   setoptval ("noclobber", "1");
747                   break;
748                 case 'p':
749                   setoptval ("noparent", "1");
750                   break;
751                 default:
752                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
753                   print_usage ();
754                   printf ("\n");
755                   printf (_("Try `%s --help' for more options.\n"), exec_name);
756                   exit (1);
757                 }
758             break;
759           }
760         case OPT__PARENT:
761         case OPT__CLOBBER:
762           {
763             /* The wgetrc commands are named noparent and noclobber,
764                so we must revert the meaning of the cmdline options
765                before passing the value to setoptval.  */
766             int flag = 1;
767             if (optarg)
768               flag = (*optarg == '1' || TOLOWER (*optarg) == 'y'
769                       || (TOLOWER (optarg[0]) == 'o'
770                           && TOLOWER (optarg[1]) == 'n'));
771             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
772                        flag ? "0" : "1");
773             break;
774           }
775         case OPT__DONT_REMOVE_LISTING:
776           setoptval ("removelisting", "0");
777           break;
778         }
779
780       longindex = -1;
781     }
782
783   /* All user options have now been processed, so it's now safe to do
784      interoption dependency checks. */
785
786   if (opt.reclevel == 0)
787     opt.reclevel = INFINITE_RECURSION;  /* see wget.h for commentary on this */
788
789   if (opt.page_requisites && !opt.recursive)
790     {
791       /* Don't set opt.recursive here because it would confuse the FTP
792          code.  Instead, call retrieve_tree below when either
793          page_requisites or recursive is requested.  */
794       opt.reclevel = 0;
795       if (!opt.no_dirstruct)
796         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
797     }
798
799   if (opt.verbose == -1)
800     opt.verbose = !opt.quiet;
801
802   /* Sanity checks.  */
803   if (opt.verbose && opt.quiet)
804     {
805       printf (_("Can't be verbose and quiet at the same time.\n"));
806       print_usage ();
807       exit (1);
808     }
809   if (opt.timestamping && opt.noclobber)
810     {
811       printf (_("\
812 Can't timestamp and not clobber old files at the same time.\n"));
813       print_usage ();
814       exit (1);
815     }
816 #ifdef ENABLE_IPV6
817   if (opt.ipv4_only && opt.ipv6_only)
818     {
819       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
820       print_usage ();
821       exit (1);
822     }
823 #endif
824
825   nurl = argc - optind;
826   if (!nurl && !opt.input_filename)
827     {
828       /* No URL specified.  */
829       printf (_("%s: missing URL\n"), exec_name);
830       print_usage ();
831       printf ("\n");
832       /* #### Something nicer should be printed here -- similar to the
833          pre-1.5 `--help' page.  */
834       printf (_("Try `%s --help' for more options.\n"), exec_name);
835       exit (1);
836     }
837
838   if (opt.background)
839     fork_to_background ();
840
841   /* Initialize progress.  Have to do this after the options are
842      processed so we know where the log file is.  */
843   if (opt.verbose)
844     set_progress_implementation (opt.progress_type);
845
846   /* Fill in the arguments.  */
847   url = alloca_array (char *, nurl + 1);
848   for (i = 0; i < nurl; i++, optind++)
849     {
850       char *rewritten = rewrite_shorthand_url (argv[optind]);
851       if (rewritten)
852         url[i] = rewritten;
853       else
854         url[i] = xstrdup (argv[optind]);
855     }
856   url[i] = NULL;
857
858   /* Change the title of console window on Windows.  #### I think this
859      statement should belong to retrieve_url().  --hniksic.  */
860 #ifdef WINDOWS
861   ws_changetitle (*url, nurl);
862 #endif
863
864   /* Initialize logging.  */
865   log_init (opt.lfilename, append_to_log);
866
867   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
868            OS_TYPE));
869
870   /* Open the output filename if necessary.  */
871   if (opt.output_document)
872     {
873       extern FILE *output_stream;
874       extern int output_stream_regular;
875
876       if (HYPHENP (opt.output_document))
877         output_stream = stdout;
878       else
879         {
880           struct stat st;
881           output_stream = fopen (opt.output_document,
882                                  opt.always_rest ? "ab" : "wb");
883           if (output_stream == NULL)
884             {
885               perror (opt.output_document);
886               exit (1);
887             }
888           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
889             output_stream_regular = 1;
890         }
891     }
892
893 #ifdef WINDOWS
894   ws_startup ();
895 #endif
896
897   /* Setup the signal handler to redirect output when hangup is
898      received.  */
899 #ifdef HAVE_SIGNAL
900   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
901     signal(SIGHUP, redirect_output_signal);
902   /* ...and do the same for SIGUSR1.  */
903   signal (SIGUSR1, redirect_output_signal);
904   /* Writing to a closed socket normally signals SIGPIPE, and the
905      process exits.  What we want is to ignore SIGPIPE and just check
906      for the return value of write().  */
907   signal (SIGPIPE, SIG_IGN);
908 #ifdef SIGWINCH
909   signal (SIGWINCH, progress_handle_sigwinch);
910 #endif
911 #endif /* HAVE_SIGNAL */
912
913   status = RETROK;              /* initialize it, just-in-case */
914   /* Retrieve the URLs from argument list.  */
915   for (t = url; *t; t++)
916     {
917       char *filename = NULL, *redirected_URL = NULL;
918       int dt;
919
920       if ((opt.recursive || opt.page_requisites)
921           && url_scheme (*t) != SCHEME_FTP)
922         status = retrieve_tree (*t);
923       else
924         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
925
926       if (opt.delete_after && file_exists_p(filename))
927         {
928           DEBUGP (("Removing file due to --delete-after in main():\n"));
929           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
930           if (unlink (filename))
931             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
932         }
933
934       xfree_null (redirected_URL);
935       xfree_null (filename);
936     }
937
938   /* And then from the input file, if any.  */
939   if (opt.input_filename)
940     {
941       int count;
942       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
943       if (!count)
944         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
945                    opt.input_filename);
946     }
947   /* Print the downloaded sum.  */
948   if (opt.recursive || opt.page_requisites
949       || nurl > 1
950       || (opt.input_filename && total_downloaded_bytes != 0))
951     {
952       logprintf (LOG_NOTQUIET,
953                  _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
954                  time_str (NULL), legible_large_int (total_downloaded_bytes),
955                  opt.numurls);
956       /* Print quota warning, if exceeded.  */
957       if (opt.quota && total_downloaded_bytes > opt.quota)
958         logprintf (LOG_NOTQUIET,
959                    _("Download quota (%s bytes) EXCEEDED!\n"),
960                    legible (opt.quota));
961     }
962
963   if (opt.cookies_output && wget_cookie_jar)
964     cookie_jar_save (wget_cookie_jar, opt.cookies_output);
965
966   if (opt.convert_links && !opt.delete_after)
967     convert_all_links ();
968
969   log_close ();
970   for (i = 0; i < nurl; i++)
971     xfree (url[i]);
972   cleanup ();
973
974 #ifdef DEBUG_MALLOC
975   print_malloc_debug_stats ();
976 #endif
977   if (status == RETROK)
978     return 0;
979   else
980     return 1;
981 }
982 \f
983 #ifdef HAVE_SIGNAL
984 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
985    will proceed operation as usual, trying to write into a log file.
986    If that is impossible, the output will be turned off.
987
988    #### It is unsafe to do call libc functions from a signal handler.
989    What we should do is, set a global variable, and have the code in
990    log.c pick it up.  */
991
992 static RETSIGTYPE
993 redirect_output_signal (int sig)
994 {
995   char *signal_name = (sig == SIGHUP ? "SIGHUP" :
996                        (sig == SIGUSR1 ? "SIGUSR1" :
997                         "WTF?!"));
998   log_request_redirect_output (signal_name);
999   progress_schedule_redirect ();
1000   signal (sig, redirect_output_signal);
1001 }
1002 #endif /* HAVE_SIGNAL */