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