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