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