]> sjero.net Git - wget/blob - src/main.c
922d605b2f5c28918b3fa5871ece6620f32f37d3
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Wget.
6
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Wget; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables.  You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL".  If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so.  If you do not wish to do
29 so, delete this exception statement from your version.  */
30
31 #include <config.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif /* HAVE_UNISTD_H */
38 #include <sys/types.h>
39 #ifdef HAVE_STRING_H
40 # include <string.h>
41 #else
42 # include <strings.h>
43 #endif /* HAVE_STRING_H */
44 #ifdef HAVE_SIGNAL_H
45 # include <signal.h>
46 #endif
47 #ifdef HAVE_NLS
48 #ifdef HAVE_LOCALE_H
49 # include <locale.h>
50 #endif /* HAVE_LOCALE_H */
51 #endif /* HAVE_NLS */
52 #include <assert.h>
53
54 #include <errno.h>
55 #ifndef errno
56 extern int errno;
57 #endif
58
59 #include "wget.h"
60 #include "utils.h"
61 #include "init.h"
62 #include "retr.h"
63 #include "recur.h"
64 #include "host.h"
65 #include "cookies.h"
66 #include "url.h"
67 #include "progress.h"           /* for progress_handle_sigwinch */
68 #include "convert.h"
69
70 /* On GNU system this will include system-wide getopt.h. */
71 #include "getopt.h"
72
73 #ifndef PATH_SEPARATOR
74 # define PATH_SEPARATOR '/'
75 #endif
76
77 struct options opt;
78
79 extern LARGE_INT total_downloaded_bytes;
80 extern char *version_string;
81
82 extern struct cookie_jar *wget_cookie_jar;
83
84 /* From log.c.  */
85 void log_init PARAMS ((const char *, int));
86 void log_close PARAMS ((void));
87 void log_request_redirect_output PARAMS ((const char *));
88
89 static RETSIGTYPE redirect_output_signal PARAMS ((int));
90
91 const char *exec_name;
92 \f
93 /* Initialize I18N.  The initialization amounts to invoking
94    setlocale(), bindtextdomain() and textdomain().
95    Does nothing if NLS is disabled or missing.  */
96 static void
97 i18n_initialize (void)
98 {
99   /* If HAVE_NLS is defined, assume the existence of the three
100      functions invoked here.  */
101 #ifdef HAVE_NLS
102   /* Set the current locale.  */
103   /* Here we use LC_MESSAGES instead of LC_ALL, for two reasons.
104      First, message catalogs are all of I18N Wget uses anyway.
105      Second, setting LC_ALL has a dangerous potential of messing
106      things up.  For example, when in a foreign locale, Solaris
107      strptime() fails to handle international dates correctly, which
108      makes http_atotm() malfunction.  */
109 #ifdef LC_MESSAGES
110   setlocale (LC_MESSAGES, "");
111   setlocale (LC_CTYPE, "");
112 #else
113   setlocale (LC_ALL, "");
114 #endif
115   /* Set the text message domain.  */
116   bindtextdomain ("wget", LOCALEDIR);
117   textdomain ("wget");
118 #endif /* HAVE_NLS */
119 }
120 \f
121 /* Definition of command-line options. */
122
123 #ifdef HAVE_SSL
124 # define IF_SSL(x) x
125 #else
126 # define IF_SSL(x) NULL
127 #endif
128
129 #ifdef ENABLE_DEBUG
130 # define IF_DEBUG(x) x
131 #else
132 # define IF_DEBUG(x) NULL
133 #endif
134
135 struct cmdline_option {
136   const char *long_name;
137   char short_name;
138   enum {
139     OPT_VALUE,
140     OPT_BOOLEAN,
141     /* Non-standard options that have to be handled specially in
142        main().  */
143     OPT__APPEND_OUTPUT,
144     OPT__CLOBBER,
145     OPT__EXECUTE,
146     OPT__HELP,
147     OPT__NO,
148     OPT__PARENT,
149     OPT__VERSION
150   } type;
151   const char *handle_cmd;       /* for standard options */
152   int argtype;                  /* for non-standard options */
153 };
154
155 struct cmdline_option option_data[] =
156   {
157     { "accept", 'A', OPT_VALUE, "accept", -1 },
158     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
159     { "background", 'b', OPT_BOOLEAN, "background", -1 },
160     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
161     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
162     { "base", 'B', OPT_VALUE, "base", -1 },
163     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
164     { "cache", 'C', OPT_BOOLEAN, "cache", -1 },
165     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
166     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
167     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
168     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
169     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
170     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
171     { IF_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
172     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
173     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
174     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
175     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
176     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
177     { "domains", 'D', OPT_VALUE, "domains", -1 },
178     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 },
179     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
180     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
181     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
182     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
183     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
184     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
185     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
186     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
187     { "glob", 'g', OPT_BOOLEAN, "glob", -1 },
188     { "header", 0, OPT_VALUE, "header", -1 },
189     { "help", 'h', OPT__HELP, NULL, no_argument },
190     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
191     { "html-extension", 'E', OPT_BOOLEAN, "htmlextension", -1 },
192     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
193     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
194     { "http-passwd", 0, OPT_VALUE, "httppasswd", -1 },
195     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
196     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
197     { "ignore-tags", 'G', OPT_VALUE, "ignoretags", -1 },
198     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
199     { "input-file", 'i', OPT_VALUE, "input", -1 },
200     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
201     { "level", 'l', OPT_VALUE, "reclevel", -1 },
202     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
203     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
204     { "mirror", 'm', OPT_BOOLEAN, NULL, -1 },
205     { "no", 'n', OPT__NO, NULL, required_argument },
206     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
207     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
208     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
209     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
210     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
211     { "parent", 0, OPT__PARENT, NULL, optional_argument },
212     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
213     { "post-data", 0, OPT_VALUE, "postdata", -1 },
214     { "post-file", 0, OPT_VALUE, "postfile", -1 },
215     { "progress", 0, OPT_VALUE, "progress", -1 },
216     { "proxy", 'Y', OPT_BOOLEAN, "useproxy", -1 },
217     { "proxy-passwd", 0, OPT_VALUE, "proxypasswd", -1 },
218     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
219     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
220     { "quota", 'Q', OPT_VALUE, "quota", -1 },
221     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
222     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
223     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
224     { "referer", 0, OPT_VALUE, "referer", -1 },
225     { "reject", 'R', OPT_VALUE, "reject", -1 },
226     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
227     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
228     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
229     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
230     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
231     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
232     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
233     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
234     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
235     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
236     { IF_SSL ("sslcadir"), 0, OPT_VALUE, "sslcadir", -1 },
237     { IF_SSL ("sslcafile"), 0, OPT_VALUE, "sslcafile", -1 },
238     { IF_SSL ("sslcertfile"), 0, OPT_VALUE, "sslcertfile", -1 },
239     { IF_SSL ("sslcertkey"), 0, OPT_VALUE, "sslcertkey", -1 },
240     { IF_SSL ("sslcerttype"), 0, OPT_VALUE, "sslcerttype", -1 },
241     { IF_SSL ("sslcheckcert"), 0, OPT_VALUE, "sslcheckcert", -1 },
242     { IF_SSL ("sslprotocol"), 0, OPT_VALUE, "sslprotocol", -1 },
243     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
244     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
245     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
246     { "tries", 't', OPT_VALUE, "tries", -1 },
247     { "use-proxy", 'Y', OPT_BOOLEAN, "useproxy", -1 },
248     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
249     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
250     { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
251     { "version", 'V', OPT__VERSION, "version", no_argument },
252     { "wait", 'w', OPT_VALUE, "wait", -1 },
253     { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
254   };
255
256 #undef IF_DEBUG
257 #undef IF_SSL
258
259 static char *
260 no_prefix (const char *s)
261 {
262   static char buffer[1024];
263   static char *p = buffer;
264
265   char *cp = p;
266   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
267
268   if (p + size >= buffer + sizeof (buffer))
269     abort ();
270
271   cp[0] = 'n';
272   cp[1] = 'o';
273   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 static void
290 init_switches (void)
291 {
292   char *p = short_options;
293   int i, o = 0;
294   for (i = 0; i < countof (option_data); i++)
295     {
296       struct cmdline_option *opt = &option_data[i];
297       struct option *longopt;
298
299       if (!opt->long_name)
300         /* The option is disabled. */
301         continue;
302
303       longopt = &long_options[o++];
304       longopt->name = opt->long_name;
305       longopt->val = i;
306       if (opt->short_name)
307         {
308           *p++ = opt->short_name;
309           optmap[opt->short_name - 32] = longopt - long_options;
310         }
311       switch (opt->type)
312         {
313         case OPT_VALUE:
314           longopt->has_arg = required_argument;
315           if (opt->short_name)
316             *p++ = ':';
317           break;
318         case OPT_BOOLEAN:
319           /* Don't specify optional arguments for boolean short
320              options.  They are evil because they prevent combining of
321              short options.  */
322           longopt->has_arg = optional_argument;
323           /* For Boolean options, add the "--no-FOO" variant, which is
324              identical to "--foo", except it has opposite meaning and
325              it doesn't allow an argument.  */
326           longopt = &long_options[o++];
327           longopt->name = no_prefix (opt->long_name);
328           longopt->has_arg = no_argument;
329           /* Mask the value so we'll be able to recognize that we're
330              dealing with the false value.  */
331           longopt->val = i | BOOLEAN_NEG_MARKER;
332           break;
333         default:
334           assert (opt->argtype != -1);
335           longopt->has_arg = opt->argtype;
336           if (opt->short_name)
337             {
338               if (longopt->has_arg == required_argument)
339                 *p++ = ':';
340               /* Don't handle optional_argument */
341             }
342         }
343     }
344   xzero (long_options[o]);
345   *p = '\0';
346 }
347
348 /* Print the usage message.  */
349 static void
350 print_usage (void)
351 {
352   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
353 }
354
355 /* Print the help message, describing all the available options.  If
356    you add an option, be sure to update this list.  */
357 static void
358 print_help (void)
359 {
360   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
361           version_string);
362   print_usage ();
363   /* Had to split this in parts, so the #@@#%# Ultrix compiler and cpp
364      don't bitch.  Also, it makes translation much easier.  */
365   fputs (_("\
366 \n\
367 Mandatory arguments to long options are mandatory for short options too.\n\
368 \n"), stdout);
369   fputs (_("\
370 Startup:\n\
371   -V,  --version           display the version of Wget and exit.\n\
372   -h,  --help              print this help.\n\
373   -b,  --background        go to background after startup.\n\
374   -e,  --execute=COMMAND   execute a `.wgetrc\'-style command.\n\
375 \n"), stdout);
376   fputs (_("\
377 Logging and input file:\n\
378   -o,  --output-file=FILE     log messages to FILE.\n\
379   -a,  --append-output=FILE   append messages to FILE.\n\
380   -d,  --debug                print debug output.\n\
381   -q,  --quiet                quiet (no output).\n\
382   -v,  --verbose              be verbose (this is the default).\n\
383   -nv, --non-verbose          turn off verboseness, without being quiet.\n\
384   -i,  --input-file=FILE      download URLs found in FILE.\n\
385   -F,  --force-html           treat input file as HTML.\n\
386   -B,  --base=URL             prepends URL to relative links in -F -i file.\n\
387 \n"),stdout);
388   fputs (_("\
389 Download:\n\
390   -t,  --tries=NUMBER           set number of retries to NUMBER (0 unlimits).\n\
391        --retry-connrefused      retry even if connection is refused.\n\
392   -O   --output-document=FILE   write documents to FILE.\n\
393   -nc, --no-clobber             don\'t clobber existing files or use .# suffixes.\n\
394   -c,  --continue               resume getting a partially-downloaded file.\n\
395        --progress=TYPE          select progress gauge type.\n\
396   -N,  --timestamping           don\'t re-retrieve files unless newer than local.\n\
397   -S,  --server-response        print server response.\n\
398        --spider                 don\'t download anything.\n\
399   -T,  --timeout=SECONDS        set all timeout values to SECONDS.\n\
400        --dns-timeout=SECS       set the DNS lookup timeout to SECS.\n\
401        --connect-timeout=SECS   set the connect timeout to SECS.\n\
402        --read-timeout=SECS      set the read timeout to SECS.\n\
403   -w,  --wait=SECONDS           wait SECONDS between retrievals.\n\
404        --waitretry=SECONDS      wait 1...SECONDS between retries of a retrieval.\n\
405        --random-wait            wait from 0...2*WAIT secs between retrievals.\n\
406   -Y,  --proxy=on/off           turn proxy on or off.\n\
407   -Q,  --quota=NUMBER           set retrieval quota to NUMBER.\n\
408        --bind-address=ADDRESS   bind to ADDRESS (hostname or IP) on local host.\n\
409        --limit-rate=RATE        limit download rate to RATE.\n\
410        --dns-cache=off          disable caching DNS lookups.\n\
411        --restrict-file-names=OS restrict chars in file names to ones OS allows.\n\
412 \n"), stdout);
413   fputs (_("\
414 Directories:\n\
415   -nd, --no-directories            don\'t create directories.\n\
416   -x,  --force-directories         force creation of directories.\n\
417   -nH, --no-host-directories       don\'t create host directories.\n\
418   -P,  --directory-prefix=PREFIX   save files to PREFIX/...\n\
419        --cut-dirs=NUMBER           ignore NUMBER remote directory components.\n\
420 \n"), stdout);
421   fputs (_("\
422 HTTP options:\n\
423        --http-user=USER      set http user to USER.\n\
424        --http-passwd=PASS    set http password to PASS.\n\
425   -C,  --cache=on/off        (dis)allow server-cached data (normally allowed).\n\
426   -E,  --html-extension      save all text/html documents with .html extension.\n\
427        --ignore-length       ignore `Content-Length\' header field.\n\
428        --header=STRING       insert STRING among the headers.\n\
429        --proxy-user=USER     set USER as proxy username.\n\
430        --proxy-passwd=PASS   set PASS as proxy password.\n\
431        --referer=URL         include `Referer: URL\' header in HTTP request.\n\
432   -s,  --save-headers        save the HTTP headers to file.\n\
433   -U,  --user-agent=AGENT    identify as AGENT instead of Wget/VERSION.\n\
434        --no-http-keep-alive  disable HTTP keep-alive (persistent connections).\n\
435        --cookies=off         don't use cookies.\n\
436        --load-cookies=FILE   load cookies from FILE before session.\n\
437        --save-cookies=FILE   save cookies to FILE after session.\n\
438        --keep-session-cookies  load and save session (non-permanent) cookies.\n\
439        --post-data=STRING    use the POST method; send STRING as the data.\n\
440        --post-file=FILE      use the POST method; send contents of FILE.\n\
441 \n"), stdout);
442 #ifdef HAVE_SSL
443   fputs (_("\
444 HTTPS (SSL) options:\n\
445        --sslcertfile=FILE     optional client certificate.\n\
446        --sslcertkey=KEYFILE   optional keyfile for this certificate.\n\
447        --egd-file=FILE        file name of the EGD socket.\n\
448        --sslcadir=DIR         dir where hash list of CA's are stored.\n\
449        --sslcafile=FILE       file with bundle of CA's\n\
450        --sslcerttype=0/1      Client-Cert type 0=PEM (default) / 1=ASN1 (DER)\n\
451        --sslcheckcert=0/1     Check the server cert agenst given CA\n\
452        --sslprotocol=0-3      choose SSL protocol; 0=automatic,\n\
453                               1=SSLv2 2=SSLv3 3=TLSv1\n\
454 \n"), stdout);
455 #endif
456   fputs (_("\
457 FTP options:\n\
458   -nr, --dont-remove-listing   don\'t remove `.listing\' files.\n\
459   -g,  --glob=on/off           turn file name globbing on or off.\n\
460        --passive-ftp           use the \"passive\" transfer mode.\n\
461        --retr-symlinks         when recursing, get linked-to files (not dirs).\n\
462 \n"), stdout);
463   fputs (_("\
464 Recursive retrieval:\n\
465   -r,  --recursive          recursive download.\n\
466   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n\
467        --delete-after       delete files locally after downloading them.\n\
468   -k,  --convert-links      convert non-relative links to relative.\n\
469   -K,  --backup-converted   before converting file X, back up as X.orig.\n\
470   -m,  --mirror             shortcut option equivalent to -r -N -l inf -nr.\n\
471   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n\
472        --strict-comments    turn on strict (SGML) handling of HTML comments.\n\
473 \n"), stdout);
474   fputs (_("\
475 Recursive accept/reject:\n\
476   -A,  --accept=LIST                comma-separated list of accepted extensions.\n\
477   -R,  --reject=LIST                comma-separated list of rejected extensions.\n\
478   -D,  --domains=LIST               comma-separated list of accepted domains.\n\
479        --exclude-domains=LIST       comma-separated list of rejected domains.\n\
480        --follow-ftp                 follow FTP links from HTML documents.\n\
481        --follow-tags=LIST           comma-separated list of followed HTML tags.\n\
482   -G,  --ignore-tags=LIST           comma-separated list of ignored HTML tags.\n\
483   -H,  --span-hosts                 go to foreign hosts when recursive.\n\
484   -L,  --relative                   follow relative links only.\n\
485   -I,  --include-directories=LIST   list of allowed directories.\n\
486   -X,  --exclude-directories=LIST   list of excluded directories.\n\
487   -np, --no-parent                  don\'t ascend to the parent directory.\n\
488 \n"), stdout);
489   fputs (_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n"),
490          stdout);
491 }
492 \f
493 int
494 main (int argc, char *const *argv)
495 {
496   char **url, **t;
497   int i, ret, longindex;
498   int nurl, status;
499   int append_to_log = 0;
500
501   i18n_initialize ();
502
503   /* Construct the name of the executable, without the directory part.  */
504   exec_name = strrchr (argv[0], PATH_SEPARATOR);
505   if (!exec_name)
506     exec_name = argv[0];
507   else
508     ++exec_name;
509
510 #ifdef WINDOWS
511   windows_main_junk (&argc, (char **) argv, (char **) &exec_name);
512 #endif
513
514   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
515   initialize ();
516
517   init_switches ();
518   longindex = -1;
519   while ((ret = getopt_long (argc, argv,
520                              short_options, long_options, &longindex)) != -1)
521     {
522       int val;
523       struct cmdline_option *opt;
524       if (ret == '?')
525         {
526           print_usage ();
527           printf ("\n");
528           printf (_("Try `%s --help' for more options.\n"), exec_name);
529           exit (2);
530         }
531
532       /* If LONGINDEX is unchanged, it means RET is referring a short
533          option.  Look it up in the mapping table.  */
534       if (longindex == -1)
535         longindex = optmap[ret - 32];
536       val = long_options[longindex].val;
537
538       /* Use the retrieved value to locate the option in the
539          option_data array, and to see if we're dealing with the
540          negated "--no-FOO" variant of the boolean option "--foo".  */
541       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
542       switch (opt->type)
543         {
544         case OPT_VALUE:
545           setoptval (opt->handle_cmd, optarg);
546           break;
547         case OPT_BOOLEAN:
548           if (optarg)
549             /* The user has specified a value -- use it. */
550             setoptval (opt->handle_cmd, optarg);
551           else
552             {
553               /* NEG is true for `--no-FOO' style boolean options. */
554               int neg = val & BOOLEAN_NEG_MARKER;
555               setoptval (opt->handle_cmd, neg ? "0" : "1");
556             }
557           break;
558         case OPT__APPEND_OUTPUT:
559           setoptval ("logfile", optarg);
560           append_to_log = 1;
561           break;
562         case OPT__HELP:
563           print_help ();
564 #ifdef WINDOWS
565           ws_help (exec_name);
566 #endif
567           exit (0);
568           break;
569         case OPT__EXECUTE:
570           run_command (optarg);
571           break;
572         case OPT__NO:
573           {
574             /* We support real --no-FOO flags now, but keep these
575                short options for convenience and backward
576                compatibility.  */
577             char *p;
578             for (p = optarg; *p; p++)
579               switch (*p)
580                 {
581                 case 'v':
582                   setoptval ("verbose", "0");
583                   break;
584                 case 'H':
585                   setoptval ("addhostdir", "0");
586                   break;
587                 case 'd':
588                   setoptval ("dirstruct", "0");
589                   break;
590                 case 'c':
591                   setoptval ("noclobber", "1");
592                   break;
593                 case 'p':
594                   setoptval ("noparent", "1");
595                   break;
596                 default:
597                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
598                   print_usage ();
599                   printf ("\n");
600                   printf (_("Try `%s --help\' for more options.\n"), exec_name);
601                   exit (1);
602                 }
603             break;
604           }
605         case OPT__PARENT:
606         case OPT__CLOBBER:
607           {
608             /* The wgetrc commands are named noparent and noclobber,
609                so we must revert the meaning of the cmdline options
610                before passing the value to setoptval.  */
611             int flag = 1;
612             if (optarg)
613               flag = (*optarg == '1' || TOLOWER (*optarg) == 'y'
614                       || (TOLOWER (optarg[0]) == 'o'
615                           && TOLOWER (optarg[1]) == 'n'));
616             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
617                        flag ? "0" : "1");
618             break;
619           }
620         case OPT__VERSION:
621           printf ("GNU Wget %s\n\n", version_string);
622           printf ("%s", _("\
623 Copyright (C) 2003 Free Software Foundation, Inc.\n"));
624           printf ("%s", _("\
625 This program is distributed in the hope that it will be useful,\n\
626 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
627 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
628 GNU General Public License for more details.\n"));
629           printf (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"));
630           exit (0);
631           break;
632         }
633
634       longindex = -1;
635     }
636
637   /* All user options have now been processed, so it's now safe to do
638      interoption dependency checks. */
639
640   if (opt.reclevel == 0)
641     opt.reclevel = INFINITE_RECURSION;  /* see wget.h for commentary on this */
642
643   if (opt.page_requisites && !opt.recursive)
644     {
645       /* Don't set opt.recursive here because it would confuse the FTP
646          code.  Instead, call retrieve_tree below when either
647          page_requisites or recursive is requested.  */
648       opt.reclevel = 0;
649       if (!opt.no_dirstruct)
650         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
651     }
652
653   if (opt.verbose == -1)
654     opt.verbose = !opt.quiet;
655
656   /* Sanity checks.  */
657   if (opt.verbose && opt.quiet)
658     {
659       printf (_("Can't be verbose and quiet at the same time.\n"));
660       print_usage ();
661       exit (1);
662     }
663   if (opt.timestamping && opt.noclobber)
664     {
665       printf (_("\
666 Can't timestamp and not clobber old files at the same time.\n"));
667       print_usage ();
668       exit (1);
669     }
670   nurl = argc - optind;
671   if (!nurl && !opt.input_filename)
672     {
673       /* No URL specified.  */
674       printf (_("%s: missing URL\n"), exec_name);
675       print_usage ();
676       printf ("\n");
677       /* #### Something nicer should be printed here -- similar to the
678          pre-1.5 `--help' page.  */
679       printf (_("Try `%s --help' for more options.\n"), exec_name);
680       exit (1);
681     }
682
683   if (opt.background)
684     fork_to_background ();
685
686   /* Initialize progress.  Have to do this after the options are
687      processed so we know where the log file is.  */
688   if (opt.verbose)
689     set_progress_implementation (opt.progress_type);
690
691   /* Fill in the arguments.  */
692   url = alloca_array (char *, nurl + 1);
693   for (i = 0; i < nurl; i++, optind++)
694     {
695       char *rewritten = rewrite_shorthand_url (argv[optind]);
696       if (rewritten)
697         url[i] = rewritten;
698       else
699         url[i] = xstrdup (argv[optind]);
700     }
701   url[i] = NULL;
702
703   /* Change the title of console window on Windows.  #### I think this
704      statement should belong to retrieve_url().  --hniksic.  */
705 #ifdef WINDOWS
706   ws_changetitle (*url, nurl);
707 #endif
708
709   /* Initialize logging.  */
710   log_init (opt.lfilename, append_to_log);
711
712   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
713            OS_TYPE));
714
715   /* Open the output filename if necessary.  */
716   if (opt.output_document)
717     {
718       if (HYPHENP (opt.output_document))
719         opt.dfp = stdout;
720       else
721         {
722           struct stat st;
723           opt.dfp = fopen (opt.output_document, opt.always_rest ? "ab" : "wb");
724           if (opt.dfp == NULL)
725             {
726               perror (opt.output_document);
727               exit (1);
728             }
729           if (fstat (fileno (opt.dfp), &st) == 0 && S_ISREG (st.st_mode))
730             opt.od_known_regular = 1;
731         }
732     }
733
734 #ifdef WINDOWS
735   ws_startup ();
736 #endif
737
738   /* Setup the signal handler to redirect output when hangup is
739      received.  */
740 #ifdef HAVE_SIGNAL
741   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
742     signal(SIGHUP, redirect_output_signal);
743   /* ...and do the same for SIGUSR1.  */
744   signal (SIGUSR1, redirect_output_signal);
745   /* Writing to a closed socket normally signals SIGPIPE, and the
746      process exits.  What we want is to ignore SIGPIPE and just check
747      for the return value of write().  */
748   signal (SIGPIPE, SIG_IGN);
749 #ifdef SIGWINCH
750   signal (SIGWINCH, progress_handle_sigwinch);
751 #endif
752 #endif /* HAVE_SIGNAL */
753
754   status = RETROK;              /* initialize it, just-in-case */
755   /* Retrieve the URLs from argument list.  */
756   for (t = url; *t; t++)
757     {
758       char *filename = NULL, *redirected_URL = NULL;
759       int dt;
760
761       if ((opt.recursive || opt.page_requisites)
762           && url_scheme (*t) != SCHEME_FTP)
763         status = retrieve_tree (*t);
764       else
765         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
766
767       if (opt.delete_after && file_exists_p(filename))
768         {
769           DEBUGP (("Removing file due to --delete-after in main():\n"));
770           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
771           if (unlink (filename))
772             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
773         }
774
775       xfree_null (redirected_URL);
776       xfree_null (filename);
777     }
778
779   /* And then from the input file, if any.  */
780   if (opt.input_filename)
781     {
782       int count;
783       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
784       if (!count)
785         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
786                    opt.input_filename);
787     }
788   /* Print the downloaded sum.  */
789   if (opt.recursive || opt.page_requisites
790       || nurl > 1
791       || (opt.input_filename && total_downloaded_bytes != 0))
792     {
793       logprintf (LOG_NOTQUIET,
794                  _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
795                  time_str (NULL), legible_large_int (total_downloaded_bytes),
796                  opt.numurls);
797       /* Print quota warning, if exceeded.  */
798       if (opt.quota && total_downloaded_bytes > opt.quota)
799         logprintf (LOG_NOTQUIET,
800                    _("Download quota (%s bytes) EXCEEDED!\n"),
801                    legible (opt.quota));
802     }
803
804   if (opt.cookies_output && wget_cookie_jar)
805     cookie_jar_save (wget_cookie_jar, opt.cookies_output);
806
807   if (opt.convert_links && !opt.delete_after)
808     convert_all_links ();
809
810   log_close ();
811   for (i = 0; i < nurl; i++)
812     xfree (url[i]);
813   cleanup ();
814
815 #ifdef DEBUG_MALLOC
816   print_malloc_debug_stats ();
817 #endif
818   if (status == RETROK)
819     return 0;
820   else
821     return 1;
822 }
823 \f
824 #ifdef HAVE_SIGNAL
825 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
826    will proceed operation as usual, trying to write into a log file.
827    If that is impossible, the output will be turned off.
828
829    #### It is unsafe to do call libc functions from a signal handler.
830    What we should do is, set a global variable, and have the code in
831    log.c pick it up.  */
832
833 static RETSIGTYPE
834 redirect_output_signal (int sig)
835 {
836   char *signal_name = (sig == SIGHUP ? "SIGHUP" :
837                        (sig == SIGUSR1 ? "SIGUSR1" :
838                         "WTF?!"));
839   log_request_redirect_output (signal_name);
840   progress_schedule_redirect ();
841   signal (sig, redirect_output_signal);
842 }
843 #endif /* HAVE_SIGNAL */