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