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