]> sjero.net Git - wget/blobdiff - src/init.c
Fix compiler warnings
[wget] / src / init.c
index 2e51291a997ed450512a1f4dc1144a810e9ba5f4..fbef133cf9d295217b1a166b996ccb5cfaf67242 100644 (file)
@@ -1,11 +1,13 @@
 /* Reading/parsing the initialization file.
 /* Reading/parsing the initialization file.
-   Copyright (C) 1996-2005 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 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
 
 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,
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,51 +16,64 @@ 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
 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.,
-51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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
-OpenSSL project's "OpenSSL" library (or with modified versions of it
-that use the same license as the "OpenSSL" library), and distribute
-the linked executables.  You must obey the GNU General Public License
-in all respects for all of the code used other than "OpenSSL".  If you
-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.  */
+Additional permission under GNU GPL version 3 section 7
 
 
-#include <config.h>
+If you modify this program, or any covered work, by linking or
+combining it with the OpenSSL project's OpenSSL library (or a
+modified version of that library), containing parts covered by the
+terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+grants you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts of OpenSSL used as well
+as that of the covered work.  */
+
+#include "wget.h"
+#include "exits.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <stdbool.h>
+#include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <string.h>
 #include <errno.h>
+#include <limits.h>
+/* not all systems provide PATH_MAX in limits.h */
+#ifndef PATH_MAX
+# include <sys/param.h>
+# ifndef PATH_MAX
+#  define PATH_MAX MAXPATHLEN
+# endif
+#endif
+
+#include <regex.h>
+#ifdef HAVE_LIBPCRE
+# include <pcre.h>
+#endif
 
 #ifdef HAVE_PWD_H
 # include <pwd.h>
 #endif
 #include <assert.h>
 
 
 #ifdef HAVE_PWD_H
 # include <pwd.h>
 #endif
 #include <assert.h>
 
-#include "wget.h"
 #include "utils.h"
 #include "init.h"
 #include "host.h"
 #include "netrc.h"
 #include "progress.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 "http.h"              /* for http_cleanup */
-#include "retr.h"              /* for output_stream */
-
-/* We want tilde expansion enabled only when reading `.wgetrc' lines;
-   otherwise, it will be performed by the shell.  This variable will
-   be set by the wgetrc-reading function.  */
+#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 */
+#include "warc.h"               /* for warc_close */
+#include "spider.h"             /* for spider_cleanup */
+
+#ifdef TESTING
+#include "test.h"
+#endif
 
 
-static bool enable_tilde_expansion;
 
 
 #define CMD_DECLARE(func) static bool func (const char *, const char *, void *)
 
 
 #define CMD_DECLARE(func) static bool func (const char *, const char *, void *)
@@ -73,6 +88,7 @@ CMD_DECLARE (cmd_directory_vector);
 CMD_DECLARE (cmd_number);
 CMD_DECLARE (cmd_number_inf);
 CMD_DECLARE (cmd_string);
 CMD_DECLARE (cmd_number);
 CMD_DECLARE (cmd_number_inf);
 CMD_DECLARE (cmd_string);
+CMD_DECLARE (cmd_string_uppercase);
 CMD_DECLARE (cmd_file);
 CMD_DECLARE (cmd_directory);
 CMD_DECLARE (cmd_time);
 CMD_DECLARE (cmd_file);
 CMD_DECLARE (cmd_directory);
 CMD_DECLARE (cmd_time);
@@ -80,12 +96,15 @@ CMD_DECLARE (cmd_vector);
 
 CMD_DECLARE (cmd_spec_dirstruct);
 CMD_DECLARE (cmd_spec_header);
 
 CMD_DECLARE (cmd_spec_dirstruct);
 CMD_DECLARE (cmd_spec_header);
+CMD_DECLARE (cmd_spec_warc_header);
 CMD_DECLARE (cmd_spec_htmlify);
 CMD_DECLARE (cmd_spec_mirror);
 CMD_DECLARE (cmd_spec_prefer_family);
 CMD_DECLARE (cmd_spec_progress);
 CMD_DECLARE (cmd_spec_recursive);
 CMD_DECLARE (cmd_spec_htmlify);
 CMD_DECLARE (cmd_spec_mirror);
 CMD_DECLARE (cmd_spec_prefer_family);
 CMD_DECLARE (cmd_spec_progress);
 CMD_DECLARE (cmd_spec_recursive);
+CMD_DECLARE (cmd_spec_regex_type);
 CMD_DECLARE (cmd_spec_restrict_file_names);
 CMD_DECLARE (cmd_spec_restrict_file_names);
+CMD_DECLARE (cmd_spec_report_speed);
 #ifdef HAVE_SSL
 CMD_DECLARE (cmd_spec_secure_protocol);
 #endif
 #ifdef HAVE_SSL
 CMD_DECLARE (cmd_spec_secure_protocol);
 #endif
@@ -96,147 +115,191 @@ 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
 /* 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[] = {
   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 },
+  { "acceptregex",      &opt.acceptregex_s,     cmd_string },
+  { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
+  { "adjustextension",  &opt.adjust_extension,  cmd_boolean },
+  { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
+  { "askpassword",      &opt.ask_passwd,        cmd_boolean },
+  { "authnochallenge",  &opt.auth_without_challenge,
+                                                cmd_boolean },
+  { "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 },
+  { "bodydata",         &opt.body_data,         cmd_string },
+  { "bodyfile",         &opt.body_file,         cmd_string },
 #ifdef HAVE_SSL
 #ifdef HAVE_SSL
-  { "cacertificate",   &opt.ca_cert,           cmd_file },
+  { "cacertificate",    &opt.ca_cert,           cmd_file },
 #endif
 #endif
-  { "cache",           &opt.allow_cache,       cmd_boolean },
+  { "cache",            &opt.allow_cache,       cmd_boolean },
 #ifdef HAVE_SSL
 #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
 #endif
-  { "connecttimeout",  &opt.connect_timeout,   cmd_time },
-  { "continue",                &opt.always_rest,       cmd_boolean },
-  { "convertlinks",    &opt.convert_links,     cmd_boolean },
+  { "chooseconfig",     &opt.choose_config,    cmd_file },
+  { "connecttimeout",   &opt.connect_timeout,   cmd_time },
   { "contentdisposition", &opt.content_disposition, cmd_boolean },
   { "contentdisposition", &opt.content_disposition, cmd_boolean },
-  { "cookies",         &opt.cookies,           cmd_boolean },
-  { "cutdirs",         &opt.cut_dirs,          cmd_number },
-#ifdef ENABLE_DEBUG
-  { "debug",           &opt.debug,             cmd_boolean },
+  { "contentonerror",   &opt.content_on_error,  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 },
+  { "debug",            &opt.debug,             cmd_boolean },
+  { "defaultpage",      &opt.default_page,      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 }, /* deprecated */
+#ifdef HAVE_SSL
+  { "egdfile",          &opt.egd_file,          cmd_file },
 #endif
 #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 },
+  { "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 },
+#ifdef __VMS
+  { "ftpstmlf",         &opt.ftp_stmlf,         cmd_boolean },
+#endif /* def __VMS */
+  { "ftpuser",          &opt.ftp_user,          cmd_string },
+  { "glob",             &opt.ftp_glob,          cmd_boolean },
+  { "header",           NULL,                   cmd_spec_header },
+  { "htmlextension",    &opt.adjust_extension,  cmd_boolean }, /* deprecated */
+  { "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 },
 #ifdef HAVE_SSL
 #ifdef HAVE_SSL
-  { "egdfile",         &opt.egd_file,          cmd_file },
+  { "httpsonly",        &opt.https_only,        cmd_boolean },
 #endif
 #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 },
-  { "ignorecase",      &opt.ignore_case,       cmd_boolean },
-  { "ignorelength",    &opt.ignore_length,     cmd_boolean },
-  { "ignoretags",      &opt.ignore_tags,       cmd_vector },
-  { "includedirectories", &opt.includes,       cmd_directory_vector },
+  { "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
 #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
 #endif
-  { "input",           &opt.input_filename,    cmd_file },
+  { "input",            &opt.input_filename,    cmd_file },
+  { "iri",              &opt.enable_iri,        cmd_boolean },
   { "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
   { "keepsessioncookies", &opt.keep_session_cookies, 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 },
+  { "localencoding",    &opt.locale,            cmd_string },
+  { "logfile",          &opt.lfilename,         cmd_file },
+  { "login",            &opt.ftp_user,          cmd_string },/* deprecated*/
+  { "maxredirect",      &opt.max_redirect,      cmd_number },
+  { "method",           &opt.method,            cmd_string_uppercase },
+  { "mirror",           NULL,                   cmd_spec_mirror },
+  { "netrc",            &opt.netrc,             cmd_boolean },
+  { "noclobber",        &opt.noclobber,         cmd_boolean },
+  { "noconfig",         &opt.noconfig,          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
 #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
 #endif
-  { "progress",                &opt.progress_type,     cmd_spec_progress },
+  { "progress",         &opt.progress_type,     cmd_spec_progress },
   { "protocoldirectories", &opt.protocol_directories, cmd_boolean },
   { "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_sum },
+  { "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
 #ifdef HAVE_SSL
-  { "randomfile",      &opt.random_file,       cmd_file },
+  { "randomfile",       &opt.random_file,       cmd_file },
 #endif
 #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 },
+  { "regextype",        &opt.regex_type,        cmd_spec_regex_type },
+  { "reject",           &opt.rejects,           cmd_vector },
+  { "rejectregex",      &opt.rejectregex_s,     cmd_string },
+  { "relativeonly",     &opt.relative_only,     cmd_boolean },
+  { "remoteencoding",   &opt.encoding_remote,   cmd_string },
+  { "removelisting",    &opt.remove_listing,    cmd_boolean },
+  { "reportspeed",             &opt.report_bps, cmd_spec_report_speed},
+  { "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
 #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 },
+  { "showalldnsentries", &opt.show_all_dns_entries, cmd_boolean },
+  { "showprogress",     &opt.show_progress,      cmd_boolean },
+  { "spanhosts",        &opt.spanhost,          cmd_boolean },
+  { "spider",           &opt.spider,            cmd_boolean },
+  { "startpos",         &opt.start_pos,         cmd_bytes },
+  { "strictcomments",   &opt.strict_comments,   cmd_boolean },
+  { "timeout",          NULL,                   cmd_spec_timeout },
+  { "timestamping",     &opt.timestamping,      cmd_boolean },
+  { "tries",            &opt.ntry,              cmd_number_inf },
+  { "trustservernames", &opt.trustservernames,  cmd_boolean },
+  { "unlink",           &opt.unlink,            cmd_boolean },
+  { "useproxy",         &opt.use_proxy,         cmd_boolean },
+  { "user",             &opt.user,              cmd_string },
+  { "useragent",        NULL,                   cmd_spec_useragent },
+  { "useservertimestamps", &opt.useservertimestamps, cmd_boolean },
+  { "verbose",          NULL,                   cmd_spec_verbose },
+  { "wait",             &opt.wait,              cmd_time },
+  { "waitretry",        &opt.waitretry,         cmd_time },
+  { "warccdx",          &opt.warc_cdx_enabled,  cmd_boolean },
+  { "warccdxdedup",     &opt.warc_cdx_dedup_filename,  cmd_file },
+#ifdef HAVE_LIBZ
+  { "warccompression",  &opt.warc_compression_enabled, cmd_boolean },
+#endif
+  { "warcdigests",      &opt.warc_digests_enabled, cmd_boolean },
+  { "warcfile",         &opt.warc_filename,     cmd_file },
+  { "warcheader",       NULL,                   cmd_spec_warc_header },
+  { "warckeeplog",      &opt.warc_keep_log,     cmd_boolean },
+  { "warcmaxsize",      &opt.warc_maxsize,      cmd_bytes },
+  { "warctempdir",      &opt.warc_tempdir,      cmd_directory },
+#ifdef USE_WATT32
+  { "wdebug",           &opt.wdebug,            cmd_boolean },
 #endif
 #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 }
 };
 
 /* Look up CMDNAME in the commands[] and return its position in the
 };
 
 /* Look up CMDNAME in the commands[] and return its position in the
@@ -254,17 +317,17 @@ command_by_name (const char *cmdname)
       int mid = (lo + hi) >> 1;
       int cmp = strcasecmp (cmdname, commands[mid].name);
       if (cmp < 0)
       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)
       else if (cmp > 0)
-       lo = mid + 1;
+        lo = mid + 1;
       else
       else
-       return mid;
+        return mid;
     }
   return -1;
 }
 \f
 /* Reset the variables to default values.  */
     }
   return -1;
 }
 \f
 /* Reset the variables to default values.  */
-static void
+void
 defaults (void)
 {
   char *tmp;
 defaults (void)
 {
   char *tmp;
@@ -289,6 +352,7 @@ defaults (void)
   tmp = getenv ("no_proxy");
   if (tmp)
     opt.no_proxy = sepstring (tmp);
   tmp = getenv ("no_proxy");
   if (tmp)
     opt.no_proxy = sepstring (tmp);
+  opt.prefer_family = prefer_none;
   opt.allow_cache = true;
 
   opt.read_timeout = 900;
   opt.allow_cache = true;
 
   opt.read_timeout = 900;
@@ -308,14 +372,47 @@ defaults (void)
 #endif
 
   /* The default for file name restriction defaults to the OS type. */
 #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;
   opt.restrict_files_os = restrict_windows;
+#else
+  opt.restrict_files_os = restrict_unix;
 #endif
   opt.restrict_files_ctrl = true;
 #endif
   opt.restrict_files_ctrl = true;
+  opt.restrict_files_nonascii = false;
+  opt.restrict_files_case = restrict_no_case_restriction;
+
+  opt.regex_type = regex_type_posix;
+
+  opt.max_redirect = 20;
+
+  opt.waitretry = 10;
+
+#ifdef ENABLE_IRI
+  opt.enable_iri = true;
+#else
+  opt.enable_iri = false;
+#endif
+  opt.locale = NULL;
+  opt.encoding_remote = NULL;
 
 
-  opt.content_disposition = true;
+  opt.useservertimestamps = true;
+  opt.show_all_dns_entries = false;
+
+  opt.warc_maxsize = 0; /* 1024 * 1024 * 1024; */
+#ifdef HAVE_LIBZ
+  opt.warc_compression_enabled = true;
+#else
+  opt.warc_compression_enabled = false;
+#endif
+  opt.warc_digests_enabled = true;
+  opt.warc_cdx_enabled = false;
+  opt.warc_cdx_dedup_filename = NULL;
+  opt.warc_tempdir = NULL;
+  opt.warc_keep_log = true;
+
+  /* Use a negative value to mark the absence of --start-pos option */
+  opt.start_pos = -1;
+  opt.show_progress = false;
 }
 \f
 /* Return the user's home directory (strdup-ed), or NULL if none is
 }
 \f
 /* Return the user's home directory (strdup-ed), or NULL if none is
@@ -323,79 +420,146 @@ defaults (void)
 char *
 home_dir (void)
 {
 char *
 home_dir (void)
 {
-  char *home = getenv ("HOME");
+  static char *buf = NULL;
+  static char *home, *ret;
 
   if (!home)
     {
 
   if (!home)
     {
-#ifndef 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;
-      home = pwd->pw_dir;
-#else  /* WINDOWS */
-      /* Under Windows, if $HOME isn't defined, use the directory where
-         `wget.exe' resides.  */
-      home = ws_mypath ();
+      home = getenv ("HOME");
+      if (!home)
+        {
+#if defined(MSDOS)
+          int len;
+
+          /* 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;
+
+          buff = _w32_get_argv0 ();
+
+          p = strrchr (buf, '/');            /* djgpp */
+          if (!p)
+            p = strrchr (buf, '\\');          /* others */
+          assert (p);
+
+          len = p - buff + 1;
+          buff = malloc (len + 1);
+          if (buff == NULL)
+            return NULL;
+
+          strncpy (buff, _w32_get_argv0 (), len);
+          buff[len] = '\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;
+          home = pwd->pw_dir;
+#else  /* !WINDOWS */
+          /* Under Windows, if $HOME isn't defined, use the directory where
+             `wget.exe' resides.  */
+          home = ws_mypath ();
 #endif /* WINDOWS */
 #endif /* WINDOWS */
+        }
     }
 
     }
 
-  return home ? xstrdup (home) : NULL;
-}
+  ret = home ? xstrdup (home) : NULL;
+  free (buf);
 
 
-/* Return the path to the user's .wgetrc.  This is either the value of
-   `WGETRC' environment variable, or `$HOME/.wgetrc'.
+  return ret;
+}
 
 
+/* Check the 'WGETRC' environment variable and return the file name
+   if  'WGETRC' is set and is a valid file.
    If the `WGETRC' variable exists but the file does not exist, the
    function will exit().  */
    If the `WGETRC' variable exists but the file does not exist, the
    function will exit().  */
-static char *
-wgetrc_file_name (void)
+char *
+wgetrc_env_file_name (void)
 {
 {
-  char *env, *home;
-  char *file = NULL;
-
-  /* Try the environment.  */
-  env = getenv ("WGETRC");
+  char *env = getenv ("WGETRC");
   if (env && *env)
     {
       if (!file_exists_p (env))
   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);
     }
       return xstrdup (env);
     }
+  return NULL;
+}
+
+/* Check for the existance of '$HOME/.wgetrc' and return its path
+   if it exists and is set.  */
+char *
+wgetrc_user_file_name (void)
+{
+  char *home;
+  char *file = NULL;
+  /* If that failed, try $HOME/.wgetrc (or equivalent).  */
 
 
-  /* If that failed, try $HOME/.wgetrc.  */
+#ifdef __VMS
+  file = "SYS$LOGIN:.wgetrc";
+#else /* def __VMS */
   home = home_dir ();
   if (home)
     file = aprintf ("%s/.wgetrc", home);
   xfree_null (home);
   home = home_dir ();
   if (home)
     file = aprintf ("%s/.wgetrc", home);
   xfree_null (home);
+#endif /* def __VMS [else] */
+
+  if (!file)
+    return NULL;
+  if (!file_exists_p (file))
+    {
+      xfree (file);
+      return NULL;
+    }
+  return file;
+}
+
+/* Return the path to the user's .wgetrc.  This is either the value of
+   `WGETRC' environment variable, or `$HOME/.wgetrc'.
+
+   Additionally, for windows, look in the directory where wget.exe
+   resides.  */
+char *
+wgetrc_file_name (void)
+{
+  char *file = wgetrc_env_file_name ();
+  if (file && *file)
+    return file;
+
+  file = wgetrc_user_file_name ();
 
 #ifdef WINDOWS
   /* Under Windows, if we still haven't found .wgetrc, look for the file
      `wget.ini' in the directory where `wget.exe' resides; we do this for
      backward compatibility with previous versions of Wget.
      SYSTEM_WGETRC should not be defined under WINDOWS.  */
 
 #ifdef WINDOWS
   /* Under Windows, if we still haven't found .wgetrc, look for the file
      `wget.ini' in the directory where `wget.exe' resides; we do this for
      backward compatibility with previous versions of Wget.
      SYSTEM_WGETRC should not be defined under WINDOWS.  */
-  if (!file || !file_exists_p (file))
+  if (!file)
     {
     {
+      char *home = home_dir ();
       xfree_null (file);
       file = NULL;
       home = ws_mypath ();
       if (home)
       xfree_null (file);
       file = NULL;
       home = ws_mypath ();
       if (home)
-       file = aprintf ("%s/wget.ini", home);
+        {
+          file = aprintf ("%s/wget.ini", home);
+          if (!file_exists_p (file))
+            {
+              xfree (file);
+              file = NULL;
+            }
+          xfree (home);
+        }
     }
 #endif /* WINDOWS */
 
     }
 #endif /* WINDOWS */
 
-  if (!file)
-    return NULL;
-  if (!file_exists_p (file))
-    {
-      xfree (file);
-      return NULL;
-    }
   return file;
 }
 
   return file;
 }
 
@@ -409,65 +573,65 @@ enum parse_line {
 
 static enum parse_line parse_line (const char *, char **, char **, int *);
 static bool setval_internal (int, const char *, const char *);
 
 static enum parse_line parse_line (const char *, char **, char **, int *);
 static bool setval_internal (int, const char *, const char *);
+static bool setval_internal_tilde (int, const char *, const char *);
 
 /* Initialize variables from a wgetrc file.  Returns zero (failure) if
    there were errors in the file.  */
 
 
 /* Initialize variables from a wgetrc file.  Returns zero (failure) if
    there were errors in the file.  */
 
-static bool
+bool
 run_wgetrc (const char *file)
 {
   FILE *fp;
 run_wgetrc (const char *file)
 {
   FILE *fp;
-  char *line;
+  char *line = NULL;
+  size_t bufsize = 0;
   int ln;
   int errcnt = 0;
 
   int ln;
   int errcnt = 0;
 
-  fp = fopen (file, "rb");
+  fp = fopen (file, "r");
   if (!fp)
     {
       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
   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;
   ln = 1;
-  while ((line = read_whole_line (fp)) != NULL)
+  while (getline (&line, &bufsize, fp) > 0)
     {
       char *com = NULL, *val = NULL;
       int comind;
 
       /* Parse the line.  */
       switch (parse_line (line, &com, &val, &comind))
     {
       char *com = NULL, *val = NULL;
       int comind;
 
       /* 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_tilde (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, quote (com), file, ln);
+          ++errcnt;
+          break;
+        case line_empty:
+          break;
+        default:
+          abort ();
+        }
       xfree_null (com);
       xfree_null (val);
       xfree_null (com);
       xfree_null (val);
-      xfree (line);
       ++ln;
     }
       ++ln;
     }
-  enable_tilde_expansion = false;
+  xfree (line);
   fclose (fp);
 
   return errcnt == 0;
   fclose (fp);
 
   return errcnt == 0;
@@ -478,16 +642,40 @@ run_wgetrc (const char *file)
 void
 initialize (void)
 {
 void
 initialize (void)
 {
-  char *file;
-  int ok = true;
-
-  /* Load the hard-coded defaults.  */
-  defaults ();
+  char *file, *env_sysrc;
+  bool ok = true;
 
 
-  /* If SYSTEM_WGETRC is defined, use it.  */
+  /* Run a non-standard system rc file when the according environment
+     variable has been set. For internal testing purposes only!  */
+  env_sysrc = getenv ("SYSTEM_WGETRC");
+  if (env_sysrc && file_exists_p (env_sysrc))
+    {
+      ok &= run_wgetrc (env_sysrc);
+      /* If there are any problems parsing the system wgetrc file, tell
+         the user and exit */
+      if (! ok)
+        {
+          fprintf (stderr, _("\
+Parsing system wgetrc file (env SYSTEM_WGETRC) failed.  Please check\n\
+'%s',\n\
+or specify a different file using --config.\n"), env_sysrc);
+          exit (2);
+        }
+    }
+  /* Otherwise, if SYSTEM_WGETRC is defined, use it.  */
 #ifdef SYSTEM_WGETRC
 #ifdef SYSTEM_WGETRC
-  if (file_exists_p (SYSTEM_WGETRC))
+  else if (file_exists_p (SYSTEM_WGETRC))
     ok &= run_wgetrc (SYSTEM_WGETRC);
     ok &= run_wgetrc (SYSTEM_WGETRC);
+  /* If there are any problems parsing the system wgetrc file, tell
+     the user and exit */
+  if (! ok)
+    {
+      fprintf (stderr, _("\
+Parsing system wgetrc file failed.  Please check\n\
+'%s',\n\
+or specify a different file using --config.\n"), SYSTEM_WGETRC);
+      exit (2);
+    }
 #endif
   /* Override it with your own, if one exists.  */
   file = wgetrc_file_name ();
 #endif
   /* Override it with your own, if one exists.  */
   file = wgetrc_file_name ();
@@ -499,8 +687,8 @@ initialize (void)
   if (!strcmp (file, SYSTEM_WGETRC))
     {
       fprintf (stderr, _("\
   if (!strcmp (file, SYSTEM_WGETRC))
     {
       fprintf (stderr, _("\
-%s: Warning: Both system and user wgetrc point to `%s'.\n"),
-              exec_name, file);
+%s: Warning: Both system and user wgetrc point to %s.\n"),
+               exec_name, quote (file));
     }
   else
 #endif
     }
   else
 #endif
@@ -513,15 +701,15 @@ initialize (void)
   xfree (file);
   return;
 }
   xfree (file);
   return;
 }
-\f
+
 /* Remove dashes and underscores from S, modifying S in the
    process. */
 
 static void
 dehyphen (char *s)
 {
 /* Remove dashes and underscores from S, modifying S in the
    process. */
 
 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;
   while (*h)
     if (*h == '_' || *h == '-')
       ++h;
@@ -553,9 +741,9 @@ parse_line (const char *line, char **com, char **val, int *comind)
   int ind;
 
   /* Skip leading and trailing whitespace.  */
   int ind;
 
   /* Skip leading and trailing whitespace.  */
-  while (*line && ISSPACE (*line))
+  while (*line && c_isspace (*line))
     ++line;
     ++line;
-  while (end > line && ISSPACE (end[-1]))
+  while (end > line && c_isspace (end[-1]))
     --end;
 
   /* Skip empty lines and comments.  */
     --end;
 
   /* Skip empty lines and comments.  */
@@ -565,17 +753,17 @@ parse_line (const char *line, char **com, char **val, int *comind)
   p = line;
 
   cmdstart = p;
   p = line;
 
   cmdstart = p;
-  while (p < end && (ISALNUM (*p) || *p == '_' || *p == '-'))
+  while (p < end && (c_isalnum (*p) || *p == '_' || *p == '-'))
     ++p;
   cmdend = p;
 
   /* Skip '=', as well as any space before or after it. */
     ++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;
     ++p;
   if (p == end || *p != '=')
     return line_syntax_error;
   ++p;
-  while (p < end && ISSPACE (*p))
+  while (p < end && c_isspace (*p))
     ++p;
 
   valstart = p;
     ++p;
 
   valstart = p;
@@ -599,16 +787,53 @@ parse_line (const char *line, char **com, char **val, int *comind)
   return line_ok;
 }
 
   return line_ok;
 }
 
+#if defined(WINDOWS) || defined(MSDOS)
+# define ISSEP(c) ((c) == '/' || (c) == '\\')
+#else
+# define ISSEP(c) ((c) == '/')
+#endif
+
 /* Run commands[comind].action. */
 
 static bool
 setval_internal (int comind, const char *com, const char *val)
 {
 /* Run commands[comind].action. */
 
 static bool
 setval_internal (int comind, const char *com, const char *val)
 {
-  assert (0 <= comind && comind < countof (commands));
+  assert (0 <= comind && ((size_t) comind) < countof (commands));
   DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
   return commands[comind].action (com, val, commands[comind].place);
 }
 
   DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
   return commands[comind].action (com, val, commands[comind].place);
 }
 
+static bool
+setval_internal_tilde (int comind, const char *com, const char *val)
+{
+  bool ret;
+  int homelen;
+  char *home;
+  char **pstring;
+  ret = setval_internal (comind, com, val);
+
+  /* We make tilde expansion for cmd_file and cmd_directory */
+  if (((commands[comind].action == cmd_file) ||
+       (commands[comind].action == cmd_directory))
+      && ret && (*val == '~' && ISSEP (val[1])))
+    {
+      pstring = commands[comind].place;
+      home = home_dir ();
+      if (home)
+       {
+         homelen = strlen (home);
+         while (homelen && ISSEP (home[homelen - 1]))
+            home[--homelen] = '\0';
+
+         /* Skip the leading "~/". */
+         for (++val; ISSEP (*val); val++)
+           ;
+         *pstring = concat_strings (home, "/", val, (char *)0);
+       }
+    }
+  return ret;
+}
+
 /* Run command COM with value VAL.  If running the command produces an
    error, report the error and exit.
 
 /* Run command COM with value VAL.  If running the command produces an
    error, report the error and exit.
 
@@ -638,21 +863,21 @@ setoptval (const char *com, const char *val, const char *optname)
    This is used by the `--execute' flag in main.c.  */
 
 void
    This is used by the `--execute' flag in main.c.  */
 
 void
-run_command (const char *opt)
+run_command (const char *cmdopt)
 {
   char *com, *val;
   int comind;
 {
   char *com, *val;
   int comind;
-  switch (parse_line (opt, &com, &val, &comind))
+  switch (parse_line (cmdopt, &com, &val, &comind))
     {
     case line_ok:
       if (!setval_internal (comind, com, val))
     {
     case line_ok:
       if (!setval_internal (comind, com, val))
-       exit (2);
+        exit (2);
       xfree (com);
       xfree (val);
       break;
     default:
       xfree (com);
       xfree (val);
       break;
     default:
-      fprintf (stderr, _("%s: Invalid --execute command `%s'\n"),
-              exec_name, opt);
+      fprintf (stderr, _("%s: Invalid --execute command %s\n"),
+               exec_name, quote (cmdopt));
       exit (2);
     }
 }
       exit (2);
     }
 }
@@ -668,16 +893,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 *);
 
 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,
 
 
 /* Store the boolean value from VAL to PLACE.  COM is ignored,
@@ -696,8 +921,8 @@ cmd_boolean (const char *com, const char *val, void *place)
   else
     {
       fprintf (stderr,
   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, quote (val));
       return false;
     }
 
       return false;
     }
 
@@ -713,8 +938,8 @@ cmd_number (const char *com, const char *val, void *place)
   if (!simple_atoi (val, val + strlen (val), place)
       || *(int *) place < 0)
     {
   if (!simple_atoi (val, val + strlen (val), place)
       || *(int *) place < 0)
     {
-      fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"),
-              exec_name, com, val);
+      fprintf (stderr, _("%s: %s: Invalid number %s.\n"),
+               exec_name, com, quote (val));
       return false;
     }
   return true;
       return false;
     }
   return true;
@@ -735,7 +960,7 @@ cmd_number_inf (const char *com, const char *val, void *place)
 /* Copy (strdup) the string at COM to a new location and place a
    pointer to *PLACE.  */
 static bool
 /* Copy (strdup) the string at COM to a new location and place a
    pointer to *PLACE.  */
 static bool
-cmd_string (const char *com, const char *val, void *place)
+cmd_string (const char *com _GL_UNUSED, const char *val, void *place)
 {
   char **pstring = (char **)place;
 
 {
   char **pstring = (char **)place;
 
@@ -744,17 +969,29 @@ cmd_string (const char *com, const char *val, void *place)
   return true;
 }
 
   return true;
 }
 
-#ifndef WINDOWS
-# define ISSEP(c) ((c) == '/')
-#else
-# define ISSEP(c) ((c) == '/' || (c) == '\\')
-#endif
+/* Like cmd_string but ensure the string is upper case.  */
+static bool
+cmd_string_uppercase (const char *com _GL_UNUSED, const char *val, void *place)
+{
+  char *q, **pstring;
+  pstring = (char **)place;
+  xfree_null (*pstring);
+
+  *pstring = xmalloc (strlen (val) + 1);
+
+  for (q = *pstring; *val; val++, q++)
+    *q = c_toupper (*val);
+
+  *q = '\0';
+  return true;
+}
+
 
 
-/* Like the above, but handles tilde-expansion when reading a user's
+/* Like cmd_string, but handles tilde-expansion when reading a user's
    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
    gets expanded to the user's home directory.  */
 static bool
    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
    gets expanded to the user's home directory.  */
 static bool
-cmd_file (const char *com, const char *val, void *place)
+cmd_file (const char *com _GL_UNUSED, const char *val, void *place)
 {
   char **pstring = (char **)place;
 
 {
   char **pstring = (char **)place;
 
@@ -762,36 +999,15 @@ cmd_file (const char *com, const char *val, void *place)
 
   /* #### If VAL is empty, perhaps should set *PLACE to NULL.  */
 
 
   /* #### If VAL is empty, perhaps should set *PLACE to NULL.  */
 
-  if (!enable_tilde_expansion || !(*val == '~' && ISSEP (val[1])))
-    {
-    noexpand:
-      *pstring = xstrdup (val);
-    }
-  else
-    {
-      int homelen;
-      char *home = home_dir ();
-      if (!home)
-       goto noexpand;
-
-      homelen = strlen (home);
-      while (homelen && ISSEP (home[homelen - 1]))
-       home[--homelen] = '\0';
-
-      /* Skip the leading "~/". */
-      for (++val; ISSEP (*val); val++)
-       ;
-
-      *pstring = concat_strings (home, "/", val, (char *) 0);
-    }
+  *pstring = xstrdup (val);
 
 
-#ifdef WINDOWS
+#if defined(WINDOWS) || defined(MSDOS)
   /* Convert "\" to "/". */
   {
     char *s;
     for (s = *pstring; *s; s++)
       if (*s == '\\')
   /* Convert "\" to "/". */
   {
     char *s;
     for (s = *pstring; *s; s++)
       if (*s == '\\')
-       *s = '/';
+        *s = '/';
   }
 #endif
   return true;
   }
 #endif
   return true;
@@ -822,7 +1038,7 @@ cmd_directory (const char *com, const char *val, void *place)
    PLACE vector is cleared instead.  */
 
 static bool
    PLACE vector is cleared instead.  */
 
 static bool
-cmd_vector (const char *com, const char *val, void *place)
+cmd_vector (const char *com _GL_UNUSED, const char *val, void *place)
 {
   char ***pvec = (char ***)place;
 
 {
   char ***pvec = (char ***)place;
 
@@ -837,7 +1053,7 @@ cmd_vector (const char *com, const char *val, void *place)
 }
 
 static bool
 }
 
 static bool
-cmd_directory_vector (const char *com, const char *val, void *place)
+cmd_directory_vector (const char *com _GL_UNUSED, const char *val, void *place)
 {
   char ***pvec = (char ***)place;
 
 {
   char ***pvec = (char ***)place;
 
@@ -848,15 +1064,15 @@ cmd_directory_vector (const char *com, const char *val, void *place)
 
       seps = sepstring (val);
       for (t = seps; t && *t; t++)
 
       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
       *pvec = merge_vecs (*pvec, seps);
     }
   else
@@ -884,12 +1100,12 @@ parse_bytes_helper (const char *val, double *result)
     }
 
   /* Strip trailing whitespace.  */
     }
 
   /* Strip trailing whitespace.  */
-  while (val < end && ISSPACE (end[-1]))
+  while (val < end && c_isspace (end[-1]))
     --end;
   if (val == end)
     return false;
 
     --end;
   if (val == end)
     return false;
 
-  switch (TOLOWER (end[-1]))
+  switch (c_tolower (end[-1]))
     {
     case 'k':
       --end, mult = 1024.0;
     {
     case 'k':
       --end, mult = 1024.0;
@@ -905,14 +1121,14 @@ parse_bytes_helper (const char *val, double *result)
       break;
     default:
       /* Not a recognized suffix: assume it's a digit.  (If not,
       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. */
       mult = 1;
     }
 
   /* Skip leading and trailing whitespace. */
-  while (val < end && ISSPACE (*val))
+  while (val < end && c_isspace (*val))
     ++val;
     ++val;
-  while (val < end && ISSPACE (end[-1]))
+  while (val < end && c_isspace (end[-1]))
     --end;
   if (val == end)
     return false;
     --end;
   if (val == end)
     return false;
@@ -944,8 +1160,8 @@ cmd_bytes (const char *com, const char *val, void *place)
   double byte_value;
   if (!parse_bytes_helper (val, &byte_value))
     {
   double byte_value;
   if (!parse_bytes_helper (val, &byte_value))
     {
-      fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
-              exec_name, com, val);
+      fprintf (stderr, _("%s: %s: Invalid byte value %s\n"),
+               exec_name, com, quote (val));
       return false;
     }
   *(wgint *)place = (wgint)byte_value;
       return false;
     }
   *(wgint *)place = (wgint)byte_value;
@@ -963,8 +1179,8 @@ cmd_bytes_sum (const char *com, const char *val, void *place)
   double byte_value;
   if (!parse_bytes_helper (val, &byte_value))
     {
   double byte_value;
   if (!parse_bytes_helper (val, &byte_value))
     {
-      fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
-              exec_name, com, val);
+      fprintf (stderr, _("%s: %s: Invalid byte value %s\n"),
+               exec_name, com, quote (val));
       return false;
     }
   *(SUM_SIZE_INT *) place = (SUM_SIZE_INT) byte_value;
       return false;
     }
   *(SUM_SIZE_INT *) place = (SUM_SIZE_INT) byte_value;
@@ -982,44 +1198,44 @@ cmd_time (const char *com, const char *val, void *place)
   const char *end = val + strlen (val);
 
   /* Strip trailing whitespace.  */
   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:
     --end;
 
   if (val == end)
     {
     err:
-      fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"),
-              exec_name, com, val);
+      fprintf (stderr, _("%s: %s: Invalid time period %s\n"),
+               exec_name, com, quote (val));
       return false;
     }
 
       return false;
     }
 
-  switch (TOLOWER (end[-1]))
+  switch (c_tolower (end[-1]))
     {
     case 's':
     {
     case 's':
-      --end, mult = 1;         /* seconds */
+      --end, mult = 1;          /* seconds */
       break;
     case 'm':
       break;
     case 'm':
-      --end, mult = 60;                /* minutes */
+      --end, mult = 60;         /* minutes */
       break;
     case 'h':
       break;
     case 'h':
-      --end, mult = 3600;      /* hours */
+      --end, mult = 3600;       /* hours */
       break;
     case 'd':
       break;
     case 'd':
-      --end, mult = 86400.0;   /* days */
+      --end, mult = 86400.0;    /* days */
       break;
     case 'w':
       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.
       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. */
       mult = 1;
     }
 
   /* Skip leading and trailing whitespace. */
-  while (val < end && ISSPACE (*val))
+  while (val < end && c_isspace (*val))
     ++val;
     ++val;
-  while (val < end && ISSPACE (end[-1]))
+  while (val < end && c_isspace (end[-1]))
     --end;
   if (val == end)
     goto err;
     --end;
   if (val == end)
     goto err;
@@ -1042,7 +1258,7 @@ cmd_cert_type (const char *com, const char *val, void *place)
   };
   int ok = decode_string (val, choices, countof (choices), place);
   if (!ok)
   };
   int ok = decode_string (val, choices, countof (choices), place);
   if (!ok)
-    fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
+    fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
   return ok;
 }
 #endif
   return ok;
 }
 #endif
@@ -1053,7 +1269,7 @@ cmd_cert_type (const char *com, const char *val, void *place)
 static bool check_user_specified_header (const char *);
 
 static bool
 static bool check_user_specified_header (const char *);
 
 static bool
-cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
+cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   if (!cmd_boolean (com, val, &opt.dirstruct))
     return false;
 {
   if (!cmd_boolean (com, val, &opt.dirstruct))
     return false;
@@ -1067,7 +1283,7 @@ cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
 }
 
 static bool
 }
 
 static bool
-cmd_spec_header (const char *com, const char *val, void *place_ignored)
+cmd_spec_header (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   /* Empty value means reset the list of headers. */
   if (*val == '\0')
 {
   /* Empty value means reset the list of headers. */
   if (*val == '\0')
@@ -1079,8 +1295,8 @@ cmd_spec_header (const char *com, const char *val, void *place_ignored)
 
   if (!check_user_specified_header (val))
     {
 
   if (!check_user_specified_header (val))
     {
-      fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
-              exec_name, com, val);
+      fprintf (stderr, _("%s: %s: Invalid header %s.\n"),
+               exec_name, com, quote (val));
       return false;
     }
   opt.user_headers = vec_append (opt.user_headers, val);
       return false;
     }
   opt.user_headers = vec_append (opt.user_headers, val);
@@ -1088,7 +1304,28 @@ cmd_spec_header (const char *com, const char *val, void *place_ignored)
 }
 
 static bool
 }
 
 static bool
-cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
+cmd_spec_warc_header (const char *com, const char *val, void *place_ignored _GL_UNUSED)
+{
+  /* Empty value means reset the list of headers. */
+  if (*val == '\0')
+    {
+      free_vec (opt.warc_user_headers);
+      opt.warc_user_headers = NULL;
+      return true;
+    }
+
+  if (!check_user_specified_header (val))
+    {
+      fprintf (stderr, _("%s: %s: Invalid WARC header %s.\n"),
+               exec_name, com, quote (val));
+      return false;
+    }
+  opt.warc_user_headers = vec_append (opt.warc_user_headers, val);
+  return true;
+}
+
+static bool
+cmd_spec_htmlify (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   int flag = cmd_boolean (com, val, &opt.htmlify);
   if (flag && !opt.htmlify)
 {
   int flag = cmd_boolean (com, val, &opt.htmlify);
   if (flag && !opt.htmlify)
@@ -1100,7 +1337,7 @@ cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
    no limit on max. recursion depth, and don't remove listings.  */
 
 static bool
    no limit on max. recursion depth, and don't remove listings.  */
 
 static bool
-cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
+cmd_spec_mirror (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   int mirror;
 
 {
   int mirror;
 
@@ -1110,7 +1347,7 @@ cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
     {
       opt.recursive = true;
       if (!opt.no_dirstruct)
     {
       opt.recursive = true;
       if (!opt.no_dirstruct)
-       opt.dirstruct = true;
+        opt.dirstruct = true;
       opt.timestamping = true;
       opt.reclevel = INFINITE_RECURSION;
       opt.remove_listing = false;
       opt.timestamping = true;
       opt.reclevel = INFINITE_RECURSION;
       opt.remove_listing = false;
@@ -1122,17 +1359,18 @@ cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
    "IPv4", "IPv6", and "none".  */
 
 static bool
    "IPv4", "IPv6", and "none".  */
 
 static bool
-cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
+cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   static const struct decode_item choices[] = {
     { "IPv4", prefer_ipv4 },
     { "IPv6", prefer_ipv6 },
     { "none", prefer_none },
   };
 {
   static const struct decode_item choices[] = {
     { "IPv4", prefer_ipv4 },
     { "IPv6", prefer_ipv6 },
     { "none", prefer_none },
   };
-  int ok = decode_string (val, choices, countof (choices),
-                         (int *) &opt.prefer_family);
+  int prefer_family = prefer_none;
+  int ok = decode_string (val, choices, countof (choices), &prefer_family);
   if (!ok)
   if (!ok)
-    fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
+    fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
+  opt.prefer_family = prefer_family;
   return ok;
 }
 
   return ok;
 }
 
@@ -1140,12 +1378,12 @@ cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
    implementation before that.  */
 
 static bool
    implementation before that.  */
 
 static bool
-cmd_spec_progress (const char *com, const char *val, void *place_ignored)
+cmd_spec_progress (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   if (!valid_progress_implementation_p (val))
     {
 {
   if (!valid_progress_implementation_p (val))
     {
-      fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
-              exec_name, com, val);
+      fprintf (stderr, _("%s: %s: Invalid progress type %s.\n"),
+               exec_name, com, quote (val));
       return false;
     }
   xfree_null (opt.progress_type);
       return false;
     }
   xfree_null (opt.progress_type);
@@ -1161,60 +1399,100 @@ cmd_spec_progress (const char *com, const char *val, void *place_ignored)
    is specified.  */
 
 static bool
    is specified.  */
 
 static bool
-cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
+cmd_spec_recursive (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   if (!cmd_boolean (com, val, &opt.recursive))
     return false;
   else
     {
       if (opt.recursive && !opt.no_dirstruct)
 {
   if (!cmd_boolean (com, val, &opt.recursive))
     return false;
   else
     {
       if (opt.recursive && !opt.no_dirstruct)
-       opt.dirstruct = true;
+        opt.dirstruct = true;
     }
   return true;
 }
 
     }
   return true;
 }
 
+/* Validate --regex-type and set the choice.  */
+
+static bool
+cmd_spec_regex_type (const char *com, const char *val, void *place_ignored _GL_UNUSED)
+{
+  static const struct decode_item choices[] = {
+    { "posix", regex_type_posix },
+#ifdef HAVE_LIBPCRE
+    { "pcre",  regex_type_pcre },
+#endif
+  };
+  int regex_type = regex_type_posix;
+  int ok = decode_string (val, choices, countof (choices), &regex_type);
+  if (!ok)
+    fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
+  opt.regex_type = regex_type;
+  return ok;
+}
+
 static bool
 static bool
-cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored)
+cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   int restrict_os = opt.restrict_files_os;
   int restrict_ctrl = opt.restrict_files_ctrl;
 {
   int restrict_os = opt.restrict_files_os;
   int restrict_ctrl = opt.restrict_files_ctrl;
+  int restrict_case = opt.restrict_files_case;
+  int restrict_nonascii = opt.restrict_files_nonascii;
 
 
-  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)
 
 
 #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 if (VAL_IS ("ascii"))
+        restrict_nonascii = true;
+      else
+        {
+          fprintf (stderr, _("\
+%s: %s: Invalid restriction %s,\n\
+    use [unix|windows],[lowercase|uppercase],[nocontrol],[ascii].\n"),
+                   exec_name, com, quote (val));
+          return false;
+        }
+
+      if (*end)
+        val = end + 1;
     }
     }
+  while (*val && *end);
 
 #undef VAL_IS
 
 
 #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_os = restrict_os;
   opt.restrict_files_ctrl = restrict_ctrl;
+  opt.restrict_files_case = restrict_case;
+  opt.restrict_files_nonascii = restrict_nonascii;
+
   return true;
 }
 
   return true;
 }
 
+static bool
+cmd_spec_report_speed (const char *com, const char *val, void *place_ignored _GL_UNUSED)
+{
+  opt.report_bps = strcasecmp (val, "bits") == 0;
+  if (!opt.report_bps)
+    fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
+  return opt.report_bps;
+}
+
 #ifdef HAVE_SSL
 static bool
 cmd_spec_secure_protocol (const char *com, const char *val, void *place)
 #ifdef HAVE_SSL
 static bool
 cmd_spec_secure_protocol (const char *com, const char *val, void *place)
@@ -1224,10 +1502,11 @@ cmd_spec_secure_protocol (const char *com, const char *val, void *place)
     { "sslv2", secure_protocol_sslv2 },
     { "sslv3", secure_protocol_sslv3 },
     { "tlsv1", secure_protocol_tlsv1 },
     { "sslv2", secure_protocol_sslv2 },
     { "sslv3", secure_protocol_sslv3 },
     { "tlsv1", secure_protocol_tlsv1 },
+    { "pfs", secure_protocol_pfs },
   };
   int ok = decode_string (val, choices, countof (choices), place);
   if (!ok)
   };
   int ok = decode_string (val, choices, countof (choices), place);
   if (!ok)
-    fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
+    fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
   return ok;
 }
 #endif
   return ok;
 }
 #endif
@@ -1235,7 +1514,7 @@ cmd_spec_secure_protocol (const char *com, const char *val, void *place)
 /* Set all three timeout values. */
 
 static bool
 /* Set all three timeout values. */
 
 static bool
-cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
+cmd_spec_timeout (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   double value;
   if (!cmd_time (com, val, &value))
 {
   double value;
   if (!cmd_time (com, val, &value))
@@ -1247,13 +1526,13 @@ cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
 }
 
 static bool
 }
 
 static bool
-cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
+cmd_spec_useragent (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   /* Disallow embedded newlines.  */
   if (strchr (val, '\n'))
     {
 {
   /* Disallow embedded newlines.  */
   if (strchr (val, '\n'))
     {
-      fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
-              exec_name, com, val);
+      fprintf (stderr, _("%s: %s: Invalid value %s.\n"),
+               exec_name, com, quote (val));
       return false;
     }
   xfree_null (opt.useragent);
       return false;
     }
   xfree_null (opt.useragent);
@@ -1266,7 +1545,7 @@ cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
    some random hackery for disallowing -q -v).  */
 
 static bool
    some random hackery for disallowing -q -v).  */
 
 static bool
-cmd_spec_verbose (const char *com, const char *val, void *place_ignored)
+cmd_spec_verbose (const char *com, const char *val, void *place_ignored _GL_UNUSED)
 {
   bool flag;
   if (cmd_boolean (com, val, &flag))
 {
   bool flag;
   if (cmd_boolean (com, val, &flag))
@@ -1290,7 +1569,7 @@ simple_atoi (const char *beg, const char *end, int *dest)
   bool negative = false;
   const char *p = beg;
 
   bool negative = false;
   const char *p = beg;
 
-  while (p < end && ISSPACE (*p))
+  while (p < end && c_isspace (*p))
     ++p;
   if (p < end && (*p == '-' || *p == '+'))
     {
     ++p;
   if (p < end && (*p == '-' || *p == '+'))
     {
@@ -1304,20 +1583,20 @@ simple_atoi (const char *beg, const char *end, int *dest)
      negative integer cannot be represented as a positive number.  */
 
   if (!negative)
      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
       }
   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)
       }
 
   if (p != end)
@@ -1344,7 +1623,7 @@ simple_atof (const char *beg, const char *end, double *dest)
 
   const char *p = beg;
 
 
   const char *p = beg;
 
-  while (p < end && ISSPACE (*p))
+  while (p < end && c_isspace (*p))
     ++p;
   if (p < end && (*p == '-' || *p == '+'))
     {
     ++p;
   if (p < end && (*p == '-' || *p == '+'))
     {
@@ -1355,23 +1634,23 @@ simple_atof (const char *beg, const char *end, double *dest)
   for (; p < end; p++)
     {
       char ch = *p;
   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 == '.')
       else if (ch == '.')
-       {
-         if (!seen_dot)
-           seen_dot = true;
-         else
-           return false;
-       }
+        {
+          if (!seen_dot)
+            seen_dot = true;
+          else
+            return false;
+        }
       else
       else
-       return false;
+        return false;
     }
   if (!seen_digit)
     return false;
     }
   if (!seen_digit)
     return false;
@@ -1391,7 +1670,7 @@ check_user_specified_header (const char *s)
 {
   const char *p;
 
 {
   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.  */
     ;
   /* The header MUST contain `:' preceded by at least one
      non-whitespace character.  */
@@ -1407,30 +1686,34 @@ check_user_specified_header (const char *s)
 
 static bool
 decode_string (const char *val, const struct decode_item *items, int itemcount,
 
 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))
       {
 {
   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;
 }
 
       }
   return false;
 }
 
-\f
-void cleanup_html_url (void);
-
-
 /* Free the memory allocated by global variables.  */
 void
 cleanup (void)
 {
   /* Free external resources, close files, etc. */
 
 /* Free the memory allocated by global variables.  */
 void
 cleanup (void)
 {
   /* Free external resources, close files, etc. */
 
+  /* Close WARC file. */
+  if (opt.warc_filename != 0)
+    warc_close ();
+
+  log_close ();
+
   if (output_stream)
   if (output_stream)
-    fclose (output_stream);
+    if (fclose (output_stream) == EOF)
+      inform_exit_status (CLOSEFAILED);
+
   /* No need to check for error because Wget flushes its output (and
      checks for errors) after any data arrives.  */
 
   /* No need to check for error because Wget flushes its output (and
      checks for errors) after any data arrives.  */
 
@@ -1447,13 +1730,15 @@ cleanup (void)
   res_cleanup ();
   http_cleanup ();
   cleanup_html_url ();
   res_cleanup ();
   http_cleanup ();
   cleanup_html_url ();
+  spider_cleanup ();
   host_cleanup ();
   log_cleanup ();
   host_cleanup ();
   log_cleanup ();
+  netrc_cleanup (netrc_list);
 
 
-  {
-    extern acc_t *netrc_list;
-    free_netrc (netrc_list);
-  }
+  for (i = 0; i < nurl; i++)
+    xfree (url[i]);
+
+  xfree_null (opt.choose_config);
   xfree_null (opt.lfilename);
   xfree_null (opt.dir_prefix);
   xfree_null (opt.input_filename);
   xfree_null (opt.lfilename);
   xfree_null (opt.dir_prefix);
   xfree_null (opt.input_filename);
@@ -1477,6 +1762,7 @@ cleanup (void)
   xfree_null (opt.http_user);
   xfree_null (opt.http_passwd);
   free_vec (opt.user_headers);
   xfree_null (opt.http_user);
   xfree_null (opt.http_passwd);
   free_vec (opt.user_headers);
+  free_vec (opt.warc_user_headers);
 # ifdef HAVE_SSL
   xfree_null (opt.cert_file);
   xfree_null (opt.private_key);
 # ifdef HAVE_SSL
   xfree_null (opt.cert_file);
   xfree_null (opt.private_key);
@@ -1490,5 +1776,71 @@ cleanup (void)
   xfree_null (opt.cookies_output);
   xfree_null (opt.user);
   xfree_null (opt.passwd);
   xfree_null (opt.cookies_output);
   xfree_null (opt.user);
   xfree_null (opt.passwd);
+  xfree_null (opt.base_href);
+  xfree_null (opt.method);
+
 #endif /* DEBUG_MALLOC */
 }
 #endif /* DEBUG_MALLOC */
 }
+\f
+/* Unit testing routines.  */
+
+#ifdef TESTING
+
+const char *
+test_commands_sorted(void)
+{
+  unsigned i;
+
+  for (i = 1; i < countof(commands); ++i)
+    {
+      if (strcasecmp (commands[i - 1].name, commands[i].name) > 0)
+        {
+          mu_assert ("FAILED", false);
+          break;
+        }
+    }
+  return NULL;
+}
+
+const char *
+test_cmd_spec_restrict_file_names(void)
+{
+  unsigned i;
+  static const struct {
+    const 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 < countof(test_array); ++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 */
+