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