]> sjero.net Git - wget/blobdiff - src/init.c
Eschew config-post.h.
[wget] / src / init.c
index c81a67bc2cda05d4382b8e2b0a5e1fc9a7abbdff..71a5ecec8f92a60aaf2a22204737afe255c5e659 100644 (file)
@@ -1,11 +1,12 @@
 /* Reading/parsing the initialization file.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,8 +15,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
 In addition, as a special exception, the Free Software Foundation
 gives permission to link the code of its release of Wget with the
@@ -27,7 +27,7 @@ modify this file, you may extend this exception to your version of the
 file, but you are not obligated to do so.  If you do not wish to do
 so, delete this exception statement from your version.  */
 
-#include <config.h>
+#include "wget.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -42,15 +42,20 @@ so, delete this exception statement from your version.  */
 #endif
 #include <assert.h>
 
-#include "wget.h"
 #include "utils.h"
 #include "init.h"
 #include "host.h"
 #include "netrc.h"
 #include "progress.h"
-#include "recur.h"             /* for INFINITE_RECURSION */
-#include "convert.h"           /* for convert_cleanup */
-#include "res.h"               /* for res_cleanup */
+#include "recur.h"              /* for INFINITE_RECURSION */
+#include "convert.h"            /* for convert_cleanup */
+#include "res.h"                /* for res_cleanup */
+#include "http.h"               /* for http_cleanup */
+#include "retr.h"               /* for output_stream */
+
+#ifdef TESTING
+#include "test.h"
+#endif
 
 /* We want tilde expansion enabled only when reading `.wgetrc' lines;
    otherwise, it will be performed by the shell.  This variable will
@@ -63,7 +68,7 @@ static bool enable_tilde_expansion;
 
 CMD_DECLARE (cmd_boolean);
 CMD_DECLARE (cmd_bytes);
-CMD_DECLARE (cmd_bytes_large);
+CMD_DECLARE (cmd_bytes_sum);
 #ifdef HAVE_SSL
 CMD_DECLARE (cmd_cert_type);
 #endif
@@ -89,150 +94,157 @@ CMD_DECLARE (cmd_spec_secure_protocol);
 #endif
 CMD_DECLARE (cmd_spec_timeout);
 CMD_DECLARE (cmd_spec_useragent);
+CMD_DECLARE (cmd_spec_verbose);
 
 /* List of recognized commands, each consisting of name, place and
    function.  When adding a new command, simply add it to the list,
    but be sure to keep the list sorted alphabetically, as
-   command_by_name depends on it.  Also, be sure to add any entries
-   that allocate memory (e.g. cmd_string and cmd_vector) to the
-   cleanup() function below. */
+   command_by_name's binary search depends on it.  Also, be sure to
+   add any entries that allocate memory (e.g. cmd_string and
+   cmd_vector) to the cleanup() function below. */
 
-static struct {
+static const struct {
   const char *name;
   void *place;
   bool (*action) (const char *, const char *, void *);
 } commands[] = {
-  { "accept",          &opt.accepts,           cmd_vector },
-  { "addhostdir",      &opt.add_hostdir,       cmd_boolean },
-  { "alwaysrest",      &opt.always_rest,       cmd_boolean }, /* deprecated */
-  { "background",      &opt.background,        cmd_boolean },
-  { "backupconverted", &opt.backup_converted,  cmd_boolean },
-  { "backups",         &opt.backups,           cmd_number },
-  { "base",            &opt.base_href,         cmd_string },
-  { "bindaddress",     &opt.bind_address,      cmd_string },
+  /* KEEP THIS LIST ALPHABETICALLY SORTED */
+  { "accept",           &opt.accepts,           cmd_vector },
+  { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
+  { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
+  { "background",       &opt.background,        cmd_boolean },
+  { "backupconverted",  &opt.backup_converted,  cmd_boolean },
+  { "backups",          &opt.backups,           cmd_number },
+  { "base",             &opt.base_href,         cmd_string },
+  { "bindaddress",      &opt.bind_address,      cmd_string },
 #ifdef HAVE_SSL
-  { "cacertificate",   &opt.ca_cert,           cmd_file },
+  { "cacertificate",    &opt.ca_cert,           cmd_file },
 #endif
-  { "cache",           &opt.allow_cache,       cmd_boolean },
+  { "cache",            &opt.allow_cache,       cmd_boolean },
 #ifdef HAVE_SSL
-  { "cadirectory",     &opt.ca_directory,      cmd_directory },
-  { "certificate",     &opt.cert_file,         cmd_file },
-  { "certificatetype", &opt.cert_type,         cmd_cert_type },
-  { "checkcertificate", &opt.check_cert,       cmd_boolean },
+  { "cadirectory",      &opt.ca_directory,      cmd_directory },
+  { "certificate",      &opt.cert_file,         cmd_file },
+  { "certificatetype",  &opt.cert_type,         cmd_cert_type },
+  { "checkcertificate", &opt.check_cert,        cmd_boolean },
 #endif
-  { "connecttimeout",  &opt.connect_timeout,   cmd_time },
-  { "continue",                &opt.always_rest,       cmd_boolean },
-  { "convertlinks",    &opt.convert_links,     cmd_boolean },
-  { "cookies",         &opt.cookies,           cmd_boolean },
-  { "cutdirs",         &opt.cut_dirs,          cmd_number },
+  { "connecttimeout",   &opt.connect_timeout,   cmd_time },
+  { "contentdisposition", &opt.content_disposition, cmd_boolean },
+  { "continue",         &opt.always_rest,       cmd_boolean },
+  { "convertlinks",     &opt.convert_links,     cmd_boolean },
+  { "cookies",          &opt.cookies,           cmd_boolean },
+  { "cutdirs",          &opt.cut_dirs,          cmd_number },
 #ifdef ENABLE_DEBUG
-  { "debug",           &opt.debug,             cmd_boolean },
+  { "debug",            &opt.debug,             cmd_boolean },
 #endif
-  { "deleteafter",     &opt.delete_after,      cmd_boolean },
-  { "dirprefix",       &opt.dir_prefix,        cmd_directory },
-  { "dirstruct",       NULL,                   cmd_spec_dirstruct },
-  { "dnscache",                &opt.dns_cache,         cmd_boolean },
-  { "dnstimeout",      &opt.dns_timeout,       cmd_time },
-  { "domains",         &opt.domains,           cmd_vector },
-  { "dotbytes",                &opt.dot_bytes,         cmd_bytes },
-  { "dotsinline",      &opt.dots_in_line,      cmd_number },
-  { "dotspacing",      &opt.dot_spacing,       cmd_number },
-  { "dotstyle",                &opt.dot_style,         cmd_string },
+  { "deleteafter",      &opt.delete_after,      cmd_boolean },
+  { "dirprefix",        &opt.dir_prefix,        cmd_directory },
+  { "dirstruct",        NULL,                   cmd_spec_dirstruct },
+  { "dnscache",         &opt.dns_cache,         cmd_boolean },
+  { "dnstimeout",       &opt.dns_timeout,       cmd_time },
+  { "domains",          &opt.domains,           cmd_vector },
+  { "dotbytes",         &opt.dot_bytes,         cmd_bytes },
+  { "dotsinline",       &opt.dots_in_line,      cmd_number },
+  { "dotspacing",       &opt.dot_spacing,       cmd_number },
+  { "dotstyle",         &opt.dot_style,         cmd_string },
 #ifdef HAVE_SSL
-  { "egdfile",         &opt.egd_file,          cmd_file },
+  { "egdfile",          &opt.egd_file,          cmd_file },
 #endif
-  { "excludedirectories", &opt.excludes,       cmd_directory_vector },
-  { "excludedomains",  &opt.exclude_domains,   cmd_vector },
-  { "followftp",       &opt.follow_ftp,        cmd_boolean },
-  { "followtags",      &opt.follow_tags,       cmd_vector },
-  { "forcehtml",       &opt.force_html,        cmd_boolean },
-  { "ftppasswd",       &opt.ftp_passwd,        cmd_string }, /* deprecated */
-  { "ftppassword",     &opt.ftp_passwd,        cmd_string },
-  { "ftpproxy",                &opt.ftp_proxy,         cmd_string },
-  { "ftpuser",         &opt.ftp_user,          cmd_string },
-  { "glob",            &opt.ftp_glob,          cmd_boolean },
-  { "header",          NULL,                   cmd_spec_header },
-  { "htmlextension",   &opt.html_extension,    cmd_boolean },
-  { "htmlify",         NULL,                   cmd_spec_htmlify },
-  { "httpkeepalive",   &opt.http_keep_alive,   cmd_boolean },
-  { "httppasswd",      &opt.http_passwd,       cmd_string }, /* deprecated */
-  { "httppassword",    &opt.http_passwd,       cmd_string },
-  { "httpproxy",       &opt.http_proxy,        cmd_string },
-  { "httpsproxy",      &opt.https_proxy,       cmd_string },
-  { "httpuser",                &opt.http_user,         cmd_string },
-  { "ignorelength",    &opt.ignore_length,     cmd_boolean },
-  { "ignoretags",      &opt.ignore_tags,       cmd_vector },
-  { "includedirectories", &opt.includes,       cmd_directory_vector },
+  { "excludedirectories", &opt.excludes,        cmd_directory_vector },
+  { "excludedomains",   &opt.exclude_domains,   cmd_vector },
+  { "followftp",        &opt.follow_ftp,        cmd_boolean },
+  { "followtags",       &opt.follow_tags,       cmd_vector },
+  { "forcehtml",        &opt.force_html,        cmd_boolean },
+  { "ftppasswd",        &opt.ftp_passwd,        cmd_string }, /* deprecated */
+  { "ftppassword",      &opt.ftp_passwd,        cmd_string },
+  { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
+  { "ftpuser",          &opt.ftp_user,          cmd_string },
+  { "glob",             &opt.ftp_glob,          cmd_boolean },
+  { "header",           NULL,                   cmd_spec_header },
+  { "htmlextension",    &opt.html_extension,    cmd_boolean },
+  { "htmlify",          NULL,                   cmd_spec_htmlify },
+  { "httpkeepalive",    &opt.http_keep_alive,   cmd_boolean },
+  { "httppasswd",       &opt.http_passwd,       cmd_string }, /* deprecated */
+  { "httppassword",     &opt.http_passwd,       cmd_string },
+  { "httpproxy",        &opt.http_proxy,        cmd_string },
+  { "httpsproxy",       &opt.https_proxy,       cmd_string },
+  { "httpuser",         &opt.http_user,         cmd_string },
+  { "ignorecase",       &opt.ignore_case,       cmd_boolean },
+  { "ignorelength",     &opt.ignore_length,     cmd_boolean },
+  { "ignoretags",       &opt.ignore_tags,       cmd_vector },
+  { "includedirectories", &opt.includes,        cmd_directory_vector },
 #ifdef ENABLE_IPV6
-  { "inet4only",       &opt.ipv4_only,         cmd_boolean },
-  { "inet6only",       &opt.ipv6_only,         cmd_boolean },
+  { "inet4only",        &opt.ipv4_only,         cmd_boolean },
+  { "inet6only",        &opt.ipv6_only,         cmd_boolean },
 #endif
-  { "input",           &opt.input_filename,    cmd_file },
+  { "input",            &opt.input_filename,    cmd_file },
   { "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
-  { "killlonger",      &opt.kill_longer,       cmd_boolean },
-  { "limitrate",       &opt.limit_rate,        cmd_bytes },
-  { "loadcookies",     &opt.cookies_input,     cmd_file },
-  { "logfile",         &opt.lfilename,         cmd_file },
-  { "login",           &opt.ftp_user,          cmd_string },/* deprecated*/
-  { "mirror",          NULL,                   cmd_spec_mirror },
-  { "netrc",           &opt.netrc,             cmd_boolean },
-  { "noclobber",       &opt.noclobber,         cmd_boolean },
-  { "noparent",                &opt.no_parent,         cmd_boolean },
-  { "noproxy",         &opt.no_proxy,          cmd_vector },
-  { "numtries",                &opt.ntry,              cmd_number_inf },/* deprecated*/
-  { "outputdocument",  &opt.output_document,   cmd_file },
-  { "pagerequisites",  &opt.page_requisites,   cmd_boolean },
-  { "passiveftp",      &opt.ftp_pasv,          cmd_boolean },
-  { "passwd",          &opt.ftp_passwd,        cmd_string },/* deprecated*/
-  { "password",                &opt.passwd,            cmd_string },
-  { "postdata",                &opt.post_data,         cmd_string },
-  { "postfile",                &opt.post_file_name,    cmd_file },
-  { "preferfamily",    NULL,                   cmd_spec_prefer_family },
-  { "preservepermissions", &opt.preserve_perm, cmd_boolean },
+  { "limitrate",        &opt.limit_rate,        cmd_bytes },
+  { "loadcookies",      &opt.cookies_input,     cmd_file },
+  { "logfile",          &opt.lfilename,         cmd_file },
+  { "login",            &opt.ftp_user,          cmd_string },/* deprecated*/
+  { "maxredirect",      &opt.max_redirect,      cmd_number },
+  { "mirror",           NULL,                   cmd_spec_mirror },
+  { "netrc",            &opt.netrc,             cmd_boolean },
+  { "noclobber",        &opt.noclobber,         cmd_boolean },
+  { "noparent",         &opt.no_parent,         cmd_boolean },
+  { "noproxy",          &opt.no_proxy,          cmd_vector },
+  { "numtries",         &opt.ntry,              cmd_number_inf },/* deprecated*/
+  { "outputdocument",   &opt.output_document,   cmd_file },
+  { "pagerequisites",   &opt.page_requisites,   cmd_boolean },
+  { "passiveftp",       &opt.ftp_pasv,          cmd_boolean },
+  { "passwd",           &opt.ftp_passwd,        cmd_string },/* deprecated*/
+  { "password",         &opt.passwd,            cmd_string },
+  { "postdata",         &opt.post_data,         cmd_string },
+  { "postfile",         &opt.post_file_name,    cmd_file },
+  { "preferfamily",     NULL,                   cmd_spec_prefer_family },
+  { "preservepermissions", &opt.preserve_perm,  cmd_boolean },
 #ifdef HAVE_SSL
-  { "privatekey",      &opt.private_key,       cmd_file },
-  { "privatekeytype",  &opt.private_key_type,  cmd_cert_type },
+  { "privatekey",       &opt.private_key,       cmd_file },
+  { "privatekeytype",   &opt.private_key_type,  cmd_cert_type },
 #endif
-  { "progress",                &opt.progress_type,     cmd_spec_progress },
+  { "progress",         &opt.progress_type,     cmd_spec_progress },
   { "protocoldirectories", &opt.protocol_directories, cmd_boolean },
-  { "proxypasswd",     &opt.proxy_passwd,      cmd_string }, /* deprecated */
-  { "proxypassword",   &opt.proxy_passwd,      cmd_string },
-  { "proxyuser",       &opt.proxy_user,        cmd_string },
-  { "quiet",           &opt.quiet,             cmd_boolean },
-  { "quota",           &opt.quota,             cmd_bytes_large },
+  { "proxypasswd",      &opt.proxy_passwd,      cmd_string }, /* deprecated */
+  { "proxypassword",    &opt.proxy_passwd,      cmd_string },
+  { "proxyuser",        &opt.proxy_user,        cmd_string },
+  { "quiet",            &opt.quiet,             cmd_boolean },
+  { "quota",            &opt.quota,             cmd_bytes_sum },
 #ifdef HAVE_SSL
-  { "randomfile",      &opt.random_file,       cmd_file },
+  { "randomfile",       &opt.random_file,       cmd_file },
 #endif
-  { "randomwait",      &opt.random_wait,       cmd_boolean },
-  { "readtimeout",     &opt.read_timeout,      cmd_time },
-  { "reclevel",                &opt.reclevel,          cmd_number_inf },
-  { "recursive",       NULL,                   cmd_spec_recursive },
-  { "referer",         &opt.referer,           cmd_string },
-  { "reject",          &opt.rejects,           cmd_vector },
-  { "relativeonly",    &opt.relative_only,     cmd_boolean },
-  { "removelisting",   &opt.remove_listing,    cmd_boolean },
-  { "restrictfilenames", NULL,                 cmd_spec_restrict_file_names },
-  { "retrsymlinks",    &opt.retr_symlinks,     cmd_boolean },
-  { "retryconnrefused",        &opt.retry_connrefused, cmd_boolean },
-  { "robots",          &opt.use_robots,        cmd_boolean },
-  { "savecookies",     &opt.cookies_output,    cmd_file },
-  { "saveheaders",     &opt.save_headers,      cmd_boolean },
+  { "randomwait",       &opt.random_wait,       cmd_boolean },
+  { "readtimeout",      &opt.read_timeout,      cmd_time },
+  { "reclevel",         &opt.reclevel,          cmd_number_inf },
+  { "recursive",        NULL,                   cmd_spec_recursive },
+  { "referer",          &opt.referer,           cmd_string },
+  { "reject",           &opt.rejects,           cmd_vector },
+  { "relativeonly",     &opt.relative_only,     cmd_boolean },
+  { "removelisting",    &opt.remove_listing,    cmd_boolean },
+  { "restrictfilenames", NULL,                  cmd_spec_restrict_file_names },
+  { "retrsymlinks",     &opt.retr_symlinks,     cmd_boolean },
+  { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
+  { "robots",           &opt.use_robots,        cmd_boolean },
+  { "savecookies",      &opt.cookies_output,    cmd_file },
+  { "saveheaders",      &opt.save_headers,      cmd_boolean },
 #ifdef HAVE_SSL
-  { "secureprotocol",  &opt.secure_protocol,   cmd_spec_secure_protocol },
+  { "secureprotocol",   &opt.secure_protocol,   cmd_spec_secure_protocol },
+#endif
+  { "serverresponse",   &opt.server_response,   cmd_boolean },
+  { "spanhosts",        &opt.spanhost,          cmd_boolean },
+  { "spider",           &opt.spider,            cmd_boolean },
+  { "strictcomments",   &opt.strict_comments,   cmd_boolean },
+  { "timeout",          NULL,                   cmd_spec_timeout },
+  { "timestamping",     &opt.timestamping,      cmd_boolean },
+  { "tries",            &opt.ntry,              cmd_number_inf },
+  { "useproxy",         &opt.use_proxy,         cmd_boolean },
+  { "user",             &opt.user,              cmd_string },
+  { "useragent",        NULL,                   cmd_spec_useragent },
+  { "verbose",          NULL,                   cmd_spec_verbose },
+  { "wait",             &opt.wait,              cmd_time },
+  { "waitretry",        &opt.waitretry,         cmd_time },
+#ifdef MSDOS
+  { "wdebug",           &opt.wdebug,            cmd_boolean },
 #endif
-  { "serverresponse",  &opt.server_response,   cmd_boolean },
-  { "spanhosts",       &opt.spanhost,          cmd_boolean },
-  { "spider",          &opt.spider,            cmd_boolean },
-  { "strictcomments",  &opt.strict_comments,   cmd_boolean },
-  { "timeout",         NULL,                   cmd_spec_timeout },
-  { "timestamping",    &opt.timestamping,      cmd_boolean },
-  { "tries",           &opt.ntry,              cmd_number_inf },
-  { "useproxy",                &opt.use_proxy,         cmd_boolean },
-  { "user",            &opt.user,              cmd_string },
-  { "useragent",       NULL,                   cmd_spec_useragent },
-  { "verbose",         &opt.verbose,           cmd_boolean },
-  { "wait",            &opt.wait,              cmd_time },
-  { "waitretry",       &opt.waitretry,         cmd_time }
 };
 
 /* Look up CMDNAME in the commands[] and return its position in the
@@ -250,11 +262,11 @@ command_by_name (const char *cmdname)
       int mid = (lo + hi) >> 1;
       int cmp = strcasecmp (cmdname, commands[mid].name);
       if (cmp < 0)
-       hi = mid - 1;
+        hi = mid - 1;
       else if (cmp > 0)
-       lo = mid + 1;
+        lo = mid + 1;
       else
-       return mid;
+        return mid;
     }
   return -1;
 }
@@ -304,12 +316,15 @@ defaults (void)
 #endif
 
   /* The default for file name restriction defaults to the OS type. */
-#if !defined(WINDOWS) && !defined(__CYGWIN__)
-  opt.restrict_files_os = restrict_unix;
-#else
+#if defined(WINDOWS) || defined(MSDOS) || defined(__CYGWIN__)
   opt.restrict_files_os = restrict_windows;
+#else
+  opt.restrict_files_os = restrict_unix;
 #endif
   opt.restrict_files_ctrl = true;
+  opt.restrict_files_case = restrict_no_case_restriction;
+
+  opt.max_redirect = 20;
 }
 \f
 /* Return the user's home directory (strdup-ed), or NULL if none is
@@ -321,14 +336,27 @@ home_dir (void)
 
   if (!home)
     {
-#ifndef WINDOWS
+#if defined(MSDOS)
+      /* Under MSDOS, if $HOME isn't defined, use the directory where
+         `wget.exe' resides.  */
+      const char *_w32_get_argv0 (void); /* in libwatt.a/pcconfig.c */
+      char *p, buf[PATH_MAX];
+
+      strcpy (buf, _w32_get_argv0 ());
+      p = strrchr (buf, '/');            /* djgpp */
+      if (!p)
+        p = strrchr (buf, '\\');          /* others */
+      assert (p);
+      *p = '\0';
+      home = buf;
+#elif !defined(WINDOWS)
       /* If HOME is not defined, try getting it from the password
          file.  */
       struct passwd *pwd = getpwuid (getuid ());
       if (!pwd || !pwd->pw_dir)
-       return NULL;
+        return NULL;
       home = pwd->pw_dir;
-#else  /* WINDOWS */
+#else  /* !WINDOWS */
       /* Under Windows, if $HOME isn't defined, use the directory where
          `wget.exe' resides.  */
       home = ws_mypath ();
@@ -354,11 +382,11 @@ wgetrc_file_name (void)
   if (env && *env)
     {
       if (!file_exists_p (env))
-       {
-         fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
-                  exec_name, env);
-         exit (1);
-       }
+        {
+          fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
+                   exec_name, env);
+          exit (1);
+        }
       return xstrdup (env);
     }
 
@@ -379,7 +407,7 @@ wgetrc_file_name (void)
       file = NULL;
       home = ws_mypath ();
       if (home)
-       file = aprintf ("%s/wget.ini", home);
+        file = aprintf ("%s/wget.ini", home);
     }
 #endif /* WINDOWS */
 
@@ -419,8 +447,8 @@ run_wgetrc (const char *file)
   if (!fp)
     {
       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
-              file, strerror (errno));
-      return true;                     /* not a fatal error */
+               file, strerror (errno));
+      return true;                      /* not a fatal error */
     }
   enable_tilde_expansion = true;
   ln = 1;
@@ -431,31 +459,31 @@ run_wgetrc (const char *file)
 
       /* Parse the line.  */
       switch (parse_line (line, &com, &val, &comind))
-       {
-       case line_ok:
-         /* If everything is OK, set the value.  */
-         if (!setval_internal (comind, com, val))
-           {
-             fprintf (stderr, _("%s: Error in %s at line %d.\n"),
-                      exec_name, file, ln);
-             ++errcnt;
-           }
-         break;
-       case line_syntax_error:
-         fprintf (stderr, _("%s: Syntax error in %s at line %d.\n"),
-                  exec_name, file, ln);
-         ++errcnt;
-         break;
-       case line_unknown_command:
-         fprintf (stderr, _("%s: Unknown command `%s' in %s at line %d.\n"),
-                  exec_name, com, file, ln);
-         ++errcnt;
-         break;
-       case line_empty:
-         break;
-       default:
-         abort ();
-       }
+        {
+        case line_ok:
+          /* If everything is OK, set the value.  */
+          if (!setval_internal (comind, com, val))
+            {
+              fprintf (stderr, _("%s: Error in %s at line %d.\n"),
+                       exec_name, file, ln);
+              ++errcnt;
+            }
+          break;
+        case line_syntax_error:
+          fprintf (stderr, _("%s: Syntax error in %s at line %d.\n"),
+                   exec_name, file, ln);
+          ++errcnt;
+          break;
+        case line_unknown_command:
+          fprintf (stderr, _("%s: Unknown command `%s' in %s at line %d.\n"),
+                   exec_name, com, file, ln);
+          ++errcnt;
+          break;
+        case line_empty:
+          break;
+        default:
+          abort ();
+        }
       xfree_null (com);
       xfree_null (val);
       xfree (line);
@@ -494,7 +522,7 @@ initialize (void)
     {
       fprintf (stderr, _("\
 %s: Warning: Both system and user wgetrc point to `%s'.\n"),
-              exec_name, file);
+               exec_name, file);
     }
   else
 #endif
@@ -514,8 +542,8 @@ initialize (void)
 static void
 dehyphen (char *s)
 {
-  char *t = s;                 /* t - tortoise */
-  char *h = s;                 /* h - hare     */
+  char *t = s;                  /* t - tortoise */
+  char *h = s;                  /* h - hare     */
   while (*h)
     if (*h == '_' || *h == '-')
       ++h;
@@ -547,9 +575,9 @@ parse_line (const char *line, char **com, char **val, int *comind)
   int ind;
 
   /* Skip leading and trailing whitespace.  */
-  while (*line && ISSPACE (*line))
+  while (*line && c_isspace (*line))
     ++line;
-  while (end > line && ISSPACE (end[-1]))
+  while (end > line && c_isspace (end[-1]))
     --end;
 
   /* Skip empty lines and comments.  */
@@ -559,17 +587,17 @@ parse_line (const char *line, char **com, char **val, int *comind)
   p = line;
 
   cmdstart = p;
-  while (p < end && (ISALPHA (*p) || *p == '_' || *p == '-'))
+  while (p < end && (c_isalnum (*p) || *p == '_' || *p == '-'))
     ++p;
   cmdend = p;
 
   /* Skip '=', as well as any space before or after it. */
-  while (p < end && ISSPACE (*p))
+  while (p < end && c_isspace (*p))
     ++p;
   if (p == end || *p != '=')
     return line_syntax_error;
   ++p;
-  while (p < end && ISSPACE (*p))
+  while (p < end && c_isspace (*p))
     ++p;
 
   valstart = p;
@@ -640,13 +668,13 @@ run_command (const char *opt)
     {
     case line_ok:
       if (!setval_internal (comind, com, val))
-       exit (2);
+        exit (2);
       xfree (com);
       xfree (val);
       break;
     default:
       fprintf (stderr, _("%s: Invalid --execute command `%s'\n"),
-              exec_name, opt);
+               exec_name, opt);
       exit (2);
     }
 }
@@ -662,16 +690,16 @@ static bool decode_string (const char *, const struct decode_item *, int, int *)
 static bool simple_atoi (const char *, const char *, int *);
 static bool simple_atof (const char *, const char *, double *);
 
-#define CMP1(p, c0) (TOLOWER((p)[0]) == (c0) && (p)[1] == '\0')
+#define CMP1(p, c0) (c_tolower((p)[0]) == (c0) && (p)[1] == '\0')
 
-#define CMP2(p, c0, c1) (TOLOWER((p)[0]) == (c0)       \
-                        && TOLOWER((p)[1]) == (c1)     \
-                        && (p)[2] == '\0')
+#define CMP2(p, c0, c1) (c_tolower((p)[0]) == (c0)        \
+                         && c_tolower((p)[1]) == (c1)     \
+                         && (p)[2] == '\0')
 
-#define CMP3(p, c0, c1, c2) (TOLOWER((p)[0]) == (c0)   \
-                    && TOLOWER((p)[1]) == (c1)         \
-                    && TOLOWER((p)[2]) == (c2)         \
-                    && (p)[3] == '\0')
+#define CMP3(p, c0, c1, c2) (c_tolower((p)[0]) == (c0)    \
+                     && c_tolower((p)[1]) == (c1)         \
+                     && c_tolower((p)[2]) == (c2)         \
+                     && (p)[3] == '\0')
 
 
 /* Store the boolean value from VAL to PLACE.  COM is ignored,
@@ -690,8 +718,8 @@ cmd_boolean (const char *com, const char *val, void *place)
   else
     {
       fprintf (stderr,
-              _("%s: %s: Invalid boolean `%s'; use `on' or `off'.\n"),
-              exec_name, com, val);
+               _("%s: %s: Invalid boolean `%s'; use `on' or `off'.\n"),
+               exec_name, com, val);
       return false;
     }
 
@@ -708,7 +736,7 @@ cmd_number (const char *com, const char *val, void *place)
       || *(int *) place < 0)
     {
       fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"),
-              exec_name, com, val);
+               exec_name, com, val);
       return false;
     }
   return true;
@@ -738,10 +766,10 @@ cmd_string (const char *com, const char *val, void *place)
   return true;
 }
 
-#ifndef WINDOWS
-# define ISSEP(c) ((c) == '/')
-#else
+#if defined(WINDOWS) || defined(MSDOS)
 # define ISSEP(c) ((c) == '/' || (c) == '\\')
+#else
+# define ISSEP(c) ((c) == '/')
 #endif
 
 /* Like the above, but handles tilde-expansion when reading a user's
@@ -766,26 +794,26 @@ cmd_file (const char *com, const char *val, void *place)
       int homelen;
       char *home = home_dir ();
       if (!home)
-       goto noexpand;
+        goto noexpand;
 
       homelen = strlen (home);
       while (homelen && ISSEP (home[homelen - 1]))
-       home[--homelen] = '\0';
+        home[--homelen] = '\0';
 
       /* Skip the leading "~/". */
       for (++val; ISSEP (*val); val++)
-       ;
+        ;
 
       *pstring = concat_strings (home, "/", val, (char *) 0);
     }
 
-#ifdef WINDOWS
+#if defined(WINDOWS) || defined(MSDOS)
   /* Convert "\" to "/". */
   {
     char *s;
     for (s = *pstring; *s; s++)
       if (*s == '\\')
-       *s = '/';
+        *s = '/';
   }
 #endif
   return true;
@@ -842,15 +870,15 @@ cmd_directory_vector (const char *com, const char *val, void *place)
 
       seps = sepstring (val);
       for (t = seps; t && *t; t++)
-       {
-         int len = strlen (*t);
-         /* Skip degenerate case of root directory.  */
-         if (len > 1)
-           {
-             if ((*t)[len - 1] == '/')
-               (*t)[len - 1] = '\0';
-           }
-       }
+        {
+          int len = strlen (*t);
+          /* Skip degenerate case of root directory.  */
+          if (len > 1)
+            {
+              if ((*t)[len - 1] == '/')
+                (*t)[len - 1] = '\0';
+            }
+        }
       *pvec = merge_vecs (*pvec, seps);
     }
   else
@@ -861,7 +889,7 @@ cmd_directory_vector (const char *com, const char *val, void *place)
   return true;
 }
 
-/* Engine for cmd_bytes and cmd_bytes_large: converts a string such as
+/* Engine for cmd_bytes and cmd_bytes_sum: converts a string such as
    "100k" or "2.5G" to a floating point number.  */
 
 static bool
@@ -878,12 +906,12 @@ parse_bytes_helper (const char *val, double *result)
     }
 
   /* Strip trailing whitespace.  */
-  while (val < end && ISSPACE (end[-1]))
+  while (val < end && c_isspace (end[-1]))
     --end;
   if (val == end)
     return false;
 
-  switch (TOLOWER (end[-1]))
+  switch (c_tolower (end[-1]))
     {
     case 'k':
       --end, mult = 1024.0;
@@ -899,14 +927,14 @@ parse_bytes_helper (const char *val, double *result)
       break;
     default:
       /* Not a recognized suffix: assume it's a digit.  (If not,
-        simple_atof will raise an error.)  */
+         simple_atof will raise an error.)  */
       mult = 1;
     }
 
   /* Skip leading and trailing whitespace. */
-  while (val < end && ISSPACE (*val))
+  while (val < end && c_isspace (*val))
     ++val;
-  while (val < end && ISSPACE (end[-1]))
+  while (val < end && c_isspace (end[-1]))
     --end;
   if (val == end)
     return false;
@@ -939,7 +967,7 @@ cmd_bytes (const char *com, const char *val, void *place)
   if (!parse_bytes_helper (val, &byte_value))
     {
       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
-              exec_name, com, val);
+               exec_name, com, val);
       return false;
     }
   *(wgint *)place = (wgint)byte_value;
@@ -947,21 +975,21 @@ cmd_bytes (const char *com, const char *val, void *place)
 }
 
 /* Like cmd_bytes, but PLACE is interpreted as a pointer to
-   LARGE_INT.  It works by converting the string to double, therefore
+   SIZE_SUM.  It works by converting the string to double, therefore
    working with values up to 2^53-1 without loss of precision.  This
    value (8192 TB) is large enough to serve for a while.  */
 
 static bool
-cmd_bytes_large (const char *com, const char *val, void *place)
+cmd_bytes_sum (const char *com, const char *val, void *place)
 {
   double byte_value;
   if (!parse_bytes_helper (val, &byte_value))
     {
       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
-              exec_name, com, val);
+               exec_name, com, val);
       return false;
     }
-  *(LARGE_INT *)place = (LARGE_INT)byte_value;
+  *(SUM_SIZE_INT *) place = (SUM_SIZE_INT) byte_value;
   return true;
 }
 
@@ -976,44 +1004,44 @@ cmd_time (const char *com, const char *val, void *place)
   const char *end = val + strlen (val);
 
   /* Strip trailing whitespace.  */
-  while (val < end && ISSPACE (end[-1]))
+  while (val < end && c_isspace (end[-1]))
     --end;
 
   if (val == end)
     {
     err:
       fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"),
-              exec_name, com, val);
+               exec_name, com, val);
       return false;
     }
 
-  switch (TOLOWER (end[-1]))
+  switch (c_tolower (end[-1]))
     {
     case 's':
-      --end, mult = 1;         /* seconds */
+      --end, mult = 1;          /* seconds */
       break;
     case 'm':
-      --end, mult = 60;                /* minutes */
+      --end, mult = 60;         /* minutes */
       break;
     case 'h':
-      --end, mult = 3600;      /* hours */
+      --end, mult = 3600;       /* hours */
       break;
     case 'd':
-      --end, mult = 86400.0;   /* days */
+      --end, mult = 86400.0;    /* days */
       break;
     case 'w':
-      --end, mult = 604800.0;  /* weeks */
+      --end, mult = 604800.0;   /* weeks */
       break;
     default:
       /* Not a recognized suffix: assume it belongs to the number.
-        (If not, simple_atof will raise an error.)  */
+         (If not, simple_atof will raise an error.)  */
       mult = 1;
     }
 
   /* Skip leading and trailing whitespace. */
-  while (val < end && ISSPACE (*val))
+  while (val < end && c_isspace (*val))
     ++val;
-  while (val < end && ISSPACE (end[-1]))
+  while (val < end && c_isspace (end[-1]))
     --end;
   if (val == end)
     goto err;
@@ -1074,7 +1102,7 @@ cmd_spec_header (const char *com, const char *val, void *place_ignored)
   if (!check_user_specified_header (val))
     {
       fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
-              exec_name, com, val);
+               exec_name, com, val);
       return false;
     }
   opt.user_headers = vec_append (opt.user_headers, val);
@@ -1104,7 +1132,7 @@ cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
     {
       opt.recursive = true;
       if (!opt.no_dirstruct)
-       opt.dirstruct = true;
+        opt.dirstruct = true;
       opt.timestamping = true;
       opt.reclevel = INFINITE_RECURSION;
       opt.remove_listing = false;
@@ -1123,10 +1151,11 @@ cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
     { "IPv6", prefer_ipv6 },
     { "none", prefer_none },
   };
-  int ok = decode_string (val, choices, countof (choices),
-                         (int *) &opt.prefer_family);
+  int prefer_family = prefer_ipv4;
+  int ok = decode_string (val, choices, countof (choices), &prefer_family);
   if (!ok)
     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
+  opt.prefer_family = prefer_family;
   return ok;
 }
 
@@ -1139,7 +1168,7 @@ cmd_spec_progress (const char *com, const char *val, void *place_ignored)
   if (!valid_progress_implementation_p (val))
     {
       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
-              exec_name, com, val);
+               exec_name, com, val);
       return false;
     }
   xfree_null (opt.progress_type);
@@ -1162,7 +1191,7 @@ cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
   else
     {
       if (opt.recursive && !opt.no_dirstruct)
-       opt.dirstruct = true;
+        opt.dirstruct = true;
     }
   return true;
 }
@@ -1172,40 +1201,47 @@ cmd_spec_restrict_file_names (const char *com, const char *val, void *place_igno
 {
   int restrict_os = opt.restrict_files_os;
   int restrict_ctrl = opt.restrict_files_ctrl;
+  int restrict_case = opt.restrict_files_case;
 
-  const char *end = strchr (val, ',');
-  if (!end)
-    end = val + strlen (val);
+  const char *end;
 
 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
 
-  if (VAL_IS ("unix"))
-    restrict_os = restrict_unix;
-  else if (VAL_IS ("windows"))
-    restrict_os = restrict_windows;
-  else if (VAL_IS ("nocontrol"))
-    restrict_ctrl = 0;
-  else
+  do
     {
-    err:
-      fprintf (stderr,
-              _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"),
-              exec_name, com, val);
-      return false;
+      end = strchr (val, ',');
+      if (!end)
+        end = val + strlen (val);
+      
+      if (VAL_IS ("unix"))
+        restrict_os = restrict_unix;
+      else if (VAL_IS ("windows"))
+        restrict_os = restrict_windows;
+      else if (VAL_IS ("lowercase"))
+        restrict_case = restrict_lowercase;
+      else if (VAL_IS ("uppercase"))
+        restrict_case = restrict_uppercase;
+      else if (VAL_IS ("nocontrol"))
+        restrict_ctrl = false;
+      else
+        {
+          fprintf (stderr,
+                   _("%s: %s: Invalid restriction `%s', use [unix|windows],[lowercase|uppercase],[nocontrol].\n"),
+                   exec_name, com, val);
+          return false;
+        }
+
+      if (*end) 
+        val = end + 1;
     }
+  while (*val && *end);
 
 #undef VAL_IS
 
-  if (*end)
-    {
-      if (!strcmp (end + 1, "nocontrol"))
-       restrict_ctrl = false;
-      else
-       goto err;
-    }
-
   opt.restrict_files_os = restrict_os;
   opt.restrict_files_ctrl = restrict_ctrl;
+  opt.restrict_files_case = restrict_case;
+  
   return true;
 }
 
@@ -1247,13 +1283,29 @@ cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
   if (strchr (val, '\n'))
     {
       fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
-              exec_name, com, val);
+               exec_name, com, val);
       return false;
     }
   xfree_null (opt.useragent);
   opt.useragent = xstrdup (val);
   return true;
 }
+
+/* The "verbose" option cannot be cmd_boolean because the variable is
+   not bool -- it's of type int (-1 means uninitialized because of
+   some random hackery for disallowing -q -v).  */
+
+static bool
+cmd_spec_verbose (const char *com, const char *val, void *place_ignored)
+{
+  bool flag;
+  if (cmd_boolean (com, val, &flag))
+    {
+      opt.verbose = flag;
+      return true;
+    }
+  return false;
+}
 \f
 /* Miscellaneous useful routines.  */
 
@@ -1268,7 +1320,7 @@ simple_atoi (const char *beg, const char *end, int *dest)
   bool negative = false;
   const char *p = beg;
 
-  while (p < end && ISSPACE (*p))
+  while (p < end && c_isspace (*p))
     ++p;
   if (p < end && (*p == '-' || *p == '+'))
     {
@@ -1282,20 +1334,20 @@ simple_atoi (const char *beg, const char *end, int *dest)
      negative integer cannot be represented as a positive number.  */
 
   if (!negative)
-    for (; p < end && ISDIGIT (*p); p++)
+    for (; p < end && c_isdigit (*p); p++)
       {
-       int next = (10 * result) + (*p - '0');
-       if (next < result)
-         return false;         /* overflow */
-       result = next;
+        int next = (10 * result) + (*p - '0');
+        if (next < result)
+          return false;         /* overflow */
+        result = next;
       }
   else
-    for (; p < end && ISDIGIT (*p); p++)
+    for (; p < end && c_isdigit (*p); p++)
       {
-       int next = (10 * result) - (*p - '0');
-       if (next > result)
-         return false;         /* underflow */
-       result = next;
+        int next = (10 * result) - (*p - '0');
+        if (next > result)
+          return false;         /* underflow */
+        result = next;
       }
 
   if (p != end)
@@ -1322,7 +1374,7 @@ simple_atof (const char *beg, const char *end, double *dest)
 
   const char *p = beg;
 
-  while (p < end && ISSPACE (*p))
+  while (p < end && c_isspace (*p))
     ++p;
   if (p < end && (*p == '-' || *p == '+'))
     {
@@ -1333,23 +1385,23 @@ simple_atof (const char *beg, const char *end, double *dest)
   for (; p < end; p++)
     {
       char ch = *p;
-      if (ISDIGIT (ch))
-       {
-         if (!seen_dot)
-           result = (10 * result) + (ch - '0');
-         else
-           result += (ch - '0') / (divider *= 10);
-         seen_digit = true;
-       }
+      if (c_isdigit (ch))
+        {
+          if (!seen_dot)
+            result = (10 * result) + (ch - '0');
+          else
+            result += (ch - '0') / (divider *= 10);
+          seen_digit = true;
+        }
       else if (ch == '.')
-       {
-         if (!seen_dot)
-           seen_dot = true;
-         else
-           return false;
-       }
+        {
+          if (!seen_dot)
+            seen_dot = true;
+          else
+            return false;
+        }
       else
-       return false;
+        return false;
     }
   if (!seen_digit)
     return false;
@@ -1369,7 +1421,8 @@ check_user_specified_header (const char *s)
 {
   const char *p;
 
-  for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
+  for (p = s; *p && *p != ':' && !c_isspace (*p); p++)
+    ;
   /* The header MUST contain `:' preceded by at least one
      non-whitespace character.  */
   if (*p != ':' || p == s)
@@ -1384,21 +1437,20 @@ check_user_specified_header (const char *s)
 
 static bool
 decode_string (const char *val, const struct decode_item *items, int itemcount,
-              int *place)
+               int *place)
 {
   int i;
   for (i = 0; i < itemcount; i++)
     if (0 == strcasecmp (val, items[i].name))
       {
-       *place = items[i].code;
-       return true;
+        *place = items[i].code;
+        return true;
       }
   return false;
 }
 
 \f
 void cleanup_html_url (void);
-void http_cleanup (void);
 
 
 /* Free the memory allocated by global variables.  */
@@ -1407,13 +1459,10 @@ cleanup (void)
 {
   /* Free external resources, close files, etc. */
 
-  {
-    extern FILE *output_stream;
-    if (output_stream)
-      fclose (output_stream);
-    /* No need to check for error because Wget flushes its output (and
-       checks for errors) after any data arrives.  */
-  }
+  if (output_stream)
+    fclose (output_stream);
+  /* No need to check for error because Wget flushes its output (and
+     checks for errors) after any data arrives.  */
 
   /* We're exiting anyway so there's no real need to call free()
      hundreds of times.  Skipping the frees will make Wget exit
@@ -1473,3 +1522,50 @@ cleanup (void)
   xfree_null (opt.passwd);
 #endif /* DEBUG_MALLOC */
 }
+\f
+/* Unit testing routines.  */
+
+#ifdef TESTING
+
+const char *
+test_cmd_spec_restrict_file_names()
+{
+  int i;
+  struct {
+    char *val;
+    int expected_restrict_files_os;
+    int expected_restrict_files_ctrl;
+    int expected_restrict_files_case;
+    bool result;
+  } test_array[] = {
+    { "windows", restrict_windows, true, restrict_no_case_restriction, true },
+    { "windows,", restrict_windows, true, restrict_no_case_restriction, true },
+    { "windows,lowercase", restrict_windows, true, restrict_lowercase, true },
+    { "unix,nocontrol,lowercase,", restrict_unix, false, restrict_lowercase, true },
+  };
+  
+  for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i) 
+    {
+      bool res;
+      
+      defaults();
+      res = cmd_spec_restrict_file_names ("dummy", test_array[i].val, NULL);
+
+      /*
+      fprintf (stderr, "test_cmd_spec_restrict_file_names: TEST %d\n", i); fflush (stderr);
+      fprintf (stderr, "opt.restrict_files_os: %d\n",   opt.restrict_files_os); fflush (stderr);
+      fprintf (stderr, "opt.restrict_files_ctrl: %d\n", opt.restrict_files_ctrl); fflush (stderr);
+      fprintf (stderr, "opt.restrict_files_case: %d\n", opt.restrict_files_case); fflush (stderr);
+      */
+      mu_assert ("test_cmd_spec_restrict_file_names: wrong result", 
+                 res == test_array[i].result
+                 && opt.restrict_files_os   == test_array[i].expected_restrict_files_os 
+                 && opt.restrict_files_ctrl == test_array[i].expected_restrict_files_ctrl 
+                 && opt.restrict_files_case == test_array[i].expected_restrict_files_case);
+    }
+
+  return NULL;
+}
+
+#endif /* TESTING */
+