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