]> sjero.net Git - wget/blob - src/main.c
29eb99d51dec2856a9e884008e887f270d129e95
[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                   explicitly turn on proxy.\n"),
450     N_("\
451        --no-proxy                explicitly turn off proxy.\n"),
452     N_("\
453   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
454     N_("\
455        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
456     N_("\
457        --limit-rate=RATE         limit download rate to RATE.\n"),
458     N_("\
459        --no-dns-cache            disable caching DNS lookups.\n"),
460     N_("\
461        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
462 #ifdef ENABLE_IPV6
463     N_("\
464   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
465     N_("\
466   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
467 #endif
468     "\n",
469
470     N_("\
471 Directories:\n"),
472     N_("\
473   -nd, --no-directories           don't create directories.\n"),
474     N_("\
475   -x,  --force-directories        force creation of directories.\n"),
476     N_("\
477   -nH, --no-host-directories      don't create host directories.\n"),
478     N_("\
479   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
480     N_("\
481        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
482     "\n",
483
484     N_("\
485 HTTP options:\n"),
486     N_("\
487        --http-user=USER        set http user to USER.\n"),
488     N_("\
489        --http-passwd=PASS      set http password to PASS.\n"),
490     N_("\
491        --no-cache              disallow server-cached data.\n"),
492     N_("\
493   -E,  --html-extension        save HTML documents with `.html' extension.\n"),
494     N_("\
495        --ignore-length         ignore `Content-Length' header field.\n"),
496     N_("\
497        --header=STRING         insert STRING among the headers.\n"),
498     N_("\
499        --proxy-user=USER       set USER as proxy username.\n"),
500     N_("\
501        --proxy-passwd=PASS     set PASS as proxy password.\n"),
502     N_("\
503        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
504     N_("\
505        --save-headers          save the HTTP headers to file.\n"),
506     N_("\
507   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
508     N_("\
509        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
510     N_("\
511        --no-cookies            don't use cookies.\n"),
512     N_("\
513        --load-cookies=FILE     load cookies from FILE before session.\n"),
514     N_("\
515        --save-cookies=FILE     save cookies to FILE after session.\n"),
516     N_("\
517        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
518     N_("\
519        --post-data=STRING      use the POST method; send STRING as the data.\n"),
520     N_("\
521        --post-file=FILE        use the POST method; send contents of FILE.\n"),
522     "\n",
523
524 #ifdef HAVE_SSL
525     N_("\
526 HTTPS (SSL) options:\n"),
527     N_("\
528        --sslcertfile=FILE    optional client certificate.\n"),
529     N_("\
530        --sslcertkey=KEYFILE  optional keyfile for this certificate.\n"),
531     N_("\
532        --egd-file=FILE       file name of the EGD socket.\n"),
533     N_("\
534        --sslcadir=DIR        dir where hash list of CA's are stored.\n"),
535     N_("\
536        --sslcafile=FILE      file with bundle of CA's.\n"),
537     N_("\
538        --sslcerttype=0/1     Client-Cert type 0=PEM (default) / 1=ASN1 (DER).\n"),
539     N_("\
540        --sslcheckcert=0/1    Check the server cert against given CA.\n"),
541     N_("\
542        --sslprotocol=0-3     choose SSL protocol; 0=automatic,\n\
543                              1=SSLv2 2=SSLv3 3=TLSv1.\n"),
544     "\n",
545 #endif /* HAVE_SSL */
546
547     N_("\
548 FTP options:\n"),
549     N_("\
550        --no-remove-listing     don't remove `.listing' files.\n"),
551     N_("\
552        --no-glob               turn off FTP file name globbing.\n"),
553     N_("\
554        --passive-ftp           use the \"passive\" transfer mode.\n"),
555     N_("\
556        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
557     N_("\
558        --preserve-permissions  preserve remote file permissions.\n"),
559     "\n",
560
561     N_("\
562 Recursive download:\n"),
563     N_("\
564   -r,  --recursive          specify recursive download.\n"),
565     N_("\
566   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
567     N_("\
568        --delete-after       delete files locally after downloading them.\n"),
569     N_("\
570   -k,  --convert-links      make links in downloaded HTML point to local files.\n"),
571     N_("\
572   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
573     N_("\
574   -m,  --mirror             shortcut option equivalent to -r -N -l inf -nr.\n"),
575     N_("\
576   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
577     N_("\
578        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
579     "\n",
580
581     N_("\
582 Recursive accept/reject:\n"),
583     N_("\
584   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
585     N_("\
586   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
587     N_("\
588   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
589     N_("\
590        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
591     N_("\
592        --follow-ftp                follow FTP links from HTML documents.\n"),
593     N_("\
594        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
595     N_("\
596        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
597     N_("\
598   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
599     N_("\
600   -L,  --relative                  follow relative links only.\n"),
601     N_("\
602   -I,  --include-directories=LIST  list of allowed directories.\n"),
603     N_("\
604   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
605     N_("\
606   -np, --no-parent                 don't ascend to the parent directory.\n"),
607     "\n",
608
609     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
610   };
611
612   int i;
613
614   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
615           version_string);
616   print_usage ();
617
618   for (i = 0; i < countof (help); i++)
619     fputs (_(help[i]), stdout);
620
621 #ifdef WINDOWS
622   ws_help (exec_name);
623 #endif
624   exit (0);
625 }
626
627 static void
628 print_version (void)
629 {
630   printf ("GNU Wget %s\n\n", version_string);
631   fputs (_("\
632 Copyright (C) 2003 Free Software Foundation, Inc.\n"), stdout);
633   fputs (_("\
634 This program is distributed in the hope that it will be useful,\n\
635 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
636 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
637 GNU General Public License for more details.\n"), stdout);
638   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
639          stdout);
640   exit (0);
641 }
642 \f
643 int
644 main (int argc, char *const *argv)
645 {
646   char **url, **t;
647   int i, ret, longindex;
648   int nurl, status;
649   int append_to_log = 0;
650
651   i18n_initialize ();
652
653   /* Construct the name of the executable, without the directory part.  */
654   exec_name = strrchr (argv[0], PATH_SEPARATOR);
655   if (!exec_name)
656     exec_name = argv[0];
657   else
658     ++exec_name;
659
660 #ifdef WINDOWS
661   windows_main_junk (&argc, (char **) argv, (char **) &exec_name);
662 #endif
663
664   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
665   initialize ();
666
667   init_switches ();
668   longindex = -1;
669   while ((ret = getopt_long (argc, argv,
670                              short_options, long_options, &longindex)) != -1)
671     {
672       int val;
673       struct cmdline_option *opt;
674       if (ret == '?')
675         {
676           print_usage ();
677           printf ("\n");
678           printf (_("Try `%s --help' for more options.\n"), exec_name);
679           exit (2);
680         }
681
682       /* If LONGINDEX is unchanged, it means RET is referring a short
683          option.  Look it up in the mapping table.  */
684       if (longindex == -1)
685         longindex = optmap[ret - 32];
686       val = long_options[longindex].val;
687
688       /* Use the retrieved value to locate the option in the
689          option_data array, and to see if we're dealing with the
690          negated "--no-FOO" variant of the boolean option "--foo".  */
691       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
692       switch (opt->type)
693         {
694         case OPT_VALUE:
695           setoptval (opt->data, optarg);
696           break;
697         case OPT_BOOLEAN:
698           if (optarg)
699             /* The user has specified a value -- use it. */
700             setoptval (opt->data, optarg);
701           else
702             {
703               /* NEG is true for `--no-FOO' style boolean options. */
704               int neg = val & BOOLEAN_NEG_MARKER;
705               setoptval (opt->data, neg ? "0" : "1");
706             }
707           break;
708         case OPT_FUNCALL:
709           {
710             void (*func) PARAMS ((void)) = opt->data;
711             func ();
712           }
713           break;
714         case OPT__APPEND_OUTPUT:
715           setoptval ("logfile", optarg);
716           append_to_log = 1;
717           break;
718         case OPT__EXECUTE:
719           run_command (optarg);
720           break;
721         case OPT__NO:
722           {
723             /* We support real --no-FOO flags now, but keep these
724                short options for convenience and backward
725                compatibility.  */
726             char *p;
727             for (p = optarg; *p; p++)
728               switch (*p)
729                 {
730                 case 'v':
731                   setoptval ("verbose", "0");
732                   break;
733                 case 'H':
734                   setoptval ("addhostdir", "0");
735                   break;
736                 case 'd':
737                   setoptval ("dirstruct", "0");
738                   break;
739                 case 'c':
740                   setoptval ("noclobber", "1");
741                   break;
742                 case 'p':
743                   setoptval ("noparent", "1");
744                   break;
745                 default:
746                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
747                   print_usage ();
748                   printf ("\n");
749                   printf (_("Try `%s --help' for more options.\n"), exec_name);
750                   exit (1);
751                 }
752             break;
753           }
754         case OPT__PARENT:
755         case OPT__CLOBBER:
756           {
757             /* The wgetrc commands are named noparent and noclobber,
758                so we must revert the meaning of the cmdline options
759                before passing the value to setoptval.  */
760             int flag = 1;
761             if (optarg)
762               flag = (*optarg == '1' || TOLOWER (*optarg) == 'y'
763                       || (TOLOWER (optarg[0]) == 'o'
764                           && TOLOWER (optarg[1]) == 'n'));
765             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
766                        flag ? "0" : "1");
767             break;
768           }
769         case OPT__DONT_REMOVE_LISTING:
770           setoptval ("removelisting", "0");
771           break;
772         }
773
774       longindex = -1;
775     }
776
777   /* All user options have now been processed, so it's now safe to do
778      interoption dependency checks. */
779
780   if (opt.reclevel == 0)
781     opt.reclevel = INFINITE_RECURSION;  /* see wget.h for commentary on this */
782
783   if (opt.page_requisites && !opt.recursive)
784     {
785       /* Don't set opt.recursive here because it would confuse the FTP
786          code.  Instead, call retrieve_tree below when either
787          page_requisites or recursive is requested.  */
788       opt.reclevel = 0;
789       if (!opt.no_dirstruct)
790         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
791     }
792
793   if (opt.verbose == -1)
794     opt.verbose = !opt.quiet;
795
796   /* Sanity checks.  */
797   if (opt.verbose && opt.quiet)
798     {
799       printf (_("Can't be verbose and quiet at the same time.\n"));
800       print_usage ();
801       exit (1);
802     }
803   if (opt.timestamping && opt.noclobber)
804     {
805       printf (_("\
806 Can't timestamp and not clobber old files at the same time.\n"));
807       print_usage ();
808       exit (1);
809     }
810 #ifdef ENABLE_IPV6
811   if (opt.ipv4_only && opt.ipv6_only)
812     {
813       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
814       print_usage ();
815       exit (1);
816     }
817 #endif
818
819   nurl = argc - optind;
820   if (!nurl && !opt.input_filename)
821     {
822       /* No URL specified.  */
823       printf (_("%s: missing URL\n"), exec_name);
824       print_usage ();
825       printf ("\n");
826       /* #### Something nicer should be printed here -- similar to the
827          pre-1.5 `--help' page.  */
828       printf (_("Try `%s --help' for more options.\n"), exec_name);
829       exit (1);
830     }
831
832   if (opt.background)
833     fork_to_background ();
834
835   /* Initialize progress.  Have to do this after the options are
836      processed so we know where the log file is.  */
837   if (opt.verbose)
838     set_progress_implementation (opt.progress_type);
839
840   /* Fill in the arguments.  */
841   url = alloca_array (char *, nurl + 1);
842   for (i = 0; i < nurl; i++, optind++)
843     {
844       char *rewritten = rewrite_shorthand_url (argv[optind]);
845       if (rewritten)
846         url[i] = rewritten;
847       else
848         url[i] = xstrdup (argv[optind]);
849     }
850   url[i] = NULL;
851
852   /* Change the title of console window on Windows.  #### I think this
853      statement should belong to retrieve_url().  --hniksic.  */
854 #ifdef WINDOWS
855   ws_changetitle (*url, nurl);
856 #endif
857
858   /* Initialize logging.  */
859   log_init (opt.lfilename, append_to_log);
860
861   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
862            OS_TYPE));
863
864   /* Open the output filename if necessary.  */
865   if (opt.output_document)
866     {
867       extern FILE *output_stream;
868       extern int output_stream_regular;
869
870       if (HYPHENP (opt.output_document))
871         output_stream = stdout;
872       else
873         {
874           struct stat st;
875           output_stream = fopen (opt.output_document,
876                                  opt.always_rest ? "ab" : "wb");
877           if (output_stream == NULL)
878             {
879               perror (opt.output_document);
880               exit (1);
881             }
882           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
883             output_stream_regular = 1;
884         }
885     }
886
887 #ifdef WINDOWS
888   ws_startup ();
889 #endif
890
891   /* Setup the signal handler to redirect output when hangup is
892      received.  */
893 #ifdef HAVE_SIGNAL
894   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
895     signal(SIGHUP, redirect_output_signal);
896   /* ...and do the same for SIGUSR1.  */
897   signal (SIGUSR1, redirect_output_signal);
898   /* Writing to a closed socket normally signals SIGPIPE, and the
899      process exits.  What we want is to ignore SIGPIPE and just check
900      for the return value of write().  */
901   signal (SIGPIPE, SIG_IGN);
902 #ifdef SIGWINCH
903   signal (SIGWINCH, progress_handle_sigwinch);
904 #endif
905 #endif /* HAVE_SIGNAL */
906
907   status = RETROK;              /* initialize it, just-in-case */
908   /* Retrieve the URLs from argument list.  */
909   for (t = url; *t; t++)
910     {
911       char *filename = NULL, *redirected_URL = NULL;
912       int dt;
913
914       if ((opt.recursive || opt.page_requisites)
915           && url_scheme (*t) != SCHEME_FTP)
916         status = retrieve_tree (*t);
917       else
918         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
919
920       if (opt.delete_after && file_exists_p(filename))
921         {
922           DEBUGP (("Removing file due to --delete-after in main():\n"));
923           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
924           if (unlink (filename))
925             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
926         }
927
928       xfree_null (redirected_URL);
929       xfree_null (filename);
930     }
931
932   /* And then from the input file, if any.  */
933   if (opt.input_filename)
934     {
935       int count;
936       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
937       if (!count)
938         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
939                    opt.input_filename);
940     }
941   /* Print the downloaded sum.  */
942   if (opt.recursive || opt.page_requisites
943       || nurl > 1
944       || (opt.input_filename && total_downloaded_bytes != 0))
945     {
946       logprintf (LOG_NOTQUIET,
947                  _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
948                  time_str (NULL), legible_large_int (total_downloaded_bytes),
949                  opt.numurls);
950       /* Print quota warning, if exceeded.  */
951       if (opt.quota && total_downloaded_bytes > opt.quota)
952         logprintf (LOG_NOTQUIET,
953                    _("Download quota (%s bytes) EXCEEDED!\n"),
954                    legible (opt.quota));
955     }
956
957   if (opt.cookies_output && wget_cookie_jar)
958     cookie_jar_save (wget_cookie_jar, opt.cookies_output);
959
960   if (opt.convert_links && !opt.delete_after)
961     convert_all_links ();
962
963   log_close ();
964   for (i = 0; i < nurl; i++)
965     xfree (url[i]);
966   cleanup ();
967
968 #ifdef DEBUG_MALLOC
969   print_malloc_debug_stats ();
970 #endif
971   if (status == RETROK)
972     return 0;
973   else
974     return 1;
975 }
976 \f
977 #ifdef HAVE_SIGNAL
978 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
979    will proceed operation as usual, trying to write into a log file.
980    If that is impossible, the output will be turned off.
981
982    #### It is unsafe to do call libc functions from a signal handler.
983    What we should do is, set a global variable, and have the code in
984    log.c pick it up.  */
985
986 static RETSIGTYPE
987 redirect_output_signal (int sig)
988 {
989   char *signal_name = (sig == SIGHUP ? "SIGHUP" :
990                        (sig == SIGUSR1 ? "SIGUSR1" :
991                         "WTF?!"));
992   log_request_redirect_output (signal_name);
993   progress_schedule_redirect ();
994   signal (sig, redirect_output_signal);
995 }
996 #endif /* HAVE_SIGNAL */