]> sjero.net Git - wget/blobdiff - src/main.c
[svn] Add --random-file option. Bail out in case of error during
[wget] / src / main.c
index 7069055197f514e3caa81486ed8881730e96033d..0be2c90c49e5e643a51bff330ab6554bf19fdfa1 100644 (file)
@@ -1,21 +1,31 @@
 /* Command line parsing.
-   Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
 
-This file is part of Wget.
+This file is part of GNU Wget.
 
-This program is free software; you can redistribute it and/or modify
+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
 (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
+GNU Wget is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 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 this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+along with Wget; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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.  */
 
 #include <config.h>
 
@@ -38,35 +48,36 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 # include <locale.h>
 #endif /* HAVE_LOCALE_H */
 #endif /* HAVE_NLS */
-#include <errno.h>
+#include <assert.h>
 
-#define OPTIONS_DEFINED_HERE   /* for options.h */
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
 
 #include "wget.h"
 #include "utils.h"
-#include "getopt.h"
 #include "init.h"
 #include "retr.h"
 #include "recur.h"
 #include "host.h"
-#include "cookies.h"
+#include "url.h"
+#include "progress.h"          /* for progress_handle_sigwinch */
+#include "convert.h"
+
+/* On GNU system this will include system-wide getopt.h. */
+#include "getopt.h"
 
 #ifndef PATH_SEPARATOR
 # define PATH_SEPARATOR '/'
 #endif
 
-extern char *version_string;
-
-#ifndef errno
-extern int errno;
-#endif
-
 struct options opt;
 
-/* From log.c.  */
-void log_init PARAMS ((const char *, int));
-void log_close PARAMS ((void));
-void redirect_output PARAMS ((const char *));
+extern LARGE_INT total_downloaded_bytes;
+extern char *version_string;
+
+extern struct cookie_jar *wget_cookie_jar;
 
 static RETSIGTYPE redirect_output_signal PARAMS ((int));
 
@@ -99,21 +110,257 @@ i18n_initialize (void)
   textdomain ("wget");
 #endif /* HAVE_NLS */
 }
+\f
+/* Definition of command-line options. */
 
-/* It's kosher to declare these here because their interface _has_ to
-   be void foo(void).  */
-void url_init PARAMS ((void));
-void host_init PARAMS ((void));
+static void print_help PARAMS ((void));
+static void print_version PARAMS ((void));
+
+#ifdef HAVE_SSL
+# define IF_SSL(x) x
+#else
+# define IF_SSL(x) NULL
+#endif
+
+#ifdef ENABLE_DEBUG
+# define IF_DEBUG(x) x
+#else
+# define IF_DEBUG(x) NULL
+#endif
+
+struct cmdline_option {
+  const char *long_name;
+  char short_name;
+  enum {
+    OPT_VALUE,
+    OPT_BOOLEAN,
+    OPT_FUNCALL,
+    /* Non-standard options that have to be handled specially in
+       main().  */
+    OPT__APPEND_OUTPUT,
+    OPT__CLOBBER,
+    OPT__DONT_REMOVE_LISTING,
+    OPT__EXECUTE,
+    OPT__NO,
+    OPT__PARENT,
+  } type;
+  const void *data;            /* for standard options */
+  int argtype;                 /* for non-standard options */
+};
+
+struct cmdline_option option_data[] =
+  {
+    { "accept", 'A', OPT_VALUE, "accept", -1 },
+    { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
+    { "background", 'b', OPT_BOOLEAN, "background", -1 },
+    { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
+    { "backups", 0, OPT_BOOLEAN, "backups", -1 },
+    { "base", 'B', OPT_VALUE, "base", -1 },
+    { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
+    { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
+    { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
+    { "cache", 0, OPT_BOOLEAN, "cache", -1 },
+    { IF_SSL ("certificate"), 0, OPT_VALUE, "certificate", -1 },
+    { IF_SSL ("certificate-type"), 0, OPT_VALUE, "certificatetype", -1 },
+    { IF_SSL ("check-certificate"), 0, OPT_BOOLEAN, "checkcertificate", -1 },
+    { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
+    { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
+    { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
+    { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
+    { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
+    { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
+    { IF_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
+    { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
+    { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
+    { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
+    { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
+    { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
+    { "domains", 'D', OPT_VALUE, "domains", -1 },
+    { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
+    { "dot-style", 0, OPT_VALUE, "dotstyle", -1 },
+    { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
+    { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
+    { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
+    { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
+    { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
+    { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
+    { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
+    { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
+    { "ftp-passwd", 0, OPT_VALUE, "ftppasswd", -1 },
+    { "glob", 0, OPT_BOOLEAN, "glob", -1 },
+    { "header", 0, OPT_VALUE, "header", -1 },
+    { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
+    { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
+    { "html-extension", 'E', OPT_BOOLEAN, "htmlextension", -1 },
+    { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
+    { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
+    { "http-passwd", 0, OPT_VALUE, "httppasswd", -1 },
+    { "http-user", 0, OPT_VALUE, "httpuser", -1 },
+    { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
+    { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
+    { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
+#ifdef ENABLE_IPV6
+    { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
+    { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
+#endif
+    { "input-file", 'i', OPT_VALUE, "input", -1 },
+    { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
+    { "level", 'l', OPT_VALUE, "reclevel", -1 },
+    { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
+    { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
+    { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
+    { "no", 'n', OPT__NO, NULL, required_argument },
+    { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
+    { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
+    { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
+    { "output-file", 'o', OPT_VALUE, "logfile", -1 },
+    { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
+    { "parent", 0, OPT__PARENT, NULL, optional_argument },
+    { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
+    { "post-data", 0, OPT_VALUE, "postdata", -1 },
+    { "post-file", 0, OPT_VALUE, "postfile", -1 },
+    { "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
+    { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
+    { IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
+    { IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
+    { "progress", 0, OPT_VALUE, "progress", -1 },
+    { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
+    { "proxy", 0, OPT_BOOLEAN, "useproxy", -1 },
+    { "proxy__compat", 'Y', OPT_VALUE, "useproxy", -1 }, /* back-compatible */
+    { "proxy-passwd", 0, OPT_VALUE, "proxypasswd", -1 },
+    { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
+    { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
+    { "quota", 'Q', OPT_VALUE, "quota", -1 },
+    { "random-file", 0, OPT_VALUE, "randomfile", -1 },
+    { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
+    { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
+    { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
+    { "referer", 0, OPT_VALUE, "referer", -1 },
+    { "reject", 'R', OPT_VALUE, "reject", -1 },
+    { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
+    { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
+    { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
+    { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
+    { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
+    { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
+    { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
+    { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
+    { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
+    { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
+    { "spider", 0, OPT_BOOLEAN, "spider", -1 },
+    { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
+    { "timeout", 'T', OPT_VALUE, "timeout", -1 },
+    { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
+    { "tries", 't', OPT_VALUE, "tries", -1 },
+    { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
+    { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
+    { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
+    { "version", 'V', OPT_FUNCALL, (void *) print_version, no_argument },
+    { "wait", 'w', OPT_VALUE, "wait", -1 },
+    { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
+  };
+
+#undef IF_DEBUG
+#undef IF_SSL
+
+/* Return a string that contains S with "no-" prepended.  The string
+   is NUL-terminated and allocated off static storage at Wget
+   startup.  */
+
+static char *
+no_prefix (const char *s)
+{
+  static char buffer[1024];
+  static char *p = buffer;
+
+  char *cp = p;
+  int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
+  if (p + size >= buffer + sizeof (buffer))
+    abort ();
+
+  cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
+  strcpy (cp + 3, s);
+  p += size;
+  return cp;
+}
+
+/* The arguments that that main passes to getopt_long. */
+static struct option long_options[2 * countof (option_data) + 1];
+static char short_options[128];
+
+/* Mapping between short option chars and option_data indices. */
+static unsigned char optmap[96];
+
+/* Marker for `--no-FOO' values in long_options.  */
+#define BOOLEAN_NEG_MARKER 1024
+
+/* Initialize the long_options array used by getopt_long from the data
+   in option_data.  */
 
-/* This just calls the various initialization functions from the
-   modules that need one-time initialization. */
 static void
-private_initialize (void)
+init_switches (void)
 {
-  url_init ();
-  host_init ();
+  char *p = short_options;
+  int i, o = 0;
+  for (i = 0; i < countof (option_data); i++)
+    {
+      struct cmdline_option *opt = &option_data[i];
+      struct option *longopt;
+
+      if (!opt->long_name)
+       /* The option is disabled. */
+       continue;
+
+      longopt = &long_options[o++];
+      longopt->name = opt->long_name;
+      longopt->val = i;
+      if (opt->short_name)
+       {
+         *p++ = opt->short_name;
+         optmap[opt->short_name - 32] = longopt - long_options;
+       }
+      switch (opt->type)
+       {
+       case OPT_VALUE:
+         longopt->has_arg = required_argument;
+          if (opt->short_name)
+           *p++ = ':';
+         break;
+       case OPT_BOOLEAN:
+         /* Specify an optional argument for long options, so that
+            --option=off works the same as --no-option, for
+            compatibility with pre-1.10 Wget.  However, don't specify
+            optional arguments short-option booleans because they
+            prevent combining of short options.  */
+         longopt->has_arg = optional_argument;
+         /* For Boolean options, add the "--no-FOO" variant, which is
+            identical to "--foo", except it has opposite meaning and
+            it doesn't allow an argument.  */
+         longopt = &long_options[o++];
+         longopt->name = no_prefix (opt->long_name);
+         longopt->has_arg = no_argument;
+         /* Mask the value so we'll be able to recognize that we're
+            dealing with the false value.  */
+         longopt->val = i | BOOLEAN_NEG_MARKER;
+         break;
+       default:
+         assert (opt->argtype != -1);
+         longopt->has_arg = opt->argtype;
+         if (opt->short_name)
+           {
+             if (longopt->has_arg == required_argument)
+               *p++ = ':';
+             /* Don't handle optional_argument */
+           }
+       }
+    }
+  /* Terminate short_options. */
+  *p = '\0';
+  /* No need for xzero(long_options[o]) because its storage is static
+     and it will be zeroed by default.  */
+  assert (o <= countof (long_options));
 }
-\f
+
 /* Print the usage message.  */
 static void
 print_usage (void)
@@ -126,216 +373,294 @@ print_usage (void)
 static void
 print_help (void)
 {
+  /* We split the help text this way to ease translation of individual
+     entries.  */
+  static const char *help[] = {
+    "\n",
+    N_("\
+Mandatory arguments to long options are mandatory for short options too.\n\n"),
+    N_("\
+Startup:\n"),
+    N_("\
+  -V,  --version           display the version of Wget and exit.\n"),
+    N_("\
+  -h,  --help              print this help.\n"),
+    N_("\
+  -b,  --background        go to background after startup.\n"),
+    N_("\
+  -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
+    "\n",
+
+    N_("\
+Logging and input file:\n"),
+    N_("\
+  -o,  --output-file=FILE    log messages to FILE.\n"),
+    N_("\
+  -a,  --append-output=FILE  append messages to FILE.\n"),
+#ifdef ENABLE_DEBUG
+    N_("\
+  -d,  --debug               print lots of debugging information.\n"),
+#endif
+    N_("\
+  -q,  --quiet               quiet (no output).\n"),
+    N_("\
+  -v,  --verbose             be verbose (this is the default).\n"),
+    N_("\
+  -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
+    N_("\
+  -i,  --input-file=FILE     download URLs found in FILE.\n"),
+    N_("\
+  -F,  --force-html          treat input file as HTML.\n"),
+    N_("\
+  -B,  --base=URL            prepends URL to relative links in -F -i file.\n"),
+    "\n",
+
+    N_("\
+Download:\n"),
+    N_("\
+  -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
+    N_("\
+       --retry-connrefused       retry even if connection is refused.\n"),
+    N_("\
+  -O,  --output-document=FILE    write documents to FILE.\n"),
+    N_("\
+  -nc, --no-clobber              skip downloads that would download to\n\
+                                 existing files.\n"),
+    N_("\
+  -c,  --continue                resume getting a partially-downloaded file.\n"),
+    N_("\
+       --progress=TYPE           select progress gauge type.\n"),
+    N_("\
+  -N,  --timestamping            don't re-retrieve files unless newer than\n\
+                                 local.\n"),
+    N_("\
+  -S,  --server-response         print server response.\n"),
+    N_("\
+       --spider                  don't download anything.\n"),
+    N_("\
+  -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
+    N_("\
+       --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
+    N_("\
+       --connect-timeout=SECS    set the connect timeout to SECS.\n"),
+    N_("\
+       --read-timeout=SECS       set the read timeout to SECS.\n"),
+    N_("\
+  -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
+    N_("\
+       --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
+    N_("\
+       --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
+    N_("\
+  -Y,  --proxy                   explicitly turn on proxy.\n"),
+    N_("\
+       --no-proxy                explicitly turn off proxy.\n"),
+    N_("\
+  -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
+    N_("\
+       --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
+    N_("\
+       --limit-rate=RATE         limit download rate to RATE.\n"),
+    N_("\
+       --no-dns-cache            disable caching DNS lookups.\n"),
+    N_("\
+       --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
+#ifdef ENABLE_IPV6
+    N_("\
+  -4,  --inet4-only              connect only to IPv4 addresses.\n"),
+    N_("\
+  -6,  --inet6-only              connect only to IPv6 addresses.\n"),
+    N_("\
+       --prefer-family=FAMILY    connect first to addresses of specified family,\n\
+                                 one of IPv6, IPv4, or none.\n"),
+#endif
+    "\n",
+
+    N_("\
+Directories:\n"),
+    N_("\
+  -nd, --no-directories           don't create directories.\n"),
+    N_("\
+  -x,  --force-directories        force creation of directories.\n"),
+    N_("\
+  -nH, --no-host-directories      don't create host directories.\n"),
+    N_("\
+       --protocol-directories     use protocol name in directories.\n"),
+    N_("\
+  -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
+    N_("\
+       --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
+    "\n",
+
+    N_("\
+HTTP options:\n"),
+    N_("\
+       --http-user=USER        set http user to USER.\n"),
+    N_("\
+       --http-passwd=PASS      set http password to PASS.\n"),
+    N_("\
+       --no-cache              disallow server-cached data.\n"),
+    N_("\
+  -E,  --html-extension        save HTML documents with `.html' extension.\n"),
+    N_("\
+       --ignore-length         ignore `Content-Length' header field.\n"),
+    N_("\
+       --header=STRING         insert STRING among the headers.\n"),
+    N_("\
+       --proxy-user=USER       set USER as proxy username.\n"),
+    N_("\
+       --proxy-passwd=PASS     set PASS as proxy password.\n"),
+    N_("\
+       --referer=URL           include `Referer: URL' header in HTTP request.\n"),
+    N_("\
+       --save-headers          save the HTTP headers to file.\n"),
+    N_("\
+  -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
+    N_("\
+       --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
+    N_("\
+       --no-cookies            don't use cookies.\n"),
+    N_("\
+       --load-cookies=FILE     load cookies from FILE before session.\n"),
+    N_("\
+       --save-cookies=FILE     save cookies to FILE after session.\n"),
+    N_("\
+       --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
+    N_("\
+       --post-data=STRING      use the POST method; send STRING as the data.\n"),
+    N_("\
+       --post-file=FILE        use the POST method; send contents of FILE.\n"),
+    "\n",
+
+#ifdef HAVE_SSL
+    N_("\
+HTTPS (SSL/TLS) options:\n"),
+    N_("\
+       --secure-protocol=PR     choose SSL protocol, one of auto, SSLv2, SSLv3,\n\
+                                and TLSv1.\n"),
+    N_("\
+       --no-check-certificate   don't validate the server's certificate.\n"),
+    N_("\
+       --certificate=FILE       client certificate file.\n"),
+    N_("\
+       --certificate-type=TYPE  client certificate type, PEM or ASN1.\n"),
+    N_("\
+       --private-key=FILE       private key file.\n"),
+    N_("\
+       --private-key-type=TYPE  private key type, PEM or ASN1.\n"),
+    N_("\
+       --ca-certificate=FILE    file with the bundle of CA's.\n"),
+    N_("\
+       --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
+    N_("\
+       --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
+    N_("\
+       --egd-file=FILE          file naming the EGD socket with random data.\n"),
+    "\n",
+#endif /* HAVE_SSL */
+
+    N_("\
+FTP options:\n"),
+    N_("\
+       --no-remove-listing     don't remove `.listing' files.\n"),
+    N_("\
+       --no-glob               turn off FTP file name globbing.\n"),
+    N_("\
+       --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
+    N_("\
+       --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
+    N_("\
+       --preserve-permissions  preserve remote file permissions.\n"),
+    "\n",
+
+    N_("\
+Recursive download:\n"),
+    N_("\
+  -r,  --recursive          specify recursive download.\n"),
+    N_("\
+  -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
+    N_("\
+       --delete-after       delete files locally after downloading them.\n"),
+    N_("\
+  -k,  --convert-links      make links in downloaded HTML point to local files.\n"),
+    N_("\
+  -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
+    N_("\
+  -m,  --mirror             shortcut option equivalent to -r -N -l inf -nr.\n"),
+    N_("\
+  -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
+    N_("\
+       --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
+    "\n",
+
+    N_("\
+Recursive accept/reject:\n"),
+    N_("\
+  -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
+    N_("\
+  -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
+    N_("\
+  -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
+    N_("\
+       --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
+    N_("\
+       --follow-ftp                follow FTP links from HTML documents.\n"),
+    N_("\
+       --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
+    N_("\
+       --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
+    N_("\
+  -H,  --span-hosts                go to foreign hosts when recursive.\n"),
+    N_("\
+  -L,  --relative                  follow relative links only.\n"),
+    N_("\
+  -I,  --include-directories=LIST  list of allowed directories.\n"),
+    N_("\
+  -X,  --exclude-directories=LIST  list of excluded directories.\n"),
+    N_("\
+  -np, --no-parent                 don't ascend to the parent directory.\n"),
+    "\n",
+
+    N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
+  };
+
+  int i;
+
   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
          version_string);
   print_usage ();
-  /* Had to split this in parts, so the #@@#%# Ultrix compiler and cpp
-     don't bitch.  Also, it makes translation much easier.  */
-  fputs (_("\
-\n\
-Mandatory arguments to long options are mandatory for short options too.\n\
-\n"), stdout);
-  fputs (_("\
-Startup:\n\
-  -V,  --version           display the version of Wget and exit.\n\
-  -h,  --help              print this help.\n\
-  -b,  --background        go to background after startup.\n\
-  -e,  --execute=COMMAND   execute a `.wgetrc\'-style command.\n\
-\n"), stdout);
-  fputs (_("\
-Logging and input file:\n\
-  -o,  --output-file=FILE     log messages to FILE.\n\
-  -a,  --append-output=FILE   append messages to FILE.\n\
-  -d,  --debug                print debug output.\n\
-  -q,  --quiet                quiet (no output).\n\
-  -v,  --verbose              be verbose (this is the default).\n\
-  -nv, --non-verbose          turn off verboseness, without being quiet.\n\
-  -i,  --input-file=FILE      download URLs found in FILE.\n\
-  -F,  --force-html           treat input file as HTML.\n\
-  -B,  --base=URL             prepends URL to relative links in -F -i file.\n\
-       --sslcertfile=FILE     optional client certificate.\n\
-       --sslcertkey=KEYFILE   optional keyfile for this certificate.\n\
-\n"), stdout);
-  fputs (_("\
-Download:\n\
-       --bind-address=ADDRESS   bind to ADDRESS (hostname or IP) on local host.\n\
-  -t,  --tries=NUMBER           set number of retries to NUMBER (0 unlimits).\n\
-  -O   --output-document=FILE   write documents to FILE.\n\
-  -nc, --no-clobber             don\'t clobber existing files or use .# suffixes.\n\
-  -c,  --continue               resume getting a partially-downloaded file.\n\
-       --dot-style=STYLE        set retrieval display style.\n\
-  -N,  --timestamping           don\'t re-retrieve files unless newer than local.\n\
-  -S,  --server-response        print server response.\n\
-       --spider                 don\'t download anything.\n\
-  -T,  --timeout=SECONDS        set the read timeout to SECONDS.\n\
-  -w,  --wait=SECONDS           wait SECONDS between retrievals.\n\
-       --waitretry=SECONDS      wait 1...SECONDS between retries of a retrieval.\n\
-  -Y,  --proxy=on/off           turn proxy on or off.\n\
-  -Q,  --quota=NUMBER           set retrieval quota to NUMBER.\n\
-\n"), stdout);
-  fputs (_("\
-Directories:\n\
-  -nd  --no-directories            don\'t create directories.\n\
-  -x,  --force-directories         force creation of directories.\n\
-  -nH, --no-host-directories       don\'t create host directories.\n\
-  -P,  --directory-prefix=PREFIX   save files to PREFIX/...\n\
-       --cut-dirs=NUMBER           ignore NUMBER remote directory components.\n\
-\n"), stdout);
-  fputs (_("\
-HTTP options:\n\
-       --http-user=USER      set http user to USER.\n\
-       --http-passwd=PASS    set http password to PASS.\n\
-  -C,  --cache=on/off        (dis)allow server-cached data (normally allowed).\n\
-  -E,  --html-extension      save all text/html documents with .html extension.\n\
-       --ignore-length       ignore `Content-Length\' header field.\n\
-       --header=STRING       insert STRING among the headers.\n\
-       --proxy-user=USER     set USER as proxy username.\n\
-       --proxy-passwd=PASS   set PASS as proxy password.\n\
-       --referer=URL         include `Referer: URL\' header in HTTP request.\n\
-  -s,  --save-headers        save the HTTP headers to file.\n\
-  -U,  --user-agent=AGENT    identify as AGENT instead of Wget/VERSION.\n\
-       --cookies=no         don't use cookies.\n\
-       --load-cookies=FILE   load cookies from FILE before session.\n\
-       --save-cookies=FILE   save cookies to FILE after session.\n\
-\n"), stdout);
-  fputs (_("\
-FTP options:\n\
-  -nr, --dont-remove-listing   don\'t remove `.listing\' files.\n\
-  -g,  --glob=on/off           turn file name globbing on or off.\n\
-       --passive-ftp           use the \"passive\" transfer mode.\n\
-       --retr-symlinks         when recursing, get linked-to files (not dirs).\n\
-\n"), stdout);
+
+  for (i = 0; i < countof (help); i++)
+    fputs (_(help[i]), stdout);
+
+  exit (0);
+}
+
+static void
+print_version (void)
+{
+  printf ("GNU Wget %s\n\n", version_string);
   fputs (_("\
-Recursive retrieval:\n\
-  -r,  --recursive          recursive web-suck -- use with care!\n\
-  -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n\
-       --delete-after       delete files locally after downloading them.\n\
-  -k,  --convert-links      convert non-relative links to relative.\n\
-  -K,  --backup-converted   before converting file X, back up as X.orig.\n\
-  -m,  --mirror             shortcut option equivalent to -r -N -l inf -nr.\n\
-  -p,  --page-requisites    get all images, etc. needed to display HTML page.\n\
-\n"), stdout);
+Copyright (C) 2005 Free Software Foundation, Inc.\n"), stdout);
   fputs (_("\
-Recursive accept/reject:\n\
-  -A,  --accept=LIST                comma-separated list of accepted extensions.\n\
-  -R,  --reject=LIST                comma-separated list of rejected extensions.\n\
-  -D,  --domains=LIST               comma-separated list of accepted domains.\n\
-       --exclude-domains=LIST       comma-separated list of rejected domains.\n\
-       --follow-ftp                 follow FTP links from HTML documents.\n\
-       --follow-tags=LIST           comma-separated list of followed HTML tags.\n\
-  -G,  --ignore-tags=LIST           comma-separated list of ignored HTML tags.\n\
-  -H,  --span-hosts                 go to foreign hosts when recursive.\n\
-  -L,  --relative                   follow relative links only.\n\
-  -I,  --include-directories=LIST   list of allowed directories.\n\
-  -X,  --exclude-directories=LIST   list of excluded directories.\n\
-  -nh, --no-host-lookup             don\'t DNS-lookup hosts.\n\
-  -np, --no-parent                  don\'t ascend to the parent directory.\n\
-\n"), stdout);
-  fputs (_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n"),
+This program is distributed in the hope that it will be useful,\n\
+but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
+GNU General Public License for more details.\n"), stdout);
+  fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
         stdout);
+  exit (0);
 }
 \f
 int
 main (int argc, char *const *argv)
 {
   char **url, **t;
-  int i, c, nurl, status, append_to_log;
-  int wr = 0;
-
-  static struct option long_options[] =
-  {
-    /* Options without arguments: */
-    { "background", no_argument, NULL, 'b' },
-    { "backup-converted", no_argument, NULL, 'K' },
-    { "continue", no_argument, NULL, 'c' },
-    { "convert-links", no_argument, NULL, 'k' },
-    { "cookies", no_argument, NULL, 160 },
-    { "debug", no_argument, NULL, 'd' },
-    { "delete-after", no_argument, NULL, 136 },
-    { "dont-remove-listing", no_argument, NULL, 149 },
-    { "email-address", no_argument, NULL, 154 }, /* undocumented (debug) */
-    { "follow-ftp", no_argument, NULL, 142 },
-    { "force-directories", no_argument, NULL, 'x' },
-    { "force-hier", no_argument, NULL, 'x' }, /* obsolete */
-    { "force-html", no_argument, NULL, 'F'},
-    { "help", no_argument, NULL, 'h' },
-    { "html-extension", no_argument, NULL, 'E' },
-    { "ignore-length", no_argument, NULL, 138 },
-    { "mirror", no_argument, NULL, 'm' },
-    { "no-clobber", no_argument, NULL, 141 },
-    { "no-directories", no_argument, NULL, 147 },
-    { "no-host-directories", no_argument, NULL, 148 },
-    { "no-host-lookup", no_argument, NULL, 150 },
-    { "no-http-keep-alive", no_argument, NULL, 156 },
-    { "no-parent", no_argument, NULL, 133 },
-    { "non-verbose", no_argument, NULL, 146 },
-    { "passive-ftp", no_argument, NULL, 139 },
-    { "page-requisites", no_argument, NULL, 'p' },
-    { "quiet", no_argument, NULL, 'q' },
-    { "recursive", no_argument, NULL, 'r' },
-    { "relative", no_argument, NULL, 'L' },
-    { "retr-symlinks", no_argument, NULL, 137 },
-    { "save-headers", no_argument, NULL, 's' },
-    { "server-response", no_argument, NULL, 'S' },
-    { "span-hosts", no_argument, NULL, 'H' },
-    { "spider", no_argument, NULL, 132 },
-    { "timestamping", no_argument, NULL, 'N' },
-    { "verbose", no_argument, NULL, 'v' },
-    { "version", no_argument, NULL, 'V' },
-
-    /* Options accepting an argument: */
-    { "accept", required_argument, NULL, 'A' },
-    { "append-output", required_argument, NULL, 'a' },
-    { "backups", required_argument, NULL, 151 }, /* undocumented */
-    { "base", required_argument, NULL, 'B' },
-    { "bind-address", required_argument, NULL, 155 },
-    { "cache", required_argument, NULL, 'C' },
-    { "cookie-file", required_argument, NULL, 161 },
-    { "cut-dirs", required_argument, NULL, 145 },
-    { "directory-prefix", required_argument, NULL, 'P' },
-    { "domains", required_argument, NULL, 'D' },
-    { "dot-style", required_argument, NULL, 134 },
-    { "execute", required_argument, NULL, 'e' },
-    { "exclude-directories", required_argument, NULL, 'X' },
-    { "exclude-domains", required_argument, NULL, 140 },
-    { "follow-tags", required_argument, NULL, 153 },
-    { "glob", required_argument, NULL, 'g' },
-    { "header", required_argument, NULL, 131 },
-    { "htmlify", required_argument, NULL, 135 },
-    { "http-passwd", required_argument, NULL, 130 },
-    { "http-user", required_argument, NULL, 129 },
-    { "ignore-tags", required_argument, NULL, 'G' },
-    { "include-directories", required_argument, NULL, 'I' },
-    { "input-file", required_argument, NULL, 'i' },
-    { "level", required_argument, NULL, 'l' },
-    { "load-cookies", required_argument, NULL, 162 },
-    { "no", required_argument, NULL, 'n' },
-    { "output-document", required_argument, NULL, 'O' },
-    { "output-file", required_argument, NULL, 'o' },
-    { "proxy", required_argument, NULL, 'Y' },
-    { "proxy-passwd", required_argument, NULL, 144 },
-    { "proxy-user", required_argument, NULL, 143 },
-    { "quota", required_argument, NULL, 'Q' },
-    { "reject", required_argument, NULL, 'R' },
-    { "save-cookies", required_argument, NULL, 163 },
-    { "timeout", required_argument, NULL, 'T' },
-    { "tries", required_argument, NULL, 't' },
-    { "user-agent", required_argument, NULL, 'U' },
-    { "referer", required_argument, NULL, 157 },
-    { "use-proxy", required_argument, NULL, 'Y' },
-#ifdef HAVE_SSL
-    { "sslcertfile", required_argument, NULL, 158 },
-    { "sslcertkey", required_argument, NULL, 159 },
-#endif /* HAVE_SSL */
-    { "wait", required_argument, NULL, 'w' },
-    { "waitretry", required_argument, NULL, 152 },
-    { 0, 0, 0, 0 }
-  };
+  int i, ret, longindex;
+  int nurl, status;
+  int append_to_log = 0;
 
   i18n_initialize ();
-  private_initialize ();
-
-  append_to_log = 0;
 
   /* Construct the name of the executable, without the directory part.  */
   exec_name = strrchr (argv[0], PATH_SEPARATOR);
@@ -345,377 +670,145 @@ main (int argc, char *const *argv)
     ++exec_name;
 
 #ifdef WINDOWS
-  windows_main_junk (&argc, (char **) argv, (char **) &exec_name);
+  /* Drop extension (typically .EXE) from executable filename. */
+  windows_main (&argc, (char **) argv, (char **) &exec_name);
 #endif
 
-  initialize (); /* sets option defaults; reads the system wgetrc and .wgetrc */
+  /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
+  initialize ();
 
-  /* [Is the order of the option letters significant?  If not, they should be
-      alphabetized, like the long_options.  The only thing I know for sure is
-      that the options with required arguments must be followed by a ':'.
-      -- Dan Harkless <wget@harkless.org>] */
-  while ((c = getopt_long (argc, argv, "\
-hpVqvdkKsxmNWrHSLcFbEY:G:g:T:U:O:l:n:i:o:a:t:D:A:R:P:B:e:Q:X:I:w:C:",
-                          long_options, (int *)0)) != EOF)
+  init_switches ();
+  longindex = -1;
+  while ((ret = getopt_long (argc, argv,
+                            short_options, long_options, &longindex)) != -1)
     {
-      switch (c)
+      int val;
+      struct cmdline_option *opt;
+
+      /* If LONGINDEX is unchanged, it means RET is referring a short
+        option.  */
+      if (longindex == -1)
        {
-         /* Options without arguments: */
-       case 132:
-         setval ("spider", "on");
-         break;
-       case 133:
-         setval ("noparent", "on");
-         break;
-       case 136:
-         setval ("deleteafter", "on");
-         break;
-       case 137:
-         setval ("retrsymlinks", "on");
-         break;
-       case 138:
-         setval ("ignorelength", "on");
-         break;
-       case 139:
-         setval ("passiveftp", "on");
-         break;
-       case 141:
-         setval ("noclobber", "on");
-         break;
-       case 142:
-         setval ("followftp", "on");
-         break;
-       case 145:
-         setval ("cutdirs", optarg);
-         break;
-       case 146:
-         setval ("verbose", "off");
-         break;
-       case 147:
-         setval ("dirstruct", "off");
-         break;
-       case 148:
-         setval ("addhostdir", "off");
-         break;
-       case 149:
-         setval ("removelisting", "off");
-         break;
-       case 150:
-         setval ("simplehostcheck", "on");
-         break;
-       case 154:
-         /* For debugging purposes.  */
-         printf ("%s\n", ftp_getaddress ());
-         exit (0);
-         break;
-       case 155:
-         setval ("bindaddress", optarg);
-         break;
-       case 156:
-         setval ("httpkeepalive", "off");
-         break;
-       case 'b':
-         setval ("background", "on");
-         break;
-       case 'c':
-         setval ("continue", "on");
-         break;
-       case 'd':
-#ifdef DEBUG
-         setval ("debug", "on");
-#else  /* not DEBUG */
-         fprintf (stderr, _("%s: debug support not compiled in.\n"),
-                  exec_name);
-#endif /* not DEBUG */
-         break;
-       case 'E':
-         setval ("htmlextension", "on");
-         break;
-       case 'F':
-         setval ("forcehtml", "on");
-         break;
-       case 'H':
-         setval ("spanhosts", "on");
-         break;
-       case 'h':
-         print_help ();
-#ifdef WINDOWS
-         ws_help (exec_name);
-#endif
-         exit (0);
-         break;
-       case 'K':
-         setval ("backupconverted", "on");
-         break;
-       case 'k':
-         setval ("convertlinks", "on");
-         break;
-       case 'L':
-         setval ("relativeonly", "on");
-         break;
-       case 'm':
-         setval ("mirror", "on");
-         break;
-       case 'N':
-         setval ("timestamping", "on");
-         break;
-       case 'p':
-         setval ("pagerequisites", "on");
-         break;
-       case 'S':
-         setval ("serverresponse", "on");
-         break;
-       case 's':
-         setval ("saveheaders", "on");
-         break;
-       case 'q':
-         setval ("quiet", "on");
-         break;
-       case 'r':
-         setval ("recursive", "on");
-         break;
-       case 'V':
-         printf ("GNU Wget %s\n\n", version_string);
-         printf ("%s", _("\
-Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.\n\
-This program is distributed in the hope that it will be useful,\n\
-but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
-GNU General Public License for more details.\n"));
-         printf (_("\nOriginally written by Hrvoje Niksic <hniksic@arsdigita.com>.\n"));
-         exit (0);
-         break;
-       case 'v':
-         setval ("verbose", "on");
-         break;
-       case 'x':
-         setval ("dirstruct", "on");
-         break;
+         if (ret == '?')
+           {
+             print_usage ();
+             printf ("\n");
+             printf (_("Try `%s --help' for more options.\n"), exec_name);
+             exit (2);
+           }
+         /* Find the short option character in the mapping.  */
+         longindex = optmap[ret - 32];
+       }
+      val = long_options[longindex].val;
 
-         /* Options accepting an argument: */
-       case 129:
-         setval ("httpuser", optarg);
-         break;
-       case 130:
-         setval ("httppasswd", optarg);
-         break;
-       case 131:
-         setval ("header", optarg);
-         break;
-       case 134:
-         setval ("dotstyle", optarg);
-         break;
-       case 135:
-         setval ("htmlify", optarg);
-         break;
-       case 140:
-         setval ("excludedomains", optarg);
-         break;
-       case 143:
-         setval ("proxyuser", optarg);
-         break;
-       case 144:
-         setval ("proxypasswd", optarg);
-         break;
-       case 151:
-         setval ("backups", optarg);
-         break;
-       case 152:
-         setval ("waitretry", optarg);
-         wr = 1;
-         break;
-       case 153:
-         setval ("followtags", optarg);
-         break;
-       case 160:
-         setval ("cookies", "on");
-         break;
-       case 161:
-         setval ("cookies", "on");
-         setval ("cookiein", optarg);
-         setval ("cookieout", optarg);
-         break;
-       case 162:
-         setval ("cookies", "on");
-         setval ("cookiein", optarg);
-         break;
-       case 163:
-         setval ("cookies", "on");
-         setval ("cookieout", optarg);
-         break;
-       case 157:
-         setval ("referer", optarg);
-         break;
-#ifdef HAVE_SSL
-       case 158:
-         setval ("sslcertfile", optarg);
-         break;
-       case 159:
-         setval ("sslcertkey", optarg);
-         break;
-#endif /* HAVE_SSL */
-       case 'A':
-         setval ("accept", optarg);
-         break;
-       case 'a':
-         setval ("logfile", optarg);
-         append_to_log = 1;
-         break;
-       case 'B':
-         setval ("base", optarg);
-         break;
-       case 'C':
-         setval ("cache", optarg);
-         break;
-       case 'D':
-         setval ("domains", optarg);
+      /* Use the retrieved value to locate the option in the
+        option_data array, and to see if we're dealing with the
+        negated "--no-FOO" variant of the boolean option "--foo".  */
+      opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
+      switch (opt->type)
+       {
+       case OPT_VALUE:
+         setoptval (opt->data, optarg);
+         break;
+       case OPT_BOOLEAN:
+         if (optarg)
+           /* The user has specified a value -- use it. */
+           setoptval (opt->data, optarg);
+         else
+           {
+             /* NEG is true for `--no-FOO' style boolean options. */
+             int neg = val & BOOLEAN_NEG_MARKER;
+             setoptval (opt->data, neg ? "0" : "1");
+           }
          break;
-       case 'e':
+       case OPT_FUNCALL:
          {
-           char *com, *val;
-           if (parse_line (optarg, &com, &val))
-             {
-               if (!setval (com, val))
-                 exit (1);
-             }
-           else
-             {
-               fprintf (stderr, _("%s: %s: invalid command\n"), exec_name,
-                        optarg);
-               exit (1);
-             }
-           xfree (com);
-           xfree (val);
+           void (*func) PARAMS ((void)) = (void (*) PARAMS ((void))) opt->data;
+           func ();
          }
          break;
-       case 'G':
-         setval ("ignoretags", optarg);
-         break;
-       case 'g':
-         setval ("glob", optarg);
-         break;
-       case 'I':
-         setval ("includedirectories", optarg);
-         break;
-       case 'i':
-         setval ("input", optarg);
+       case OPT__APPEND_OUTPUT:
+         setoptval ("logfile", optarg);
+         append_to_log = 1;
          break;
-       case 'l':
-         setval ("reclevel", optarg);
+       case OPT__EXECUTE:
+         run_command (optarg);
          break;
-       case 'n':
+       case OPT__NO:
          {
-           /* #### The n? options are utter crock!  */
+           /* We support real --no-FOO flags now, but keep these
+              short options for convenience and backward
+              compatibility.  */
            char *p;
-
            for (p = optarg; *p; p++)
              switch (*p)
                {
                case 'v':
-                 setval ("verbose", "off");
-                 break;
-               case 'h':
-                 setval ("simplehostcheck", "on");
+                 setoptval ("verbose", "0");
                  break;
                case 'H':
-                 setval ("addhostdir", "off");
+                 setoptval ("addhostdir", "0");
                  break;
                case 'd':
-                 setval ("dirstruct", "off");
+                 setoptval ("dirstruct", "0");
                  break;
                case 'c':
-                 setval ("noclobber", "on");
-                 break;
-               case 'r':
-                 setval ("removelisting", "off");
+                 setoptval ("noclobber", "1");
                  break;
                case 'p':
-                 setval ("noparent", "on");
-                 break;
-               case 'k':
-                 setval ("httpkeepalive", "off");
+                 setoptval ("noparent", "1");
                  break;
                default:
                  printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
                  print_usage ();
                  printf ("\n");
-                 printf (_("Try `%s --help\' for more options.\n"), exec_name);
+                 printf (_("Try `%s --help' for more options.\n"), exec_name);
                  exit (1);
                }
            break;
          }
-       case 'O':
-         setval ("outputdocument", optarg);
-         break;
-       case 'o':
-         setval ("logfile", optarg);
-         break;
-       case 'P':
-         setval ("dirprefix", optarg);
-         break;
-       case 'Q':
-         setval ("quota", optarg);
-         break;
-       case 'R':
-         setval ("reject", optarg);
-         break;
-       case 'T':
-         setval ("timeout", optarg);
-         break;
-       case 't':
-         setval ("tries", optarg);
-         break;
-       case 'U':
-         setval ("useragent", optarg);
-         break;
-       case 'w':
-         setval ("wait", optarg);
-         break;
-       case 'X':
-         setval ("excludedirectories", optarg);
-         break;
-       case 'Y':
-         setval ("useproxy", optarg);
-         break;
-
-       case '?':
-         print_usage ();
-         printf ("\n");
-         printf (_("Try `%s --help' for more options.\n"), exec_name);
-         exit (0);
+       case OPT__PARENT:
+       case OPT__CLOBBER:
+         {
+           /* The wgetrc commands are named noparent and noclobber,
+              so we must revert the meaning of the cmdline options
+              before passing the value to setoptval.  */
+           int flag = 1;
+           if (optarg)
+             flag = (*optarg == '1' || TOLOWER (*optarg) == 'y'
+                     || (TOLOWER (optarg[0]) == 'o'
+                         && TOLOWER (optarg[1]) == 'n'));
+           setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
+                      flag ? "0" : "1");
+           break;
+         }
+       case OPT__DONT_REMOVE_LISTING:
+         setoptval ("removelisting", "0");
          break;
        }
+
+      longindex = -1;
     }
 
   /* All user options have now been processed, so it's now safe to do
      interoption dependency checks. */
 
   if (opt.reclevel == 0)
-    opt.reclevel = INFINITE_RECURSION;  /* see wget.h for commentary on this */
+    opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary on this */
 
   if (opt.page_requisites && !opt.recursive)
     {
-      opt.recursive = TRUE;
+      /* Don't set opt.recursive here because it would confuse the FTP
+        code.  Instead, call retrieve_tree below when either
+        page_requisites or recursive is requested.  */
       opt.reclevel = 0;
       if (!opt.no_dirstruct)
-       opt.dirstruct = TRUE;  /* usually handled by cmd_spec_recursive() */
+       opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
     }
 
   if (opt.verbose == -1)
     opt.verbose = !opt.quiet;
 
-  /* Retain compatibility with previous scripts.
-     if wait has been set, but waitretry has not, give it the wait value.
-     A simple check on the values is not enough, I could have set
-     wait to n>0 and waitretry to 0 - HEH */
-  if (opt.wait && !wr)
-    {
-      char  opt_wait_str[256];  /* bigger than needed buf to prevent overflow */
-
-      sprintf(opt_wait_str, "%ld", opt.wait);
-      setval ("waitretry", opt_wait_str);
-    }
-    
   /* Sanity checks.  */
   if (opt.verbose && opt.quiet)
     {
@@ -730,6 +823,15 @@ Can't timestamp and not clobber old files at the same time.\n"));
       print_usage ();
       exit (1);
     }
+#ifdef ENABLE_IPV6
+  if (opt.ipv4_only && opt.ipv6_only)
+    {
+      printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
+      print_usage ();
+      exit (1);
+    }
+#endif
+
   nurl = argc - optind;
   if (!nurl && !opt.input_filename)
     {
@@ -746,23 +848,23 @@ Can't timestamp and not clobber old files at the same time.\n"));
   if (opt.background)
     fork_to_background ();
 
-  /* Allocate basic pointer.  */
-  url = ALLOCA_ARRAY (char *, nurl + 1);
+  /* Initialize progress.  Have to do this after the options are
+     processed so we know where the log file is.  */
+  if (opt.verbose)
+    set_progress_implementation (opt.progress_type);
+
   /* Fill in the arguments.  */
+  url = alloca_array (char *, nurl + 1);
   for (i = 0; i < nurl; i++, optind++)
     {
-      char *irix4_cc_needs_this;
-      STRDUP_ALLOCA (irix4_cc_needs_this, argv[optind]);
-      url[i] = irix4_cc_needs_this;
+      char *rewritten = rewrite_shorthand_url (argv[optind]);
+      if (rewritten)
+       url[i] = rewritten;
+      else
+       url[i] = xstrdup (argv[optind]);
     }
   url[i] = NULL;
 
-  /* Change the title of console window on Windows.  #### I think this
-     statement should belong to retrieve_url().  --hniksic.  */
-#ifdef WINDOWS
-  ws_changetitle (*url, nurl);
-#endif
-
   /* Initialize logging.  */
   log_init (opt.lfilename, append_to_log);
 
@@ -772,19 +874,23 @@ Can't timestamp and not clobber old files at the same time.\n"));
   /* Open the output filename if necessary.  */
   if (opt.output_document)
     {
+      extern FILE *output_stream;
+      extern int output_stream_regular;
+
       if (HYPHENP (opt.output_document))
-       opt.dfp = stdout;
+       output_stream = stdout;
       else
        {
-         struct stat st;
-         opt.dfp = fopen (opt.output_document, opt.always_rest ? "ab" : "wb");
-         if (opt.dfp == NULL)
+         struct_stat st;
+         output_stream = fopen (opt.output_document,
+                                opt.always_rest ? "ab" : "wb");
+         if (output_stream == NULL)
            {
              perror (opt.output_document);
              exit (1);
            }
-         if (fstat (fileno (opt.dfp), &st) == 0 && S_ISREG (st.st_mode))
-           opt.od_known_regular = 1;
+         if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
+           output_stream_regular = 1;
        }
     }
 
@@ -792,9 +898,6 @@ Can't timestamp and not clobber old files at the same time.\n"));
   ws_startup ();
 #endif
 
-  if (opt.cookies_input)
-      load_cookies (opt.cookies_input);
-
   /* Setup the signal handler to redirect output when hangup is
      received.  */
 #ifdef HAVE_SIGNAL
@@ -806,20 +909,23 @@ Can't timestamp and not clobber old files at the same time.\n"));
      process exits.  What we want is to ignore SIGPIPE and just check
      for the return value of write().  */
   signal (SIGPIPE, SIG_IGN);
+#ifdef SIGWINCH
+  signal (SIGWINCH, progress_handle_sigwinch);
+#endif
 #endif /* HAVE_SIGNAL */
 
   status = RETROK;             /* initialize it, just-in-case */
-  recursive_reset ();
   /* Retrieve the URLs from argument list.  */
   for (t = url; *t; t++)
     {
-      char *filename, *redirected_URL;
+      char *filename = NULL, *redirected_URL = NULL;
       int dt;
 
-      status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
-      if (opt.recursive && status == RETROK && (dt & TEXTHTML))
-       status = recursive_retrieve (filename,
-                                    redirected_URL ? redirected_URL : *t);
+      if ((opt.recursive || opt.page_requisites)
+         && url_scheme (*t) != SCHEME_FTP)
+       status = retrieve_tree (*t);
+      else
+       status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
 
       if (opt.delete_after && file_exists_p(filename))
        {
@@ -829,8 +935,8 @@ Can't timestamp and not clobber old files at the same time.\n"));
            logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
        }
 
-      FREE_MAYBE (redirected_URL);
-      FREE_MAYBE (filename);
+      xfree_null (redirected_URL);
+      xfree_null (filename);
     }
 
   /* And then from the input file, if any.  */
@@ -843,32 +949,32 @@ Can't timestamp and not clobber old files at the same time.\n"));
                   opt.input_filename);
     }
   /* Print the downloaded sum.  */
-  if (opt.recursive
+  if (opt.recursive || opt.page_requisites
       || nurl > 1
-      || (opt.input_filename && opt.downloaded != 0))
+      || (opt.input_filename && total_downloaded_bytes != 0))
     {
       logprintf (LOG_NOTQUIET,
                 _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
-                time_str (NULL),
-                (opt.downloaded_overflow ?
-                 "<overflow>" : legible_very_long (opt.downloaded)),
+                time_str (NULL), with_thousand_seps_large (total_downloaded_bytes),
                 opt.numurls);
       /* Print quota warning, if exceeded.  */
-      if (downloaded_exceeds_quota ())
+      if (opt.quota && total_downloaded_bytes > opt.quota)
        logprintf (LOG_NOTQUIET,
                   _("Download quota (%s bytes) EXCEEDED!\n"),
-                  legible (opt.quota));
+                  with_thousand_seps_large (opt.quota));
     }
 
   if (opt.cookies_output)
-    save_cookies (opt.cookies_output);
+    save_cookies ();
 
   if (opt.convert_links && !opt.delete_after)
-    {
-      convert_all_links ();
-    }
+    convert_all_links ();
+
   log_close ();
+  for (i = 0; i < nurl; i++)
+    xfree (url[i]);
   cleanup ();
+
 #ifdef DEBUG_MALLOC
   print_malloc_debug_stats ();
 #endif
@@ -878,22 +984,23 @@ Can't timestamp and not clobber old files at the same time.\n"));
     return 1;
 }
 \f
+#ifdef HAVE_SIGNAL
 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
    will proceed operation as usual, trying to write into a log file.
-   If that is impossible, the output will be turned off.  */
+   If that is impossible, the output will be turned off.
+
+   #### It is unsafe to do call libc functions from a signal handler.
+   What we should do is, set a global variable, and have the code in
+   log.c pick it up.  */
 
-#ifdef HAVE_SIGNAL
 static RETSIGTYPE
 redirect_output_signal (int sig)
 {
-  char tmp[100];
+  const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
+                            (sig == SIGUSR1 ? "SIGUSR1" :
+                             "WTF?!"));
+  log_request_redirect_output (signal_name);
+  progress_schedule_redirect ();
   signal (sig, redirect_output_signal);
-  /* Please note that the double `%' in `%%s' is intentional, because
-     redirect_output passes tmp through printf.  */
-  sprintf (tmp, _("%s received, redirecting output to `%%s'.\n"),
-          (sig == SIGHUP ? "SIGHUP" :
-           (sig == SIGUSR1 ? "SIGUSR1" :
-            "WTF?!")));
-  redirect_output (tmp);
 }
 #endif /* HAVE_SIGNAL */