]> sjero.net Git - wget/blob - src/main.c
[svn] Doc fix.
[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   nurl = argc - optind;
810   if (!nurl && !opt.input_filename)
811     {
812       /* No URL specified.  */
813       printf (_("%s: missing URL\n"), exec_name);
814       print_usage ();
815       printf ("\n");
816       /* #### Something nicer should be printed here -- similar to the
817          pre-1.5 `--help' page.  */
818       printf (_("Try `%s --help' for more options.\n"), exec_name);
819       exit (1);
820     }
821
822   if (opt.background)
823     fork_to_background ();
824
825   /* Initialize progress.  Have to do this after the options are
826      processed so we know where the log file is.  */
827   if (opt.verbose)
828     set_progress_implementation (opt.progress_type);
829
830   /* Fill in the arguments.  */
831   url = alloca_array (char *, nurl + 1);
832   for (i = 0; i < nurl; i++, optind++)
833     {
834       char *rewritten = rewrite_shorthand_url (argv[optind]);
835       if (rewritten)
836         url[i] = rewritten;
837       else
838         url[i] = xstrdup (argv[optind]);
839     }
840   url[i] = NULL;
841
842   /* Change the title of console window on Windows.  #### I think this
843      statement should belong to retrieve_url().  --hniksic.  */
844 #ifdef WINDOWS
845   ws_changetitle (*url, nurl);
846 #endif
847
848   /* Initialize logging.  */
849   log_init (opt.lfilename, append_to_log);
850
851   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
852            OS_TYPE));
853
854   /* Open the output filename if necessary.  */
855   if (opt.output_document)
856     {
857       if (HYPHENP (opt.output_document))
858         opt.dfp = stdout;
859       else
860         {
861           struct stat st;
862           opt.dfp = fopen (opt.output_document, opt.always_rest ? "ab" : "wb");
863           if (opt.dfp == NULL)
864             {
865               perror (opt.output_document);
866               exit (1);
867             }
868           if (fstat (fileno (opt.dfp), &st) == 0 && S_ISREG (st.st_mode))
869             opt.od_known_regular = 1;
870         }
871     }
872
873 #ifdef WINDOWS
874   ws_startup ();
875 #endif
876
877   /* Setup the signal handler to redirect output when hangup is
878      received.  */
879 #ifdef HAVE_SIGNAL
880   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
881     signal(SIGHUP, redirect_output_signal);
882   /* ...and do the same for SIGUSR1.  */
883   signal (SIGUSR1, redirect_output_signal);
884   /* Writing to a closed socket normally signals SIGPIPE, and the
885      process exits.  What we want is to ignore SIGPIPE and just check
886      for the return value of write().  */
887   signal (SIGPIPE, SIG_IGN);
888 #ifdef SIGWINCH
889   signal (SIGWINCH, progress_handle_sigwinch);
890 #endif
891 #endif /* HAVE_SIGNAL */
892
893   status = RETROK;              /* initialize it, just-in-case */
894   /* Retrieve the URLs from argument list.  */
895   for (t = url; *t; t++)
896     {
897       char *filename = NULL, *redirected_URL = NULL;
898       int dt;
899
900       if ((opt.recursive || opt.page_requisites)
901           && url_scheme (*t) != SCHEME_FTP)
902         status = retrieve_tree (*t);
903       else
904         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
905
906       if (opt.delete_after && file_exists_p(filename))
907         {
908           DEBUGP (("Removing file due to --delete-after in main():\n"));
909           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
910           if (unlink (filename))
911             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
912         }
913
914       xfree_null (redirected_URL);
915       xfree_null (filename);
916     }
917
918   /* And then from the input file, if any.  */
919   if (opt.input_filename)
920     {
921       int count;
922       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
923       if (!count)
924         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
925                    opt.input_filename);
926     }
927   /* Print the downloaded sum.  */
928   if (opt.recursive || opt.page_requisites
929       || nurl > 1
930       || (opt.input_filename && total_downloaded_bytes != 0))
931     {
932       logprintf (LOG_NOTQUIET,
933                  _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
934                  time_str (NULL), legible_large_int (total_downloaded_bytes),
935                  opt.numurls);
936       /* Print quota warning, if exceeded.  */
937       if (opt.quota && total_downloaded_bytes > opt.quota)
938         logprintf (LOG_NOTQUIET,
939                    _("Download quota (%s bytes) EXCEEDED!\n"),
940                    legible (opt.quota));
941     }
942
943   if (opt.cookies_output && wget_cookie_jar)
944     cookie_jar_save (wget_cookie_jar, opt.cookies_output);
945
946   if (opt.convert_links && !opt.delete_after)
947     convert_all_links ();
948
949   log_close ();
950   for (i = 0; i < nurl; i++)
951     xfree (url[i]);
952   cleanup ();
953
954 #ifdef DEBUG_MALLOC
955   print_malloc_debug_stats ();
956 #endif
957   if (status == RETROK)
958     return 0;
959   else
960     return 1;
961 }
962 \f
963 #ifdef HAVE_SIGNAL
964 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
965    will proceed operation as usual, trying to write into a log file.
966    If that is impossible, the output will be turned off.
967
968    #### It is unsafe to do call libc functions from a signal handler.
969    What we should do is, set a global variable, and have the code in
970    log.c pick it up.  */
971
972 static RETSIGTYPE
973 redirect_output_signal (int sig)
974 {
975   char *signal_name = (sig == SIGHUP ? "SIGHUP" :
976                        (sig == SIGUSR1 ? "SIGUSR1" :
977                         "WTF?!"));
978   log_request_redirect_output (signal_name);
979   progress_schedule_redirect ();
980   signal (sig, redirect_output_signal);
981 }
982 #endif /* HAVE_SIGNAL */