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