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