]> sjero.net Git - wget/blob - src/main.c
03bf357b36e58e6ee2b46277dd26c6ef57b4e684
[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 <errno.h>
53
54 #include "wget.h"
55 #include "utils.h"
56 #include "init.h"
57 #include "retr.h"
58 #include "recur.h"
59 #include "host.h"
60 #include "cookies.h"
61 #include "url.h"
62 #include "progress.h"           /* for progress_handle_sigwinch */
63
64 #ifdef HAVE_SSL
65 # include "gen_sslfunc.h"
66 #endif
67
68 /* On GNU system this will include system-wide getopt.h. */
69 #include "getopt.h"
70
71 #ifndef PATH_SEPARATOR
72 # define PATH_SEPARATOR '/'
73 #endif
74
75 extern char *version_string;
76
77 #ifndef errno
78 extern int errno;
79 #endif
80
81 struct options opt;
82
83 extern struct cookie_jar *wget_cookie_jar;
84
85 /* From log.c.  */
86 void log_init PARAMS ((const char *, int));
87 void log_close PARAMS ((void));
88 void log_request_redirect_output PARAMS ((const char *));
89
90 static RETSIGTYPE redirect_output_signal PARAMS ((int));
91
92 const char *exec_name;
93 \f
94 /* Initialize I18N.  The initialization amounts to invoking
95    setlocale(), bindtextdomain() and textdomain().
96    Does nothing if NLS is disabled or missing.  */
97 static void
98 i18n_initialize (void)
99 {
100   /* If HAVE_NLS is defined, assume the existence of the three
101      functions invoked here.  */
102 #ifdef HAVE_NLS
103   /* Set the current locale.  */
104   /* Here we use LC_MESSAGES instead of LC_ALL, for two reasons.
105      First, message catalogs are all of I18N Wget uses anyway.
106      Second, setting LC_ALL has a dangerous potential of messing
107      things up.  For example, when in a foreign locale, Solaris
108      strptime() fails to handle international dates correctly, which
109      makes http_atotm() malfunction.  */
110 #ifdef LC_MESSAGES
111   setlocale (LC_MESSAGES, "");
112   setlocale (LC_CTYPE, "");
113 #else
114   setlocale (LC_ALL, "");
115 #endif
116   /* Set the text message domain.  */
117   bindtextdomain ("wget", LOCALEDIR);
118   textdomain ("wget");
119 #endif /* HAVE_NLS */
120 }
121 \f
122 /* Print the usage message.  */
123 static void
124 print_usage (void)
125 {
126   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
127 }
128
129 /* Print the help message, describing all the available options.  If
130    you add an option, be sure to update this list.  */
131 static void
132 print_help (void)
133 {
134   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
135           version_string);
136   print_usage ();
137   /* Had to split this in parts, so the #@@#%# Ultrix compiler and cpp
138      don't bitch.  Also, it makes translation much easier.  */
139   fputs (_("\
140 \n\
141 Mandatory arguments to long options are mandatory for short options too.\n\
142 \n"), stdout);
143   fputs (_("\
144 Startup:\n\
145   -V,  --version           display the version of Wget and exit.\n\
146   -h,  --help              print this help.\n\
147   -b,  --background        go to background after startup.\n\
148   -e,  --execute=COMMAND   execute a `.wgetrc\'-style command.\n\
149 \n"), stdout);
150   fputs (_("\
151 Logging and input file:\n\
152   -o,  --output-file=FILE     log messages to FILE.\n\
153   -a,  --append-output=FILE   append messages to FILE.\n\
154   -d,  --debug                print debug output.\n\
155   -q,  --quiet                quiet (no output).\n\
156   -v,  --verbose              be verbose (this is the default).\n\
157   -nv, --non-verbose          turn off verboseness, without being quiet.\n\
158   -i,  --input-file=FILE      download URLs found in FILE.\n\
159   -F,  --force-html           treat input file as HTML.\n\
160   -B,  --base=URL             prepends URL to relative links in -F -i file.\n\
161 \n"),stdout);
162   fputs (_("\
163 Download:\n\
164   -t,  --tries=NUMBER           set number of retries to NUMBER (0 unlimits).\n\
165   -O   --output-document=FILE   write documents to FILE.\n\
166   -nc, --no-clobber             don\'t clobber existing files or use .# suffixes.\n\
167   -c,  --continue               resume getting a partially-downloaded file.\n\
168        --progress=TYPE          select progress gauge type.\n\
169   -N,  --timestamping           don\'t re-retrieve files unless newer than local.\n\
170   -S,  --server-response        print server response.\n\
171        --spider                 don\'t download anything.\n\
172   -T,  --timeout=SECONDS        set the read timeout to SECONDS.\n\
173   -w,  --wait=SECONDS           wait SECONDS between retrievals.\n\
174        --waitretry=SECONDS      wait 1...SECONDS between retries of a retrieval.\n\
175        --random-wait            wait from 0...2*WAIT secs between retrievals.\n\
176   -Y,  --proxy=on/off           turn proxy on or off.\n\
177   -Q,  --quota=NUMBER           set retrieval quota to NUMBER.\n\
178        --bind-address=ADDRESS   bind to ADDRESS (hostname or IP) on local host.\n\
179        --limit-rate=RATE        limit download rate to RATE.\n\
180 \n"), stdout);
181   fputs (_("\
182 Directories:\n\
183   -nd  --no-directories            don\'t create directories.\n\
184   -x,  --force-directories         force creation of directories.\n\
185   -nH, --no-host-directories       don\'t create host directories.\n\
186   -P,  --directory-prefix=PREFIX   save files to PREFIX/...\n\
187        --cut-dirs=NUMBER           ignore NUMBER remote directory components.\n\
188 \n"), stdout);
189   fputs (_("\
190 HTTP options:\n\
191        --http-user=USER      set http user to USER.\n\
192        --http-passwd=PASS    set http password to PASS.\n\
193   -C,  --cache=on/off        (dis)allow server-cached data (normally allowed).\n\
194   -E,  --html-extension      save all text/html documents with .html extension.\n\
195        --ignore-length       ignore `Content-Length\' header field.\n\
196        --header=STRING       insert STRING among the headers.\n\
197        --proxy-user=USER     set USER as proxy username.\n\
198        --proxy-passwd=PASS   set PASS as proxy password.\n\
199        --referer=URL         include `Referer: URL\' header in HTTP request.\n\
200   -s,  --save-headers        save the HTTP headers to file.\n\
201   -U,  --user-agent=AGENT    identify as AGENT instead of Wget/VERSION.\n\
202        --no-http-keep-alive  disable HTTP keep-alive (persistent connections).\n\
203        --cookies=off         don't use cookies.\n\
204        --load-cookies=FILE   load cookies from FILE before session.\n\
205        --save-cookies=FILE   save cookies to FILE after session.\n\
206        --post-data=STRING    use the POST method; send STRING as the data.\n\
207        --post-file=FILE      use the POST method; send contents of FILE.\n\
208 \n"), stdout);
209 #ifdef HAVE_SSL
210   fputs (_("\
211 HTTPS (SSL) options:\n\
212        --sslcertfile=FILE     optional client certificate.\n\
213        --sslcertkey=KEYFILE   optional keyfile for this certificate.\n\
214        --egd-file=FILE        file name of the EGD socket.\n\
215        --sslcadir=DIR         dir where hash list of CA's are stured.\n\
216        --sslcafile=FILE       file with bundle of CA's\n\
217        --sslcerttype=0/1      Client-Cert type 0=PEM (default) / 1=ASN1 (DER)\n\
218        --sslcheckcert=0/1     Check the server cert agenst given CA\n\
219        --sslprotocol=0-3      choose SSL protocol; 0=automatic,\n\
220                               1=SSLv2 2=SSLv3 3=TLSv1\n\
221 \n"), stdout);
222 #endif
223   fputs (_("\
224 FTP options:\n\
225   -nr, --dont-remove-listing   don\'t remove `.listing\' files.\n\
226   -g,  --glob=on/off           turn file name globbing on or off.\n\
227        --passive-ftp           use the \"passive\" transfer mode.\n\
228        --retr-symlinks         when recursing, get linked-to files (not dirs).\n\
229 \n"), stdout);
230   fputs (_("\
231 Recursive retrieval:\n\
232   -r,  --recursive          recursive download.\n\
233   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n\
234        --delete-after       delete files locally after downloading them.\n\
235   -k,  --convert-links      convert non-relative links to relative.\n\
236   -K,  --backup-converted   before converting file X, back up as X.orig.\n\
237   -m,  --mirror             shortcut option equivalent to -r -N -l inf -nr.\n\
238   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n\
239 \n"), stdout);
240   fputs (_("\
241 Recursive accept/reject:\n\
242   -A,  --accept=LIST                comma-separated list of accepted extensions.\n\
243   -R,  --reject=LIST                comma-separated list of rejected extensions.\n\
244   -D,  --domains=LIST               comma-separated list of accepted domains.\n\
245        --exclude-domains=LIST       comma-separated list of rejected domains.\n\
246        --follow-ftp                 follow FTP links from HTML documents.\n\
247        --follow-tags=LIST           comma-separated list of followed HTML tags.\n\
248   -G,  --ignore-tags=LIST           comma-separated list of ignored HTML tags.\n\
249   -H,  --span-hosts                 go to foreign hosts when recursive.\n\
250   -L,  --relative                   follow relative links only.\n\
251   -I,  --include-directories=LIST   list of allowed directories.\n\
252   -X,  --exclude-directories=LIST   list of excluded directories.\n\
253   -np, --no-parent                  don\'t ascend to the parent directory.\n\
254 \n"), stdout);
255   fputs (_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n"),
256          stdout);
257 }
258 \f
259 int
260 main (int argc, char *const *argv)
261 {
262   char **url, **t;
263   int i, c, nurl, status, append_to_log;
264
265   static struct option long_options[] =
266   {
267     /* Options without arguments: */
268     { "background", no_argument, NULL, 'b' },
269     { "backup-converted", no_argument, NULL, 'K' },
270     { "continue", no_argument, NULL, 'c' },
271     { "convert-links", no_argument, NULL, 'k' },
272     { "debug", no_argument, NULL, 'd' },
273     { "delete-after", no_argument, NULL, 136 },
274     { "dont-remove-listing", no_argument, NULL, 149 },
275     { "follow-ftp", no_argument, NULL, 142 },
276     { "force-directories", no_argument, NULL, 'x' },
277     { "force-hier", no_argument, NULL, 'x' }, /* obsolete */
278     { "force-html", no_argument, NULL, 'F'},
279     { "help", no_argument, NULL, 'h' },
280     { "html-extension", no_argument, NULL, 'E' },
281     { "ignore-length", no_argument, NULL, 138 },
282     { "mirror", no_argument, NULL, 'm' },
283     { "no-clobber", no_argument, NULL, 141 },
284     { "no-directories", no_argument, NULL, 147 },
285     { "no-host-directories", no_argument, NULL, 148 },
286     { "no-host-lookup", no_argument, NULL, 150 },
287     { "no-http-keep-alive", no_argument, NULL, 156 },
288     { "no-parent", no_argument, NULL, 133 },
289     { "non-verbose", no_argument, NULL, 146 },
290     { "passive-ftp", no_argument, NULL, 139 },
291     { "page-requisites", no_argument, NULL, 'p' },
292     { "quiet", no_argument, NULL, 'q' },
293     { "random-wait", no_argument, NULL, 165 },
294     { "recursive", no_argument, NULL, 'r' },
295     { "relative", no_argument, NULL, 'L' },
296     { "retr-symlinks", no_argument, NULL, 137 },
297     { "save-headers", no_argument, NULL, 's' },
298     { "server-response", no_argument, NULL, 'S' },
299     { "span-hosts", no_argument, NULL, 'H' },
300     { "spider", no_argument, NULL, 132 },
301     { "timestamping", no_argument, NULL, 'N' },
302     { "verbose", no_argument, NULL, 'v' },
303     { "version", no_argument, NULL, 'V' },
304
305     /* Options accepting an argument: */
306     { "accept", required_argument, NULL, 'A' },
307     { "append-output", required_argument, NULL, 'a' },
308     { "backups", required_argument, NULL, 151 }, /* undocumented */
309     { "base", required_argument, NULL, 'B' },
310     { "bind-address", required_argument, NULL, 155 },
311     { "cache", required_argument, NULL, 'C' },
312     { "cookies", required_argument, NULL, 160 },
313     { "cut-dirs", required_argument, NULL, 145 },
314     { "directory-prefix", required_argument, NULL, 'P' },
315     { "domains", required_argument, NULL, 'D' },
316     { "dot-style", required_argument, NULL, 134 },
317     { "execute", required_argument, NULL, 'e' },
318     { "exclude-directories", required_argument, NULL, 'X' },
319     { "exclude-domains", required_argument, NULL, 140 },
320     { "follow-tags", required_argument, NULL, 153 },
321     { "glob", required_argument, NULL, 'g' },
322     { "header", required_argument, NULL, 131 },
323     { "htmlify", required_argument, NULL, 135 },
324     { "http-passwd", required_argument, NULL, 130 },
325     { "http-user", required_argument, NULL, 129 },
326     { "ignore-tags", required_argument, NULL, 'G' },
327     { "include-directories", required_argument, NULL, 'I' },
328     { "input-file", required_argument, NULL, 'i' },
329     { "level", required_argument, NULL, 'l' },
330     { "limit-rate", required_argument, NULL, 164 },
331     { "load-cookies", required_argument, NULL, 161 },
332     { "no", required_argument, NULL, 'n' },
333     { "output-document", required_argument, NULL, 'O' },
334     { "output-file", required_argument, NULL, 'o' },
335     { "post-data", required_argument, NULL, 167 },
336     { "post-file", required_argument, NULL, 168 },
337     { "progress", required_argument, NULL, 163 },
338     { "proxy", required_argument, NULL, 'Y' },
339     { "proxy-passwd", required_argument, NULL, 144 },
340     { "proxy-user", required_argument, NULL, 143 },
341     { "quota", required_argument, NULL, 'Q' },
342     { "reject", required_argument, NULL, 'R' },
343     { "save-cookies", required_argument, NULL, 162 },
344     { "timeout", required_argument, NULL, 'T' },
345     { "tries", required_argument, NULL, 't' },
346     { "user-agent", required_argument, NULL, 'U' },
347     { "referer", required_argument, NULL, 157 },
348     { "use-proxy", required_argument, NULL, 'Y' },
349 #ifdef HAVE_SSL
350     { "sslcertfile", required_argument, NULL, 158 },
351     { "sslcertkey", required_argument, NULL, 159 },
352     { "egd-file", required_argument, NULL, 166 },
353     { "sslcadir",         required_argument, NULL, 169},
354     { "sslcafile",        required_argument, NULL, 170},
355     { "sslcerttype",      required_argument, NULL, 171},
356     { "sslcheckcert",     required_argument, NULL, 172},
357     { "sslprotocol",      required_argument, NULL, 173},
358 #endif /* HAVE_SSL */
359     { "wait", required_argument, NULL, 'w' },
360     { "waitretry", required_argument, NULL, 152 },
361     { 0, 0, 0, 0 }
362   };
363
364   i18n_initialize ();
365
366   append_to_log = 0;
367
368   /* Construct the name of the executable, without the directory part.  */
369   exec_name = strrchr (argv[0], PATH_SEPARATOR);
370   if (!exec_name)
371     exec_name = argv[0];
372   else
373     ++exec_name;
374
375 #ifdef WINDOWS
376   windows_main_junk (&argc, (char **) argv, (char **) &exec_name);
377 #endif
378
379   initialize (); /* sets option defaults; reads the system wgetrc and .wgetrc */
380
381   /* [Is the order of the option letters significant?  If not, they should be
382       alphabetized, like the long_options.  The only thing I know for sure is
383       that the options with required arguments must be followed by a ':'.
384       -- Dan Harkless <wget@harkless.org>] */
385   while ((c = getopt_long (argc, argv, "\
386 hpVqvdkKsxmNWrHSLcFbEY:G:g:T:U:O:l:n:i:o:a:t:D:A:R:P:B:e:Q:X:I:w:C:",
387                            long_options, (int *)0)) != EOF)
388     {
389       switch (c)
390         {
391           /* Options without arguments: */
392         case 132:
393           setval ("spider", "on");
394           break;
395         case 133:
396           setval ("noparent", "on");
397           break;
398         case 136:
399           setval ("deleteafter", "on");
400           break;
401         case 137:
402           setval ("retrsymlinks", "on");
403           break;
404         case 138:
405           setval ("ignorelength", "on");
406           break;
407         case 139:
408           setval ("passiveftp", "on");
409           break;
410         case 141:
411           setval ("noclobber", "on");
412           break;
413         case 142:
414           setval ("followftp", "on");
415           break;
416         case 145:
417           setval ("cutdirs", optarg);
418           break;
419         case 146:
420           setval ("verbose", "off");
421           break;
422         case 147:
423           setval ("dirstruct", "off");
424           break;
425         case 148:
426           setval ("addhostdir", "off");
427           break;
428         case 149:
429           setval ("removelisting", "off");
430           break;
431         case 155:
432           setval ("bindaddress", optarg);
433           break;
434         case 156:
435           setval ("httpkeepalive", "off");
436           break;
437         case 165:
438           setval ("randomwait", "on");
439           break;
440         case 'b':
441           setval ("background", "on");
442           break;
443         case 'c':
444           setval ("continue", "on");
445           break;
446         case 'd':
447 #ifdef DEBUG
448           setval ("debug", "on");
449 #else  /* not DEBUG */
450           fprintf (stderr, _("%s: debug support not compiled in.\n"),
451                    exec_name);
452 #endif /* not DEBUG */
453           break;
454         case 'E':
455           setval ("htmlextension", "on");
456           break;
457         case 'F':
458           setval ("forcehtml", "on");
459           break;
460         case 'H':
461           setval ("spanhosts", "on");
462           break;
463         case 'h':
464           print_help ();
465 #ifdef WINDOWS
466           ws_help (exec_name);
467 #endif
468           exit (0);
469           break;
470         case 'K':
471           setval ("backupconverted", "on");
472           break;
473         case 'k':
474           setval ("convertlinks", "on");
475           break;
476         case 'L':
477           setval ("relativeonly", "on");
478           break;
479         case 'm':
480           setval ("mirror", "on");
481           break;
482         case 'N':
483           setval ("timestamping", "on");
484           break;
485         case 'p':
486           setval ("pagerequisites", "on");
487           break;
488         case 'S':
489           setval ("serverresponse", "on");
490           break;
491         case 's':
492           setval ("saveheaders", "on");
493           break;
494         case 'q':
495           setval ("quiet", "on");
496           break;
497         case 'r':
498           setval ("recursive", "on");
499           break;
500         case 'V':
501           printf ("GNU Wget %s\n\n", version_string);
502           printf ("%s", _("\
503 Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.\n"));
504           printf ("%s", _("\
505 This program is distributed in the hope that it will be useful,\n\
506 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
507 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
508 GNU General Public License for more details.\n"));
509           printf (_("\nOriginally written by Hrvoje Niksic <hniksic@arsdigita.com>.\n"));
510           exit (0);
511           break;
512         case 'v':
513           setval ("verbose", "on");
514           break;
515         case 'x':
516           setval ("dirstruct", "on");
517           break;
518
519           /* Options accepting an argument: */
520         case 129:
521           setval ("httpuser", optarg);
522           break;
523         case 130:
524           setval ("httppasswd", optarg);
525           break;
526         case 131:
527           setval ("header", optarg);
528           break;
529         case 134:
530           setval ("dotstyle", optarg);
531           break;
532         case 135:
533           setval ("htmlify", optarg);
534           break;
535         case 140:
536           setval ("excludedomains", optarg);
537           break;
538         case 143:
539           setval ("proxyuser", optarg);
540           break;
541         case 144:
542           setval ("proxypasswd", optarg);
543           break;
544         case 151:
545           setval ("backups", optarg);
546           break;
547         case 152:
548           setval ("waitretry", optarg);
549           break;
550         case 153:
551           setval ("followtags", optarg);
552           break;
553         case 160:
554           setval ("cookies", optarg);
555           break;
556         case 161:
557           setval ("loadcookies", optarg);
558           break;
559         case 162:
560           setval ("savecookies", optarg);
561           break;
562         case 163:
563           setval ("progress", optarg);
564           break;
565         case 164:
566           setval ("limitrate", optarg);
567           break;
568         case 157:
569           setval ("referer", optarg);
570           break;
571 #ifdef HAVE_SSL
572         case 158:
573           setval ("sslcertfile", optarg);
574           break;
575         case 159:
576           setval ("sslcertkey", optarg);
577           break;
578         case 166:
579           setval ("egdfile", optarg);
580           break;
581         case 169:
582           setval ("sslcadir", optarg);
583           break;
584         case 170:
585           setval ("sslcafile", optarg);
586           break;
587         case 171:
588           setval ("sslcerttype", optarg);
589           break;
590         case 172:
591           setval ("sslcheckcert", optarg);
592           break;
593         case 173:
594           setval ("sslprotocol", optarg);
595           break;
596 #endif /* HAVE_SSL */
597         case 167:
598           setval ("postdata", optarg);
599           break;
600         case 168:
601           setval ("postfile", optarg);
602           break;
603         case 'A':
604           setval ("accept", optarg);
605           break;
606         case 'a':
607           setval ("logfile", optarg);
608           append_to_log = 1;
609           break;
610         case 'B':
611           setval ("base", optarg);
612           break;
613         case 'C':
614           setval ("cache", optarg);
615           break;
616         case 'D':
617           setval ("domains", optarg);
618           break;
619         case 'e':
620           {
621             char *com, *val;
622             if (parse_line (optarg, &com, &val))
623               {
624                 if (!setval (com, val))
625                   exit (1);
626               }
627             else
628               {
629                 fprintf (stderr, _("%s: %s: invalid command\n"), exec_name,
630                          optarg);
631                 exit (1);
632               }
633             xfree (com);
634             xfree (val);
635           }
636           break;
637         case 'G':
638           setval ("ignoretags", optarg);
639           break;
640         case 'g':
641           setval ("glob", optarg);
642           break;
643         case 'I':
644           setval ("includedirectories", optarg);
645           break;
646         case 'i':
647           setval ("input", optarg);
648           break;
649         case 'l':
650           setval ("reclevel", optarg);
651           break;
652         case 'n':
653           {
654             /* #### What we really want here is --no-foo. */
655             char *p;
656
657             for (p = optarg; *p; p++)
658               switch (*p)
659                 {
660                 case 'v':
661                   setval ("verbose", "off");
662                   break;
663                 case 'H':
664                   setval ("addhostdir", "off");
665                   break;
666                 case 'd':
667                   setval ("dirstruct", "off");
668                   break;
669                 case 'c':
670                   setval ("noclobber", "on");
671                   break;
672                 case 'r':
673                   setval ("removelisting", "off");
674                   break;
675                 case 'p':
676                   setval ("noparent", "on");
677                   break;
678                 case 'k':
679                   setval ("httpkeepalive", "off");
680                   break;
681                 default:
682                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
683                   print_usage ();
684                   printf ("\n");
685                   printf (_("Try `%s --help\' for more options.\n"), exec_name);
686                   exit (1);
687                 }
688             break;
689           }
690         case 'O':
691           setval ("outputdocument", optarg);
692           break;
693         case 'o':
694           setval ("logfile", optarg);
695           break;
696         case 'P':
697           setval ("dirprefix", optarg);
698           break;
699         case 'Q':
700           setval ("quota", optarg);
701           break;
702         case 'R':
703           setval ("reject", optarg);
704           break;
705         case 'T':
706           setval ("timeout", optarg);
707           break;
708         case 't':
709           setval ("tries", optarg);
710           break;
711         case 'U':
712           setval ("useragent", optarg);
713           break;
714         case 'w':
715           setval ("wait", optarg);
716           break;
717         case 'X':
718           setval ("excludedirectories", optarg);
719           break;
720         case 'Y':
721           setval ("useproxy", optarg);
722           break;
723
724         case '?':
725           print_usage ();
726           printf ("\n");
727           printf (_("Try `%s --help' for more options.\n"), exec_name);
728           exit (0);
729           break;
730         }
731     }
732
733   /* All user options have now been processed, so it's now safe to do
734      interoption dependency checks. */
735
736   if (opt.reclevel == 0)
737     opt.reclevel = INFINITE_RECURSION;  /* see wget.h for commentary on this */
738
739   if (opt.page_requisites && !opt.recursive)
740     {
741       opt.recursive = TRUE;
742       opt.reclevel = 0;
743       if (!opt.no_dirstruct)
744         opt.dirstruct = TRUE;  /* usually handled by cmd_spec_recursive() */
745     }
746
747   if (opt.verbose == -1)
748     opt.verbose = !opt.quiet;
749
750   /* Sanity checks.  */
751   if (opt.verbose && opt.quiet)
752     {
753       printf (_("Can't be verbose and quiet at the same time.\n"));
754       print_usage ();
755       exit (1);
756     }
757   if (opt.timestamping && opt.noclobber)
758     {
759       printf (_("\
760 Can't timestamp and not clobber old files at the same time.\n"));
761       print_usage ();
762       exit (1);
763     }
764   nurl = argc - optind;
765   if (!nurl && !opt.input_filename)
766     {
767       /* No URL specified.  */
768       printf (_("%s: missing URL\n"), exec_name);
769       print_usage ();
770       printf ("\n");
771       /* #### Something nicer should be printed here -- similar to the
772          pre-1.5 `--help' page.  */
773       printf (_("Try `%s --help' for more options.\n"), exec_name);
774       exit (1);
775     }
776
777   if (opt.background)
778     fork_to_background ();
779
780   /* Initialize progress.  Have to do this after the options are
781      processed so we know where the log file is.  */
782   if (opt.verbose)
783     set_progress_implementation (opt.progress_type);
784
785   /* Allocate basic pointer.  */
786   url = ALLOCA_ARRAY (char *, nurl + 1);
787   /* Fill in the arguments.  */
788   for (i = 0; i < nurl; i++, optind++)
789     {
790       char *rewritten = rewrite_shorthand_url (argv[optind]);
791       if (rewritten)
792         url[i] = rewritten;
793       else
794         url[i] = xstrdup (argv[optind]);
795     }
796   url[i] = NULL;
797
798   /* Change the title of console window on Windows.  #### I think this
799      statement should belong to retrieve_url().  --hniksic.  */
800 #ifdef WINDOWS
801   ws_changetitle (*url, nurl);
802 #endif
803
804   /* Initialize logging.  */
805   log_init (opt.lfilename, append_to_log);
806
807   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
808            OS_TYPE));
809
810   /* Open the output filename if necessary.  */
811   if (opt.output_document)
812     {
813       if (HYPHENP (opt.output_document))
814         opt.dfp = stdout;
815       else
816         {
817           struct stat st;
818           opt.dfp = fopen (opt.output_document, opt.always_rest ? "ab" : "wb");
819           if (opt.dfp == NULL)
820             {
821               perror (opt.output_document);
822               exit (1);
823             }
824           if (fstat (fileno (opt.dfp), &st) == 0 && S_ISREG (st.st_mode))
825             opt.od_known_regular = 1;
826         }
827     }
828
829 #ifdef WINDOWS
830   ws_startup ();
831 #endif
832
833   /* Setup the signal handler to redirect output when hangup is
834      received.  */
835 #ifdef HAVE_SIGNAL
836   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
837     signal(SIGHUP, redirect_output_signal);
838   /* ...and do the same for SIGUSR1.  */
839   signal (SIGUSR1, redirect_output_signal);
840   /* Writing to a closed socket normally signals SIGPIPE, and the
841      process exits.  What we want is to ignore SIGPIPE and just check
842      for the return value of write().  */
843   signal (SIGPIPE, SIG_IGN);
844 #ifdef SIGWINCH
845   signal (SIGWINCH, progress_handle_sigwinch);
846 #endif
847 #endif /* HAVE_SIGNAL */
848
849 #ifdef HAVE_SSL
850   /* Must call this before resolving any URLs because it has the power
851      to disable `https'.  */
852   ssl_init_prng ();
853 #endif
854
855   status = RETROK;              /* initialize it, just-in-case */
856   /* Retrieve the URLs from argument list.  */
857   for (t = url; *t; t++)
858     {
859       char *filename = NULL, *redirected_URL = NULL;
860       int dt;
861
862       if (opt.recursive && url_scheme (*t) != SCHEME_FTP)
863         status = retrieve_tree (*t);
864       else
865         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
866
867       if (opt.delete_after && file_exists_p(filename))
868         {
869           DEBUGP (("Removing file due to --delete-after in main():\n"));
870           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
871           if (unlink (filename))
872             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
873         }
874
875       FREE_MAYBE (redirected_URL);
876       FREE_MAYBE (filename);
877     }
878
879   /* And then from the input file, if any.  */
880   if (opt.input_filename)
881     {
882       int count;
883       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
884       if (!count)
885         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
886                    opt.input_filename);
887     }
888   /* Print the downloaded sum.  */
889   if (opt.recursive
890       || nurl > 1
891       || (opt.input_filename && opt.downloaded != 0))
892     {
893       logprintf (LOG_NOTQUIET,
894                  _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
895                  time_str (NULL),
896                  (opt.downloaded_overflow ?
897                   "<overflow>" : legible_very_long (opt.downloaded)),
898                  opt.numurls);
899       /* Print quota warning, if exceeded.  */
900       if (downloaded_exceeds_quota ())
901         logprintf (LOG_NOTQUIET,
902                    _("Download quota (%s bytes) EXCEEDED!\n"),
903                    legible (opt.quota));
904     }
905
906   if (opt.cookies_output && wget_cookie_jar)
907     cookie_jar_save (wget_cookie_jar, opt.cookies_output);
908
909   if (opt.convert_links && !opt.delete_after)
910     {
911       convert_all_links ();
912     }
913
914   log_close ();
915   for (i = 0; i < nurl; i++)
916     xfree (url[i]);
917   cleanup ();
918
919 #ifdef DEBUG_MALLOC
920   print_malloc_debug_stats ();
921 #endif
922   if (status == RETROK)
923     return 0;
924   else
925     return 1;
926 }
927 \f
928 #ifdef HAVE_SIGNAL
929 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
930    will proceed operation as usual, trying to write into a log file.
931    If that is impossible, the output will be turned off.
932
933    #### It is unsafe to do call libc functions from a signal handler.
934    What we should do is, set a global variable, and have the code in
935    log.c pick it up.  */
936
937 static RETSIGTYPE
938 redirect_output_signal (int sig)
939 {
940   char *signal_name = (sig == SIGHUP ? "SIGHUP" :
941                        (sig == SIGUSR1 ? "SIGUSR1" :
942                         "WTF?!"));
943   log_request_redirect_output (signal_name);
944   progress_schedule_redirect ();
945   signal (sig, redirect_output_signal);
946 }
947 #endif /* HAVE_SIGNAL */