]> sjero.net Git - wget/blob - src/init.c
[svn] Enabled separation of different timeout values.
[wget] / src / init.c
1 /* Reading/parsing the initialization file.
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 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 <sys/types.h>
35 #include <stdlib.h>
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #ifdef HAVE_STRING_H
40 # include <string.h>
41 #else
42 # include <strings.h>
43 #endif
44 #include <errno.h>
45
46 #ifdef WINDOWS
47 # include <winsock.h>
48 #else
49 # include <sys/socket.h>
50 # include <netinet/in.h>
51 #ifndef __BEOS__
52 # include <arpa/inet.h>
53 #endif
54 #endif
55
56 #ifdef HAVE_PWD_H
57 # include <pwd.h>
58 #endif
59 #include <assert.h>
60
61 #include "wget.h"
62 #include "utils.h"
63 #include "init.h"
64 #include "host.h"
65 #include "recur.h"
66 #include "netrc.h"
67 #include "cookies.h"            /* for cookie_jar_delete */
68 #include "progress.h"
69
70 #ifndef errno
71 extern int errno;
72 #endif
73
74 extern struct cookie_jar *wget_cookie_jar;
75
76 /* We want tilde expansion enabled only when reading `.wgetrc' lines;
77    otherwise, it will be performed by the shell.  This variable will
78    be set by the wgetrc-reading function.  */
79
80 static int enable_tilde_expansion;
81
82
83 #define CMD_DECLARE(func) static int func \
84   PARAMS ((const char *, const char *, void *))
85
86 CMD_DECLARE (cmd_boolean);
87 CMD_DECLARE (cmd_bytes);
88 CMD_DECLARE (cmd_directory_vector);
89 CMD_DECLARE (cmd_lockable_boolean);
90 CMD_DECLARE (cmd_number);
91 CMD_DECLARE (cmd_number_inf);
92 CMD_DECLARE (cmd_string);
93 CMD_DECLARE (cmd_file);
94 CMD_DECLARE (cmd_directory);
95 CMD_DECLARE (cmd_time);
96 CMD_DECLARE (cmd_vector);
97
98 CMD_DECLARE (cmd_spec_dirstruct);
99 CMD_DECLARE (cmd_spec_header);
100 CMD_DECLARE (cmd_spec_htmlify);
101 CMD_DECLARE (cmd_spec_mirror);
102 CMD_DECLARE (cmd_spec_progress);
103 CMD_DECLARE (cmd_spec_recursive);
104 CMD_DECLARE (cmd_spec_restrict_file_names);
105 CMD_DECLARE (cmd_spec_timeout);
106 CMD_DECLARE (cmd_spec_useragent);
107
108 /* List of recognized commands, each consisting of name, closure and function.
109    When adding a new command, simply add it to the list, but be sure to keep the
110    list sorted alphabetically, as findcmd() depends on it.  Also, be sure to add
111    any entries that allocate memory (e.g. cmd_string and cmd_vector guys) to the
112    cleanup() function below. */
113 static struct {
114   char *name;
115   void *closure;
116   int (*action) PARAMS ((const char *, const char *, void *));
117 } commands[] = {
118   { "accept",           &opt.accepts,           cmd_vector },
119   { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
120   { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
121   { "background",       &opt.background,        cmd_boolean },
122   { "backupconverted",  &opt.backup_converted,  cmd_boolean },
123   { "backups",          &opt.backups,           cmd_number },
124   { "base",             &opt.base_href,         cmd_string },
125   { "bindaddress",      &opt.bind_address,      cmd_string },
126   { "cache",            &opt.allow_cache,       cmd_boolean },
127   { "connecttimeout",   &opt.connect_timeout,   cmd_time },
128   { "continue",         &opt.always_rest,       cmd_boolean },
129   { "convertlinks",     &opt.convert_links,     cmd_boolean },
130   { "cookies",          &opt.cookies,           cmd_boolean },
131   { "cutdirs",          &opt.cut_dirs,          cmd_number },
132 #ifdef DEBUG
133   { "debug",            &opt.debug,             cmd_boolean },
134 #endif
135   { "deleteafter",      &opt.delete_after,      cmd_boolean },
136   { "dirprefix",        &opt.dir_prefix,        cmd_directory },
137   { "dirstruct",        NULL,                   cmd_spec_dirstruct },
138   { "dnscache",         &opt.dns_cache,         cmd_boolean },
139   { "dnstimeout",       &opt.dns_timeout,       cmd_time },
140   { "domains",          &opt.domains,           cmd_vector },
141   { "dotbytes",         &opt.dot_bytes,         cmd_bytes },
142   { "dotsinline",       &opt.dots_in_line,      cmd_number },
143   { "dotspacing",       &opt.dot_spacing,       cmd_number },
144   { "dotstyle",         &opt.dot_style,         cmd_string },
145 #ifdef HAVE_SSL
146   { "egdfile",          &opt.sslegdsock,        cmd_file },
147 #endif
148   { "excludedirectories", &opt.excludes,        cmd_directory_vector },
149   { "excludedomains",   &opt.exclude_domains,   cmd_vector },
150   { "followftp",        &opt.follow_ftp,        cmd_boolean },
151   { "followtags",       &opt.follow_tags,       cmd_vector },
152   { "forcehtml",        &opt.force_html,        cmd_boolean },
153   { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
154   { "glob",             &opt.ftp_glob,          cmd_boolean },
155   { "header",           NULL,                   cmd_spec_header },
156   { "htmlextension",    &opt.html_extension,    cmd_boolean },
157   { "htmlify",          NULL,                   cmd_spec_htmlify },
158   { "httpkeepalive",    &opt.http_keep_alive,   cmd_boolean },
159   { "httppasswd",       &opt.http_passwd,       cmd_string },
160   { "httpproxy",        &opt.http_proxy,        cmd_string },
161   { "httpsproxy",       &opt.https_proxy,       cmd_string },
162   { "httpuser",         &opt.http_user,         cmd_string },
163   { "ignorelength",     &opt.ignore_length,     cmd_boolean },
164   { "ignoretags",       &opt.ignore_tags,       cmd_vector },
165   { "includedirectories", &opt.includes,        cmd_directory_vector },
166   { "input",            &opt.input_filename,    cmd_file },
167   { "killlonger",       &opt.kill_longer,       cmd_boolean },
168   { "limitrate",        &opt.limit_rate,        cmd_bytes },
169   { "loadcookies",      &opt.cookies_input,     cmd_file },
170   { "logfile",          &opt.lfilename,         cmd_file },
171   { "login",            &opt.ftp_acc,           cmd_string },
172   { "mirror",           NULL,                   cmd_spec_mirror },
173   { "netrc",            &opt.netrc,             cmd_boolean },
174   { "noclobber",        &opt.noclobber,         cmd_boolean },
175   { "noparent",         &opt.no_parent,         cmd_boolean },
176   { "noproxy",          &opt.no_proxy,          cmd_vector },
177   { "numtries",         &opt.ntry,              cmd_number_inf },/* deprecated*/
178   { "outputdocument",   &opt.output_document,   cmd_file },
179   { "pagerequisites",   &opt.page_requisites,   cmd_boolean },
180   { "passiveftp",       &opt.ftp_pasv,          cmd_lockable_boolean },
181   { "passwd",           &opt.ftp_pass,          cmd_string },
182   { "postdata",         &opt.post_data,         cmd_string },
183   { "postfile",         &opt.post_file_name,    cmd_file },
184   { "progress",         &opt.progress_type,     cmd_spec_progress },
185   { "proxypasswd",      &opt.proxy_passwd,      cmd_string },
186   { "proxyuser",        &opt.proxy_user,        cmd_string },
187   { "quiet",            &opt.quiet,             cmd_boolean },
188   { "quota",            &opt.quota,             cmd_bytes },
189   { "randomwait",       &opt.random_wait,       cmd_boolean },
190   { "readtimeout",      &opt.read_timeout,      cmd_time },
191   { "reclevel",         &opt.reclevel,          cmd_number_inf },
192   { "recursive",        NULL,                   cmd_spec_recursive },
193   { "referer",          &opt.referer,           cmd_string },
194   { "reject",           &opt.rejects,           cmd_vector },
195   { "relativeonly",     &opt.relative_only,     cmd_boolean },
196   { "removelisting",    &opt.remove_listing,    cmd_boolean },
197   { "restrictfilenames", NULL,                  cmd_spec_restrict_file_names },
198   { "retrsymlinks",     &opt.retr_symlinks,     cmd_boolean },
199   { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
200   { "robots",           &opt.use_robots,        cmd_boolean },
201   { "savecookies",      &opt.cookies_output,    cmd_file },
202   { "saveheaders",      &opt.save_headers,      cmd_boolean },
203   { "serverresponse",   &opt.server_response,   cmd_boolean },
204   { "spanhosts",        &opt.spanhost,          cmd_boolean },
205   { "spider",           &opt.spider,            cmd_boolean },
206 #ifdef HAVE_SSL
207   { "sslcadir",         &opt.sslcadir,          cmd_directory },
208   { "sslcafile",        &opt.sslcafile,         cmd_file },
209   { "sslcertfile",      &opt.sslcertfile,       cmd_file },
210   { "sslcertkey",       &opt.sslcertkey,        cmd_file },
211   { "sslcerttype",      &opt.sslcerttype,       cmd_number },
212   { "sslcheckcert",     &opt.sslcheckcert,      cmd_number },
213   { "sslprotocol",      &opt.sslprotocol,       cmd_number },
214 #endif /* HAVE_SSL */
215   { "strictcomments",   &opt.strict_comments,   cmd_boolean },
216   { "timeout",          NULL,                   cmd_spec_timeout },
217   { "timestamping",     &opt.timestamping,      cmd_boolean },
218   { "tries",            &opt.ntry,              cmd_number_inf },
219   { "useproxy",         &opt.use_proxy,         cmd_boolean },
220   { "useragent",        NULL,                   cmd_spec_useragent },
221   { "verbose",          &opt.verbose,           cmd_boolean },
222   { "wait",             &opt.wait,              cmd_time },
223   { "waitretry",        &opt.waitretry,         cmd_time }
224 };
225
226 /* Look up COM in the commands[] array and return its index.  If COM
227    is not found, -1 is returned.  This function uses binary search.  */
228
229 static int
230 findcmd (const char *com)
231 {
232   int lo = 0, hi = countof (commands) - 1;
233
234   while (lo <= hi)
235     {
236       int mid = (lo + hi) >> 1;
237       int cmp = strcasecmp (com, commands[mid].name);
238       if (cmp < 0)
239         hi = mid - 1;
240       else if (cmp > 0)
241         lo = mid + 1;
242       else
243         return mid;
244     }
245   return -1;
246 }
247 \f
248 /* Reset the variables to default values.  */
249 static void
250 defaults (void)
251 {
252   char *tmp;
253
254   /* Most of the default values are 0.  Just reset everything, and
255      fill in the non-zero values.  Note that initializing pointers to
256      NULL this way is technically illegal, but porting Wget to a
257      machine where NULL is not all-zero bit pattern will be the least
258      of the implementors' worries.  */
259   memset (&opt, 0, sizeof (opt));
260
261   opt.cookies = 1;
262
263   opt.verbose = -1;
264   opt.ntry = 20;
265   opt.reclevel = 5;
266   opt.add_hostdir = 1;
267   opt.ftp_acc  = xstrdup ("anonymous");
268   opt.ftp_pass = xstrdup ("-wget@");
269   opt.netrc = 1;
270   opt.ftp_glob = 1;
271   opt.htmlify = 1;
272   opt.http_keep_alive = 1;
273   opt.use_proxy = 1;
274   tmp = getenv ("no_proxy");
275   if (tmp)
276     opt.no_proxy = sepstring (tmp);
277   opt.allow_cache = 1;
278
279   opt.read_timeout = 900;
280   opt.use_robots = 1;
281
282   opt.remove_listing = 1;
283
284   opt.dot_bytes = 1024;
285   opt.dot_spacing = 10;
286   opt.dots_in_line = 50;
287
288   opt.dns_cache = 1;
289
290   /* The default for file name restriction defaults to the OS type. */
291 #if !defined(WINDOWS) && !defined(__CYGWIN__)
292   opt.restrict_files_os = restrict_unix;
293 #else
294   opt.restrict_files_os = restrict_windows;
295 #endif
296   opt.restrict_files_ctrl = 1;
297 }
298 \f
299 /* Return the user's home directory (strdup-ed), or NULL if none is
300    found.  */
301 char *
302 home_dir (void)
303 {
304   char *home = getenv ("HOME");
305
306   if (!home)
307     {
308 #ifndef WINDOWS
309       /* If HOME is not defined, try getting it from the password
310          file.  */
311       struct passwd *pwd = getpwuid (getuid ());
312       if (!pwd || !pwd->pw_dir)
313         return NULL;
314       home = pwd->pw_dir;
315 #else  /* WINDOWS */
316       home = "C:\\";
317       /* #### Maybe I should grab home_dir from registry, but the best
318          that I could get from there is user's Start menu.  It sucks!  */
319 #endif /* WINDOWS */
320     }
321
322   return home ? xstrdup (home) : NULL;
323 }
324
325 /* Return the path to the user's .wgetrc.  This is either the value of
326    `WGETRC' environment variable, or `$HOME/.wgetrc'.
327
328    If the `WGETRC' variable exists but the file does not exist, the
329    function will exit().  */
330 static char *
331 wgetrc_file_name (void)
332 {
333   char *env, *home;
334   char *file = NULL;
335
336   /* Try the environment.  */
337   env = getenv ("WGETRC");
338   if (env && *env)
339     {
340       if (!file_exists_p (env))
341         {
342           fprintf (stderr, "%s: %s: %s.\n", exec_name, env, strerror (errno));
343           exit (1);
344         }
345       return xstrdup (env);
346     }
347
348 #ifndef WINDOWS
349   /* If that failed, try $HOME/.wgetrc.  */
350   home = home_dir ();
351   if (home)
352     {
353       file = (char *)xmalloc (strlen (home) + 1 + strlen (".wgetrc") + 1);
354       sprintf (file, "%s/.wgetrc", home);
355     }
356   FREE_MAYBE (home);
357 #else  /* WINDOWS */
358   /* Under Windows, "home" is (for the purposes of this function) the
359      directory where `wget.exe' resides, and `wget.ini' will be used
360      as file name.  SYSTEM_WGETRC should not be defined under WINDOWS.
361
362      It is not as trivial as I assumed, because on 95 argv[0] is full
363      path, but on NT you get what you typed in command line.  --dbudor */
364   home = ws_mypath ();
365   if (home)
366     {
367       file = (char *)xmalloc (strlen (home) + strlen ("wget.ini") + 1);
368       sprintf (file, "%swget.ini", home);
369     }
370 #endif /* WINDOWS */
371
372   if (!file)
373     return NULL;
374   if (!file_exists_p (file))
375     {
376       xfree (file);
377       return NULL;
378     }
379   return file;
380 }
381
382 static int parse_line PARAMS ((const char *, char **, char **, int *));
383 static int setval_internal PARAMS ((int, const char *, const char *));
384
385 /* Initialize variables from a wgetrc file.  */
386
387 static void
388 run_wgetrc (const char *file)
389 {
390   FILE *fp;
391   char *line;
392   int ln;
393
394   fp = fopen (file, "rb");
395   if (!fp)
396     {
397       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
398                file, strerror (errno));
399       return;
400     }
401   enable_tilde_expansion = 1;
402   ln = 1;
403   while ((line = read_whole_line (fp)))
404     {
405       char *com, *val;
406       int comind, status;
407
408       /* Parse the line.  */
409       status = parse_line (line, &com, &val, &comind);
410       xfree (line);
411       /* If everything is OK, set the value.  */
412       if (status == 1)
413         {
414           if (!setval_internal (comind, com, val))
415             fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
416                      file, ln);
417           xfree (com);
418           xfree (val);
419         }
420       else if (status == 0)
421         fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
422                  file, ln);
423       ++ln;
424     }
425   enable_tilde_expansion = 0;
426   fclose (fp);
427 }
428
429 /* Initialize the defaults and run the system wgetrc and user's own
430    wgetrc.  */
431 void
432 initialize (void)
433 {
434   char *file;
435
436   /* Load the hard-coded defaults.  */
437   defaults ();
438
439   /* If SYSTEM_WGETRC is defined, use it.  */
440 #ifdef SYSTEM_WGETRC
441   if (file_exists_p (SYSTEM_WGETRC))
442     run_wgetrc (SYSTEM_WGETRC);
443 #endif
444   /* Override it with your own, if one exists.  */
445   file = wgetrc_file_name ();
446   if (!file)
447     return;
448   /* #### We should canonicalize `file' and SYSTEM_WGETRC with
449      something like realpath() before comparing them with `strcmp'  */
450 #ifdef SYSTEM_WGETRC
451   if (!strcmp (file, SYSTEM_WGETRC))
452     {
453       fprintf (stderr, _("\
454 %s: Warning: Both system and user wgetrc point to `%s'.\n"),
455                exec_name, file);
456     }
457   else
458 #endif
459     run_wgetrc (file);
460   xfree (file);
461   return;
462 }
463 \f
464 /* Remove dashes and underscores from S, modifying S in the
465    process. */
466
467 static void
468 dehyphen (char *s)
469 {
470   char *t = s;                  /* t - tortoise */
471   char *h = s;                  /* h - hare     */
472   while (*h)
473     if (*h == '_' || *h == '-')
474       ++h;
475     else
476       *t++ = *h++;
477   *t = '\0';
478 }
479
480 /* Parse the line pointed by line, with the syntax:
481    <sp>* command <sp>* = <sp>* value <newline>
482    Uses malloc to allocate space for command and value.
483    If the line is invalid, data is freed and 0 is returned.
484
485    Return values:
486     1 - success
487     0 - failure
488    -1 - empty */
489
490 static int
491 parse_line (const char *line, char **com, char **val, int *comind)
492 {
493   const char *p;
494   const char *end = line + strlen (line);
495   const char *cmdstart, *cmdend;
496   const char *valstart, *valend;
497
498   char *cmdcopy;
499   int ind;
500
501   /* Skip leading and trailing whitespace.  */
502   while (*line && ISSPACE (*line))
503     ++line;
504   while (end > line && ISSPACE (end[-1]))
505     --end;
506
507   /* Skip empty lines and comments.  */
508   if (!*line || *line == '#')
509     return -1;
510
511   p = line;
512
513   cmdstart = p;
514   while (p < end && (ISALPHA (*p) || *p == '_' || *p == '-'))
515     ++p;
516   cmdend = p;
517
518   /* Skip '=', as well as any space before or after it. */
519   while (p < end && ISSPACE (*p))
520     ++p;
521   if (p == end || *p != '=')
522     return 0;
523   ++p;
524   while (p < end && ISSPACE (*p))
525     ++p;
526
527   valstart = p;
528   valend   = end;
529
530   /* The line now known to be syntactically correct.  Check whether
531      the command is valid.  */
532   BOUNDED_TO_ALLOCA (cmdstart, cmdend, cmdcopy);
533   dehyphen (cmdcopy);
534   ind = findcmd (cmdcopy);
535   if (ind == -1)
536     return 0;
537
538   /* The command is valid.  Now fill in the values and report success
539      to the caller.  */
540   *comind = ind;
541   *com = strdupdelim (cmdstart, cmdend);
542   *val = strdupdelim (valstart, valend);
543   return 1;
544 }
545
546 /* Run commands[comind].action. */
547
548 static int
549 setval_internal (int comind, const char *com, const char *val)
550 {
551   assert (0 <= comind && comind < countof (commands));
552   return ((*commands[comind].action) (com, val, commands[comind].closure));
553 }
554
555 /* Run command COM with value VAL.  If running the command produces an
556    error, report the error and exit.
557
558    This is intended to be called from main() with commands not
559    provided by the user, therefore it aborts when an unknown command
560    is encountered.  Once the COMIND's are exported to init.h, this
561    function will be changed to accept COMIND directly.  */
562
563 void
564 setoptval (const char *com, const char *val)
565 {
566   int comind = findcmd (com);
567   assert (comind != -1);
568   if (!setval_internal (comind, com, val))
569     exit (2);
570 }
571
572 void
573 run_command (const char *opt)
574 {
575   char *com, *val;
576   int comind;
577   int status = parse_line (opt, &com, &val, &comind);
578   if (status == 1)
579     {
580       if (!setval_internal (comind, com, val))
581         exit (2);
582       xfree (com);
583       xfree (val);
584     }
585   else if (status == 0)
586     {
587       fprintf (stderr, "Invalid command `%s'\n", opt);
588       exit (2);
589     }
590 }
591 \f
592 /* Generic helper functions, for use with `commands'. */
593
594 static int myatoi PARAMS ((const char *s));
595
596 /* Store the boolean value from VAL to CLOSURE.  COM is ignored,
597    except for error messages.  */
598 static int
599 cmd_boolean (const char *com, const char *val, void *closure)
600 {
601   int bool_value;
602   const char *v = val;
603 #define LC(x) TOLOWER(x)
604
605   if ((LC(v[0]) == 'o' && LC(v[1]) == 'n' && !v[2])
606       ||
607       (LC(v[0]) == 'y' && LC(v[1]) == 'e' && LC(v[2]) == 's' && !v[3])
608       ||
609       (v[0] == '1' && !v[1]))
610     /* "on", "yes" and "1" mean true. */
611     bool_value = 1;
612   else if ((LC(v[0]) == 'o' && LC(v[1]) == 'f' && LC(v[2]) == 'f' && !v[3])
613            ||
614            (LC(v[0]) == 'n' && LC(v[1]) == 'o' && !v[2])
615            ||
616            (v[0] == '0' && !v[1]))
617     /* "off", "no" and "0" mean false. */
618     bool_value = 0;
619   else
620     {
621       fprintf (stderr, _("%s: %s: Please specify on or off.\n"),
622                exec_name, com);
623       return 0;
624     }
625
626   *(int *)closure = bool_value;
627   return 1;
628 }
629
630 /* Store the lockable_boolean {2, 1, 0, -1} value from VAL to CLOSURE.  COM is
631    ignored, except for error messages.  Values 2 and -1 indicate that once
632    defined, the value may not be changed by successive wgetrc files or
633    command-line arguments.
634
635    Values: 2 - Enable a particular option for good ("always")
636            1 - Enable an option ("on")
637            0 - Disable an option ("off")
638           -1 - Disable an option for good ("never") */
639 static int
640 cmd_lockable_boolean (const char *com, const char *val, void *closure)
641 {
642   int lockable_boolean_value;
643
644   /*
645    * If a config file said "always" or "never", don't allow command line
646    * arguments to override the config file.
647    */
648   if (*(int *)closure == -1 || *(int *)closure == 2)
649     return 1;
650
651   if (!strcasecmp (val, "always") || !strcmp (val, "2"))
652     lockable_boolean_value = 2;
653   else if (!strcasecmp (val, "on")
654            || !strcasecmp (val, "yes")
655            || !strcmp (val, "1"))
656     lockable_boolean_value = 1;
657   else if (!strcasecmp (val, "off")
658            || !strcasecmp (val, "no")
659            || !strcmp (val, "0"))
660     lockable_boolean_value = 0;
661   else if (!strcasecmp (val, "never") || !strcmp (val, "-1"))
662     lockable_boolean_value = -1;
663   else
664     {
665       fprintf (stderr, _("%s: %s: Please specify always, on, off, "
666                          "or never.\n"),
667                exec_name, com);
668       return 0;
669     }
670
671   *(int *)closure = lockable_boolean_value;
672   return 1;
673 }
674
675 /* Set the non-negative integer value from VAL to CLOSURE.  With
676    incorrect specification, the number remains unchanged.  */
677 static int
678 cmd_number (const char *com, const char *val, void *closure)
679 {
680   int num = myatoi (val);
681
682   if (num == -1)
683     {
684       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
685                exec_name, com, val);
686       return 0;
687     }
688   *(int *)closure = num;
689   return 1;
690 }
691
692 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
693 static int
694 cmd_number_inf (const char *com, const char *val, void *closure)
695 {
696   if (!strcasecmp (val, "inf"))
697     {
698       *(int *)closure = 0;
699       return 1;
700     }
701   return cmd_number (com, val, closure);
702 }
703
704 /* Copy (strdup) the string at COM to a new location and place a
705    pointer to *CLOSURE.  */
706 static int
707 cmd_string (const char *com, const char *val, void *closure)
708 {
709   char **pstring = (char **)closure;
710
711   FREE_MAYBE (*pstring);
712   *pstring = xstrdup (val);
713   return 1;
714 }
715
716 #ifndef WINDOWS
717 # define ISSEP(c) ((c) == '/')
718 #else
719 # define ISSEP(c) ((c) == '/' || (c) == '\\')
720 #endif
721
722 /* Like the above, but handles tilde-expansion when reading a user's
723    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
724    gets expanded to the user's home directory.  */
725 static int
726 cmd_file (const char *com, const char *val, void *closure)
727 {
728   char **pstring = (char **)closure;
729
730   FREE_MAYBE (*pstring);
731
732   /* #### If VAL is empty, perhaps should set *CLOSURE to NULL.  */
733
734   if (!enable_tilde_expansion || !(*val == '~' && ISSEP (val[1])))
735     {
736     noexpand:
737       *pstring = xstrdup (val);
738     }
739   else
740     {
741       char *result;
742       int homelen;
743       char *home = home_dir ();
744       if (!home)
745         goto noexpand;
746
747       homelen = strlen (home);
748       while (homelen && ISSEP (home[homelen - 1]))
749         home[--homelen] = '\0';
750
751       /* Skip the leading "~/". */
752       for (++val; ISSEP (*val); val++)
753         ;
754
755       result = xmalloc (homelen + 1 + strlen (val) + 1);
756       memcpy (result, home, homelen);
757       result[homelen] = '/';
758       strcpy (result + homelen + 1, val);
759
760       *pstring = result;
761     }
762
763 #ifdef WINDOWS
764   /* Convert "\" to "/". */
765   {
766     char *s;
767     for (s = *pstring; *s; s++)
768       if (*s == '\\')
769         *s = '/';
770   }
771 #endif
772   return 1;
773 }
774
775 /* Like cmd_file, but strips trailing '/' characters.  */
776 static int
777 cmd_directory (const char *com, const char *val, void *closure)
778 {
779   char *s, *t;
780
781   /* Call cmd_file() for tilde expansion and separator
782      canonicalization (backslash -> slash under Windows).  These
783      things should perhaps be in a separate function.  */
784   if (!cmd_file (com, val, closure))
785     return 0;
786
787   s = *(char **)closure;
788   t = s + strlen (s);
789   while (t > s && *--t == '/')
790     *t = '\0';
791
792   return 1;
793 }
794
795 /* Merge the vector (array of strings separated with `,') in COM with
796    the vector (NULL-terminated array of strings) pointed to by
797    CLOSURE.  */
798 static int
799 cmd_vector (const char *com, const char *val, void *closure)
800 {
801   char ***pvec = (char ***)closure;
802
803   if (*val)
804     *pvec = merge_vecs (*pvec, sepstring (val));
805   else
806     {
807       free_vec (*pvec);
808       *pvec = NULL;
809     }
810   return 1;
811 }
812
813 static int
814 cmd_directory_vector (const char *com, const char *val, void *closure)
815 {
816   char ***pvec = (char ***)closure;
817
818   if (*val)
819     {
820       /* Strip the trailing slashes from directories.  */
821       char **t, **seps;
822
823       seps = sepstring (val);
824       for (t = seps; t && *t; t++)
825         {
826           int len = strlen (*t);
827           /* Skip degenerate case of root directory.  */
828           if (len > 1)
829             {
830               if ((*t)[len - 1] == '/')
831                 (*t)[len - 1] = '\0';
832             }
833         }
834       *pvec = merge_vecs (*pvec, seps);
835     }
836   else
837     {
838       free_vec (*pvec);
839       *pvec = NULL;
840     }
841   return 1;
842 }
843
844 /* Poor man's atof: handles only <digits>.<digits>.  Returns 1 on
845    success, 0 on failure.  In case of success, stores its result to
846    *DEST.  */
847
848 static int
849 simple_atof (const char *beg, const char *end, double *dest)
850 {
851   double result = 0;
852
853   int seen_dot = 0;
854   int seen_digit = 0;
855   double divider = 1;
856
857   const char *p = beg;
858
859   while (p < end)
860     {
861       char ch = *p++;
862       if (ISDIGIT (ch))
863         {
864           if (!seen_dot)
865             result = (10 * result) + (ch - '0');
866           else
867             result += (ch - '0') / (divider *= 10);
868           seen_digit = 1;
869         }
870       else if (ch == '.')
871         {
872           if (!seen_dot)
873             seen_dot = 1;
874           else
875             return 0;
876         }
877     }
878   if (!seen_digit)
879     return 0;
880
881   *dest = result;
882   return 1;
883 }
884
885 /* Parse VAL as a number and set its value to CLOSURE (which should
886    point to a long int).
887
888    By default, the value is assumed to be in bytes.  If "K", "M", or
889    "G" are appended, the value is multiplied with 1<<10, 1<<20, or
890    1<<30, respectively.  Floating point values are allowed and are
891    cast to integer before use.  The idea is to be able to use things
892    like 1.5k instead of "1536".
893
894    The string "inf" is returned as 0.
895
896    In case of error, 0 is returned and memory pointed to by CLOSURE
897    remains unmodified.  */
898
899 static int
900 cmd_bytes (const char *com, const char *val, void *closure)
901 {
902   long mult;
903   double number;
904   const char *end = val + strlen (val);
905
906   /* Check for "inf".  */
907   if (0 == strcmp (val, "inf"))
908     {
909       *(long *)closure = 0;
910       return 1;
911     }
912
913   /* Strip trailing whitespace.  */
914   while (val < end && ISSPACE (end[-1]))
915     --end;
916
917   if (val == end)
918     {
919     err:
920       fprintf (stderr, _("%s: Invalid byte value `%s'\n"), com, val);
921       return 0;
922     }
923
924   switch (TOLOWER (end[-1]))
925     {
926     case 'k':
927       --end, mult = 1L<<10;
928       break;
929     case 'm':
930       --end, mult = 1L<<20;
931       break;
932     case 'g':
933       --end, mult = 1L<<30;
934       break;
935     default:
936       /* Not a recognized suffix: assume it belongs to the number.
937          (If not, atof simple_atof will raise an error.)  */
938       mult = 1;
939     }
940
941   /* Skip leading and trailing whitespace. */
942   while (val < end && ISSPACE (*val))
943     ++val;
944   while (val < end && ISSPACE (end[-1]))
945     --end;
946   if (val == end)
947     goto err;
948
949   if (!simple_atof (val, end, &number))
950     goto err;
951
952   *(long *)closure = (long)(number * mult);
953   return 1;
954 }
955
956 /* Store the value of VAL to *OUT.  The value is a time period, by
957    default expressed in seconds, but also accepting suffixes "m", "h",
958    "d", and "w" for minutes, hours, days, and weeks respectively.  */
959
960 static int
961 cmd_time (const char *com, const char *val, void *closure)
962 {
963   double number, mult;
964   const char *end = val + strlen (val);
965
966   /* Strip trailing whitespace.  */
967   while (val < end && ISSPACE (end[-1]))
968     --end;
969
970   if (val == end)
971     {
972     err:
973       fprintf (stderr, _("%s: Invalid time specification `%s'\n"), com, val);
974       return 0;
975     }
976
977   switch (TOLOWER (end[-1]))
978     {
979     case 's':
980       --end, mult = 1;          /* seconds */
981       break;
982     case 'm':
983       --end, mult = 60;         /* minutes */
984       break;
985     case 'h':
986       --end, mult = 3600;       /* hours */
987       break;
988     case 'd':
989       --end, mult = 86400.0;    /* days */
990       break;
991     case 'w':
992       --end, mult = 604800.0;   /* weeks */
993       break;
994     default:
995       /* Not a recognized suffix: assume it belongs to the number.
996          (If not, atof simple_atof will raise an error.)  */
997       mult = 1;
998     }
999
1000   /* Skip leading and trailing whitespace. */
1001   while (val < end && ISSPACE (*val))
1002     ++val;
1003   while (val < end && ISSPACE (end[-1]))
1004     --end;
1005   if (val == end)
1006     goto err;
1007
1008   if (!simple_atof (val, end, &number))
1009     goto err;
1010
1011   *(double *)closure = number * mult;
1012   return 1;
1013 }
1014 \f
1015 /* Specialized helper functions, used by `commands' to handle some
1016    options specially.  */
1017
1018 static int check_user_specified_header PARAMS ((const char *));
1019
1020 static int
1021 cmd_spec_dirstruct (const char *com, const char *val, void *closure)
1022 {
1023   if (!cmd_boolean (com, val, &opt.dirstruct))
1024     return 0;
1025   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
1026      must be affected inversely.  */
1027   if (opt.dirstruct)
1028     opt.no_dirstruct = 0;
1029   else
1030     opt.no_dirstruct = 1;
1031   return 1;
1032 }
1033
1034 static int
1035 cmd_spec_header (const char *com, const char *val, void *closure)
1036 {
1037   if (!*val)
1038     {
1039       /* Empty header means reset headers.  */
1040       FREE_MAYBE (opt.user_header);
1041       opt.user_header = NULL;
1042     }
1043   else
1044     {
1045       int i;
1046
1047       if (!check_user_specified_header (val))
1048         {
1049           fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
1050                    exec_name, com, val);
1051           return 0;
1052         }
1053       i = opt.user_header ? strlen (opt.user_header) : 0;
1054       opt.user_header = (char *)xrealloc (opt.user_header, i + strlen (val)
1055                                           + 2 + 1);
1056       strcpy (opt.user_header + i, val);
1057       i += strlen (val);
1058       opt.user_header[i++] = '\r';
1059       opt.user_header[i++] = '\n';
1060       opt.user_header[i] = '\0';
1061     }
1062   return 1;
1063 }
1064
1065 static int
1066 cmd_spec_htmlify (const char *com, const char *val, void *closure)
1067 {
1068   int flag = cmd_boolean (com, val, &opt.htmlify);
1069   if (flag && !opt.htmlify)
1070     opt.remove_listing = 0;
1071   return flag;
1072 }
1073
1074 static int
1075 cmd_spec_mirror (const char *com, const char *val, void *closure)
1076 {
1077   int mirror;
1078
1079   if (!cmd_boolean (com, val, &mirror))
1080     return 0;
1081   if (mirror)
1082     {
1083       opt.recursive = 1;
1084       if (!opt.no_dirstruct)
1085         opt.dirstruct = 1;
1086       opt.timestamping = 1;
1087       opt.reclevel = INFINITE_RECURSION;
1088       opt.remove_listing = 0;
1089     }
1090   return 1;
1091 }
1092
1093 static int
1094 cmd_spec_progress (const char *com, const char *val, void *closure)
1095 {
1096   if (!valid_progress_implementation_p (val))
1097     {
1098       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
1099                exec_name, com, val);
1100       return 0;
1101     }
1102   FREE_MAYBE (opt.progress_type);
1103
1104   /* Don't call set_progress_implementation here.  It will be called
1105      in main() when it becomes clear what the log output is.  */
1106   opt.progress_type = xstrdup (val);
1107   return 1;
1108 }
1109
1110 static int
1111 cmd_spec_recursive (const char *com, const char *val, void *closure)
1112 {
1113   if (!cmd_boolean (com, val, &opt.recursive))
1114     return 0;
1115   else
1116     {
1117       if (opt.recursive && !opt.no_dirstruct)
1118         opt.dirstruct = 1;
1119     }
1120   return 1;
1121 }
1122
1123 static int
1124 cmd_spec_restrict_file_names (const char *com, const char *val, void *closure)
1125 {
1126   int restrict_os = opt.restrict_files_os;
1127   int restrict_ctrl = opt.restrict_files_ctrl;
1128
1129   const char *end = strchr (val, ',');
1130   if (!end)
1131     end = val + strlen (val);
1132
1133 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1134
1135   if (VAL_IS ("unix"))
1136     restrict_os = restrict_unix;
1137   else if (VAL_IS ("windows"))
1138     restrict_os = restrict_windows;
1139   else if (VAL_IS ("nocontrol"))
1140     restrict_ctrl = 0;
1141   else
1142     {
1143     err:
1144       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
1145                exec_name, com, val);
1146       return 0;
1147     }
1148
1149 #undef VAL_IS
1150
1151   if (*end)
1152     {
1153       if (!strcmp (end + 1, "nocontrol"))
1154         restrict_ctrl = 0;
1155       else
1156         goto err;
1157     }
1158
1159   opt.restrict_files_os = restrict_os;
1160   opt.restrict_files_ctrl = restrict_ctrl;
1161   return 1;
1162 }
1163
1164 /* Set all three timeout values. */
1165
1166 static int
1167 cmd_spec_timeout (const char *com, const char *val, void *closure)
1168 {
1169   double value;
1170   if (!cmd_time (com, val, &value))
1171     return 0;
1172   opt.read_timeout = value;
1173   opt.connect_timeout = value;
1174   opt.dns_timeout = value;
1175   return 1;
1176 }
1177
1178 static int
1179 cmd_spec_useragent (const char *com, const char *val, void *closure)
1180 {
1181   /* Just check for empty string and newline, so we don't throw total
1182      junk to the server.  */
1183   if (!*val || strchr (val, '\n'))
1184     {
1185       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
1186                exec_name, com, val);
1187       return 0;
1188     }
1189   opt.useragent = xstrdup (val);
1190   return 1;
1191 }
1192 \f
1193 /* Miscellaneous useful routines.  */
1194
1195 /* Return the integer value of a positive integer written in S, or -1
1196    if an error was encountered.  */
1197 static int
1198 myatoi (const char *s)
1199 {
1200   int res;
1201   const char *orig = s;
1202
1203   for (res = 0; *s && ISDIGIT (*s); s++)
1204     res = 10 * res + (*s - '0');
1205   if (*s || orig == s)
1206     return -1;
1207   else
1208     return res;
1209 }
1210
1211 static int
1212 check_user_specified_header (const char *s)
1213 {
1214   const char *p;
1215
1216   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1217   /* The header MUST contain `:' preceded by at least one
1218      non-whitespace character.  */
1219   if (*p != ':' || p == s)
1220     return 0;
1221   /* The header MUST NOT contain newlines.  */
1222   if (strchr (s, '\n'))
1223     return 0;
1224   return 1;
1225 }
1226 \f
1227 void cleanup_html_url PARAMS ((void));
1228 void res_cleanup PARAMS ((void));
1229 void downloaded_files_free PARAMS ((void));
1230 void http_cleanup PARAMS ((void));
1231
1232
1233 /* Free the memory allocated by global variables.  */
1234 void
1235 cleanup (void)
1236 {
1237   /* Free external resources, close files, etc. */
1238
1239   if (opt.dfp)
1240     fclose (opt.dfp);
1241
1242   /* We're exiting anyway so there's no real need to call free()
1243      hundreds of times.  Skipping the frees will make Wget exit
1244      faster.
1245
1246      However, when detecting leaks, it's crucial to free() everything
1247      because then you can find the real leaks, i.e. the allocated
1248      memory which grows with the size of the program.  */
1249
1250 #ifdef DEBUG_MALLOC
1251   recursive_cleanup ();
1252   res_cleanup ();
1253   http_cleanup ();
1254   cleanup_html_url ();
1255   downloaded_files_free ();
1256   host_cleanup ();
1257   cookie_jar_delete (wget_cookie_jar);
1258
1259   {
1260     extern acc_t *netrc_list;
1261     free_netrc (netrc_list);
1262   }
1263   FREE_MAYBE (opt.lfilename);
1264   FREE_MAYBE (opt.dir_prefix);
1265   FREE_MAYBE (opt.input_filename);
1266   FREE_MAYBE (opt.output_document);
1267   free_vec (opt.accepts);
1268   free_vec (opt.rejects);
1269   free_vec (opt.excludes);
1270   free_vec (opt.includes);
1271   free_vec (opt.domains);
1272   free_vec (opt.follow_tags);
1273   free_vec (opt.ignore_tags);
1274   FREE_MAYBE (opt.progress_type);
1275   xfree (opt.ftp_acc);
1276   FREE_MAYBE (opt.ftp_pass);
1277   FREE_MAYBE (opt.ftp_proxy);
1278   FREE_MAYBE (opt.https_proxy);
1279   FREE_MAYBE (opt.http_proxy);
1280   free_vec (opt.no_proxy);
1281   FREE_MAYBE (opt.useragent);
1282   FREE_MAYBE (opt.referer);
1283   FREE_MAYBE (opt.http_user);
1284   FREE_MAYBE (opt.http_passwd);
1285   FREE_MAYBE (opt.user_header);
1286 #ifdef HAVE_SSL
1287   FREE_MAYBE (opt.sslcertkey);
1288   FREE_MAYBE (opt.sslcertfile);
1289 #endif /* HAVE_SSL */
1290   FREE_MAYBE (opt.bind_address);
1291   FREE_MAYBE (opt.cookies_input);
1292   FREE_MAYBE (opt.cookies_output);
1293 #endif
1294 }