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