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