[setup - the official Cygwin setup program] branch master, updated. release_2.903-5-ga7f2d458

Jon TURNEY via Cygwin-apps-cvs <[email protected]>
Newsgroups gmane.os.cygwin.cvs.apps
Message-ID <[email protected]>


https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=a7f2d458db2ed508959d2a425d326b0cc94806da

commit a7f2d458db2ed508959d2a425d326b0cc94806da
Author: Jon Turney <[email protected]>
Date:   Wed Mar 18 22:04:47 2020 +0000

    Fix an allocation length error
    
    Allow for the terminating null.

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=2fd5251b66ff0634579c3bfd8c0d0109fc0116b7

commit 2fd5251b66ff0634579c3bfd8c0d0109fc0116b7
Author: Jon Turney <[email protected]>
Date:   Tue Mar 17 15:21:50 2020 +0000

    Disable old Cygwin setup signing key by default
    
    Add a new option '--enable-old-keys', for if you really need to install
    from an old mirror for some reason.
    
    '--disable-old-keys' is still accepted, but is the default now.

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=8effde7afc285895e7a4d40a944ab2a7b9e51af1

commit 8effde7afc285895e7a4d40a944ab2a7b9e51af1
Author: Jon Turney <[email protected]>
Date:   Tue Mar 17 14:27:02 2020 +0000

    Implement paired boolean options
    
    Add some infrastructure for options which may appear with multiple
    prefixes.
    
    Add an implementation of paired boolean options like '--enable-foo' and
    '--disable-foo', or '--bar' and '--no-bar'.
    
    Add/fix tests

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=9a7997b94b5e9cf382e5094f91163f76b64ccb0f

commit 9a7997b94b5e9cf382e5094f91163f76b64ccb0f
Author: Jon Turney <[email protected]>
Date:   Tue Mar 17 13:54:16 2020 +0000

    Rename Start Menu folder for 32-bit installs on WoW64
    
    This is not totally straightforward: Since setup can install Cygwin with
    either bitness (using the '--arch 32|64' option), we must do the right
    thing if this is a 64-bit installer being used to install 32-bit Cygwin,
    which will run under WoW, even if the installer isn't...
    
    (Naming things like this makes things consistent with Cygwin-X, which
    already names it's Start Menu folder 'Cygwin-X (32-bit)' on WoW64. It
    also ensures that there aren't collisions between any setup created
    shortcuts for 32-bit and 64-bits.)
    
    The desktop icon is already named 'Cygwin Terminal' or 'Cygwin64
    Terminal' so doesn't need attention.
    
    Start menu links made in the 'Cygwin' folder by cygwin-doc, and possibly
    other packages will also need adjusting.

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=e73fb694a2d21f3cf36e658d9dd066b8ceaaa330

commit e73fb694a2d21f3cf36e658d9dd066b8ceaaa330
Author: Jon Turney <[email protected]>
Date:   Tue Mar 17 13:52:55 2020 +0000

    Factor out WoW detection
    
    Factor out WoW detection as a separate function


Diff:
---
 archive.cc                                       |  2 +-
 crypto.cc                                        |  7 ++--
 desktop.cc                                       | 13 ++++--
 libgetopt++/include/getopt++/BoolOption.h        | 17 ++++++--
 libgetopt++/include/getopt++/Option.h            |  6 ++-
 libgetopt++/include/getopt++/OptionSet.h         |  3 +-
 libgetopt++/include/getopt++/StringArrayOption.h |  2 +-
 libgetopt++/include/getopt++/StringOption.h      |  2 +-
 libgetopt++/src/BoolOption.cc                    | 40 ++++++++++++++++---
 libgetopt++/src/Option.cc                        |  7 ++++
 libgetopt++/src/OptionSet.cc                     | 50 +++++++++++++++---------
 libgetopt++/src/StringArrayOption.cc             |  2 +-
 libgetopt++/src/StringOption.cc                  |  2 +-
 libgetopt++/tests/BoolOptionTest.cc              | 26 +++++++++---
 libgetopt++/tests/OptionSet.cc                   |  4 +-
 nio-ie5.cc                                       | 45 ++++++++-------------
 win32.cc                                         | 26 ++++++++++++
 win32.h                                          |  2 +
 18 files changed, 177 insertions(+), 79 deletions(-)

diff --git a/archive.cc b/archive.cc
index e4af4f7b..1ceb3552 100644
--- a/archive.cc
+++ b/archive.cc
@@ -173,7 +173,7 @@ archive::extract_file (archive * source, const std::string& prefixURL,
 	  break;
 	case ARCHIVE_FILE_DIRECTORY:
 	  {
-	    char *path = (char *) alloca (destfilename.size());
+	    char *path = (char *) alloca (destfilename.size() + 1);
 	    strcpy (path, destfilename.c_str());
 	    while (path[0] && path[strlen (path) - 1] == '/')
 	      path[strlen (path) - 1] = 0;
diff --git a/crypto.cc b/crypto.cc
index 2e4ba218..88ced387 100644
--- a/crypto.cc
+++ b/crypto.cc
@@ -52,8 +52,9 @@ static BoolOption UntrustedKeysOption (false, 'u', "untrusted-keys",
 			"Use untrusted saved extra keys");
 static BoolOption KeepUntrustedKeysOption (false, 'U', "keep-untrusted-keys",
 			"Use untrusted keys and retain all");
-static BoolOption DisableOldKeysOption (false, '\0', "disable-old-keys",
-                                        "Disable old cygwin.com keys");
+static BoolOption EnableOldKeysOption (false, '\0', "old-keys",
+                                       "Enable old cygwin.com keys",
+                                       BoolOption::BoolOptionType::pairedAble);
 
 /*  Embedded public half of Cygwin signing key.  */
 static const char *cygwin_pubkey_sexpr =
@@ -708,7 +709,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
 
   /* If not disabled, also try the old built-in key */
   gcry_sexp_t cygwin_old_key;
-  if (!DisableOldKeysOption)
+  if (EnableOldKeysOption)
     {
       rv = gcry_sexp_new (&cygwin_old_key, cygwin_old_pubkey_sexpr, strlen (cygwin_old_pubkey_sexpr), 1);
       if (rv != GPG_ERR_NO_ERROR)
diff --git a/desktop.cc b/desktop.cc
index eec8ca91..29dbf635 100644
--- a/desktop.cc
+++ b/desktop.cc
@@ -95,6 +95,14 @@ make_link (const std::string& linkpath,
 	       icon.c_str(), fname.c_str());
 }
 
+static const char *startmenudir()
+{
+  if (!is_64bit && (WowNativeMachine() != IMAGE_FILE_MACHINE_I386))
+    return "/Cygwin (32-bit)";
+  else
+    return "/Cygwin";
+}
+
 static void
 start_menu (const std::string& title, const std::string& target,
 	    const std::string& arg, const std::string& iconpath)
@@ -107,7 +115,7 @@ start_menu (const std::string& title, const std::string& target,
 			      issystem ? CSIDL_COMMON_PROGRAMS :
 			      CSIDL_PROGRAMS, &id);
   SHGetPathFromIDList (id, path);
-  strncat (path, "/Cygwin", MAX_PATH - strlen(path) - 1);
+  strncat (path, startmenudir(), MAX_PATH - strlen(path) - 1);
   LogBabblePrintf ("Program directory for program link: %s", path);
   make_link (path, title, target, arg, iconpath);
 }
@@ -194,7 +202,6 @@ save_icon (std::string &iconpath, const char *resource_name)
 #define TERMINALICON	"/Cygwin-Terminal.ico"
 #define TERMINALTITLE	(is_64bit ? "Cygwin64 Terminal" \
 				  : "Cygwin Terminal")
-#define STARTMENUDIR	"/Cygwin"
 
 static void
 do_desktop_setup ()
@@ -300,7 +307,7 @@ check_startmenu (const std::string title, const std::string target)
 			      CSIDL_PROGRAMS, &id);
   SHGetPathFromIDList (id, path);
   LogBabblePrintf ("Program directory for program link: %s", path);
-  strcat (path, STARTMENUDIR);
+  strcat (path, startmenudir());
   std::string fname = std::string(path) + "/" + title + ".lnk";
 
   if (_access (fname.c_str(), 0) == 0)
diff --git a/libgetopt++/include/getopt++/BoolOption.h b/libgetopt++/include/getopt++/BoolOption.h
index 35227cb1..8b20e1cc 100644
--- a/libgetopt++/include/getopt++/BoolOption.h
+++ b/libgetopt++/include/getopt++/BoolOption.h
@@ -23,17 +23,25 @@
 class BoolOption : public Option
 {
 public:
+  enum class BoolOptionType
+    {
+     simple,
+     pairedAble,
+     pairedNo,
+    };
+
   BoolOption(bool const defaultvalue, char shortopt, char const *longopt = 0,
-	     std::string const &shorthelp = std::string(), 
-	     OptionSet &owner=GetOption::GetInstance());
+             std::string const &shorthelp = std::string(),
+             BoolOptionType type = BoolOptionType::simple,
+             OptionSet &owner=GetOption::GetInstance());
   virtual ~ BoolOption ();
   virtual std::string const shortOption () const;
   virtual std::string const longOption () const;
+  virtual std::vector<std::string> const & longOptionPrefixes () const;
   virtual std::string const shortHelp () const;
-  virtual Result Process (char const *);
+  virtual Result Process (char const *, int);
   virtual Argument argument () const;
   operator bool () const;
- 
 
 private:
   bool _value;
@@ -41,6 +49,7 @@ private:
   char _shortopt;
   char const *_longopt;
   std::string _shorthelp;
+  BoolOptionType _type;
 };
 
 #endif // _BOOLOPTION_H_
diff --git a/libgetopt++/include/getopt++/Option.h b/libgetopt++/include/getopt++/Option.h
index a32f9495..b3b140ff 100644
--- a/libgetopt++/include/getopt++/Option.h
+++ b/libgetopt++/include/getopt++/Option.h
@@ -21,9 +21,10 @@
 #endif
 #if HAVE_STRING_H
 #include <string>
-#else 
+#else
 #error "<string> required"
 #endif
+#include <vector>
 
 // Each registered option must implement this class.
 class Option
@@ -32,13 +33,14 @@ public:
   virtual ~ Option ();
   virtual std::string const shortOption () const = 0;
   virtual std::string const longOption () const = 0;
+  virtual std::vector<std::string> const & longOptionPrefixes () const;
   virtual std::string const shortHelp () const = 0;
   enum Result {
       Failed,
       Ok,
       Stop
   };
-  virtual Result Process (char const *) = 0;
+  virtual Result Process (char const *, int) = 0;
   enum Argument {
       None,
       Optional,
diff --git a/libgetopt++/include/getopt++/OptionSet.h b/libgetopt++/include/getopt++/OptionSet.h
index 4ccaddaf..dbd8046b 100644
--- a/libgetopt++/include/getopt++/OptionSet.h
+++ b/libgetopt++/include/getopt++/OptionSet.h
@@ -44,7 +44,8 @@ private:
   bool isOption(std::string::size_type) const;
   void doOption(std::string &option, std::string::size_type const &pos);
   bool doNoArgumentOption(std::string &option, std::string::size_type const &pos);
-  Option * findOption(std::string &option, std::string::size_type const &pos) const;
+  void findOption(std::string &option, std::string::size_type const &pos,
+                  Option *&theOption, int & prefixIndex) const;
   std::vector<Option *> options;
   std::vector<std::string> argv;
   std::vector<std::string> nonoptions;
diff --git a/libgetopt++/include/getopt++/StringArrayOption.h b/libgetopt++/include/getopt++/StringArrayOption.h
index d3f87c0d..b589d283 100644
--- a/libgetopt++/include/getopt++/StringArrayOption.h
+++ b/libgetopt++/include/getopt++/StringArrayOption.h
@@ -29,7 +29,7 @@ public:
   virtual std::string const shortOption () const;
   virtual std::string const longOption () const;
   virtual std::string const shortHelp () const;
-  virtual Result Process (char const *);
+  virtual Result Process (char const *, int);
   virtual Argument argument () const;
   operator std::vector<std::string> () const;
 
diff --git a/libgetopt++/include/getopt++/StringOption.h b/libgetopt++/include/getopt++/StringOption.h
index f13be8cb..37e723a6 100644
--- a/libgetopt++/include/getopt++/StringOption.h
+++ b/libgetopt++/include/getopt++/StringOption.h
@@ -30,7 +30,7 @@ public:
   virtual std::string const shortOption () const;
   virtual std::string const longOption () const;
   virtual std::string const shortHelp () const;
-  virtual Result Process (char const *);
+  virtual Result Process (char const *, int);
   virtual Argument argument () const;
   operator const std::string& () const;
 
diff --git a/libgetopt++/src/BoolOption.cc b/libgetopt++/src/BoolOption.cc
index 4b265539..37d9a229 100644
--- a/libgetopt++/src/BoolOption.cc
+++ b/libgetopt++/src/BoolOption.cc
@@ -16,10 +16,10 @@
 #include <getopt++/BoolOption.h>
 
 BoolOption::BoolOption(bool const defaultvalue, char shortopt,
-		       char const *longopt, std::string const &shorthelp,
-		       OptionSet &owner) : _value (defaultvalue) ,
-		       _ovalue (defaultvalue), _shortopt(shortopt),
-		       _longopt (longopt), _shorthelp (shorthelp)
+                       char const *longopt, std::string const &shorthelp,
+                       BoolOptionType type, OptionSet &owner) :
+  _value (defaultvalue), _ovalue (defaultvalue), _shortopt(shortopt),
+  _longopt (longopt), _shorthelp (shorthelp), _type(type)
 {
   owner.Register (this);
 };
@@ -38,6 +38,24 @@ BoolOption::longOption () const
   return _longopt;
 }
 
+std::vector<std::string> const &
+BoolOption::longOptionPrefixes () const
+{
+  switch (_type)
+    {
+    default:
+    case BoolOption::BoolOptionType::simple:
+      static std::vector<std::string> simple = {""};
+      return simple;
+    case BoolOption::BoolOptionType::pairedAble:
+      static std::vector<std::string> able = {"enable-", "disable-"};
+      return able;
+    case BoolOption::BoolOptionType::pairedNo:
+      static std::vector<std::string> no = {"", "no-"};
+      return no;
+    }
+}
+
 std::string const
 BoolOption::shortHelp () const
 {
@@ -45,9 +63,19 @@ BoolOption::shortHelp () const
 }
 
 Option::Result
-BoolOption::Process (char const *)
+BoolOption::Process (char const *, int prefixIndex)
 {
-  _value = !_ovalue;
+  switch (_type)
+    {
+    default:
+    case BoolOption::BoolOptionType::simple:
+      _value = !_ovalue;
+    case BoolOption::BoolOptionType::pairedAble:
+      _value = (prefixIndex == 0);
+    case BoolOption::BoolOptionType::pairedNo:
+      _value = (prefixIndex == 0);
+    }
+
   return Ok;
 }
 
diff --git a/libgetopt++/src/Option.cc b/libgetopt++/src/Option.cc
index 7c61ebad..2e6e9d8f 100644
--- a/libgetopt++/src/Option.cc
+++ b/libgetopt++/src/Option.cc
@@ -22,3 +22,10 @@ Option::Option () : present(false)
 Option::~Option ()
 {
 }
+
+std::vector<std::string> const &
+Option::longOptionPrefixes () const
+{
+  static std::vector<std::string> noprefix = {""};
+  return noprefix;
+}
diff --git a/libgetopt++/src/OptionSet.cc b/libgetopt++/src/OptionSet.cc
index a8f02e82..5a8ddee4 100644
--- a/libgetopt++/src/OptionSet.cc
+++ b/libgetopt++/src/OptionSet.cc
@@ -38,37 +38,47 @@ OptionSet::processOne()
 
     if (!isOption(pos)) {
         /* Push the non option into storage */
-	if (nonOptionHandler) {
-	    lastResult = nonOptionHandler->Process(option.c_str());
-	} else {
-	    nonoptions.push_back(option);
-	    lastResult = Option::Ok;
-	}
+      if (nonOptionHandler) {
+        lastResult = nonOptionHandler->Process(option.c_str(), 0);
+      } else {
+        nonoptions.push_back(option);
+        lastResult = Option::Ok;
+      }
     } else {
-	doOption(option, pos);
+      doOption(option, pos);
     }
 }
 
-Option *
-OptionSet::findOption(std::string &option, std::string::size_type const &pos) const
+void
+OptionSet::findOption(std::string &option, std::string::size_type const &pos,
+                      Option *&theOption, int & prefixIndex) const
 {
-    Option *theOption = NULL;
+    theOption = NULL;
+    prefixIndex = 0;
 
     for (std::vector<Option *>::const_iterator i = options.begin(); i != options.end(); 
             ++i) {
         if (pos == 1) {
             if (option[0] == (*i)->shortOption()[0]) {
                 theOption = (*i);
+                return;
             }
         } else {
-            /* pos == 2 : todo - prefix matches */
-
-            if (option.find((*i)->longOption()) == 0) {
+          /* pos == 2 */
+          std::vector<std::string> prefixes = (*i)->longOptionPrefixes();
+          for (std::vector<std::string>::const_iterator j = prefixes.begin();
+               j != prefixes.end();
+               j++)
+            {
+              std::string prefixedOption = *j + (*i)->longOption();
+              if (option.find(prefixedOption) == 0) {
                 theOption = (*i);
+                prefixIndex = j - prefixes.begin();
+                return;
+              }
             }
         }
     }
-    return theOption;
 }
 
 bool
@@ -98,7 +108,9 @@ OptionSet::doOption(std::string &option, std::string::size_type const &pos)
 {
     lastResult = Option::Failed;
     option.erase(0, pos);
-    Option *theOption = findOption(option, pos);
+    Option *theOption = NULL;
+    int prefixIndex = 0;
+    findOption(option, pos, theOption, prefixIndex);
     char const *optionValue = NULL;
     std::string value;
 
@@ -108,9 +120,9 @@ OptionSet::doOption(std::string &option, std::string::size_type const &pos)
     switch (theOption->argument()) {
 
     case Option::None:
-        if (!doNoArgumentOption (option, pos))
-	    return;
-	break;
+      if (!doNoArgumentOption (option, pos))
+        return;
+      break;
 
     case Option::Optional: {
             if (pos == 1) {
@@ -231,7 +243,7 @@ OptionSet::doOption(std::string &option, std::string::size_type const &pos)
 	break;
     }
     theOption->setPresent(true);
-    lastResult = theOption->Process(optionValue);
+    lastResult = theOption->Process(optionValue, prefixIndex);
 }
 
 OptionSet::OptionSet () {}
diff --git a/libgetopt++/src/StringArrayOption.cc b/libgetopt++/src/StringArrayOption.cc
index 7cbee201..fe6f6131 100644
--- a/libgetopt++/src/StringArrayOption.cc
+++ b/libgetopt++/src/StringArrayOption.cc
@@ -44,7 +44,7 @@ StringArrayOption::shortHelp () const
 }
 
 Option::Result
-StringArrayOption::Process (char const *optarg)
+StringArrayOption::Process (char const *optarg, int prefixIndex)
 {
   if (optarg)
     {
diff --git a/libgetopt++/src/StringOption.cc b/libgetopt++/src/StringOption.cc
index d3592366..e3c4af64 100644
--- a/libgetopt++/src/StringOption.cc
+++ b/libgetopt++/src/StringOption.cc
@@ -49,7 +49,7 @@ StringOption::shortHelp () const
 }
 
 Option::Result
-StringOption::Process (char const *optarg)
+StringOption::Process (char const *optarg, int prefixIndex)
 {
   if (optarg)
     _value = optarg;
diff --git a/libgetopt++/tests/BoolOptionTest.cc b/libgetopt++/tests/BoolOptionTest.cc
index d2c51909..7fdd2591 100644
--- a/libgetopt++/tests/BoolOptionTest.cc
+++ b/libgetopt++/tests/BoolOptionTest.cc
@@ -20,16 +20,18 @@
 #include <iostream>
 #include <string.h>
 
-static BoolOption testoption (false, 't', "testoption", "Tests the use of boolean options");
 int
 main (int anargc, char **anargv)
 {
+  BoolOption helpoption (false, 'h', "help", "Tests the use of help output.");
+  BoolOption helpoption2 (false, 'o', "help2", "Tests the use of help output.");
+  BoolOption ableoption (false, '\0', "foo", "Tests the use of paired option.", BoolOption::BoolOptionType::pairedAble);
+
   int argc=2;
   char *argv[4];
   argv[0] = strdup("BoolOptionTest");
   argv[1] = strdup("-h");
     {
-      BoolOption helpoption (false, 'h', "help", "Tests the use of help output.");
       if (!GetOption::GetInstance().Process (argc, argv, NULL))
 	{
 	  std::cout << "Failed to process options" << std::endl;
@@ -44,17 +46,31 @@ main (int anargc, char **anargv)
       argc = 0;
     }
     {
-      BoolOption helpoption (false, 'h', "help", "Tests the use of help output.");
       if (!GetOption::GetInstance().Process (argc, argv, NULL))
 	{
 	  std::cout << "Failed to process options (2) " << std::endl;
 	  return 1;
 	}
-      if (helpoption)
+      if (helpoption2)
 	{
-	  std::cout << "Recieved unexpected  help option" << std::endl;
+	  std::cout << "Received unexpected help option" << std::endl;
 	  return 1;
 	}
     }
+  argc=2;
+  argv[0] = strdup("BoolOptionTest");
+  argv[1] = strdup("--enable-foo");
+    {
+      if (!GetOption::GetInstance().Process (argc, argv, NULL))
+        {
+          std::cout << "Failed to process options (3) " << std::endl;
+          return 1;
+        }
+      if (!ableoption)
+        {
+          std::cout << "Did not receive expected enable-foo option" << std::endl;
+          return 1;
+        }
+    }
   return 0;
 }
diff --git a/libgetopt++/tests/OptionSet.cc b/libgetopt++/tests/OptionSet.cc
index ff63e390..4eac880c 100644
--- a/libgetopt++/tests/OptionSet.cc
+++ b/libgetopt++/tests/OptionSet.cc
@@ -36,7 +36,7 @@ class StringCollector : public Option
        {
 	 return "";
        }
-     virtual Option::Result Process(const char * value);
+     virtual Option::Result Process(const char * value, int index);
      virtual Option::Argument argument() const
        {
 	 return Required;
@@ -46,7 +46,7 @@ class StringCollector : public Option
 };
 
 Option::Result
-StringCollector::Process(const char * value)
+StringCollector::Process(const char * value, int index)
 {
     values.push_back(value);
     if (values.size() == 1)
diff --git a/nio-ie5.cc b/nio-ie5.cc
index f5ad020c..fe61b778 100644
--- a/nio-ie5.cc
+++ b/nio-ie5.cc
@@ -52,37 +52,24 @@ determine_default_useragent(void)
 #ifdef __x86_64__
   bitness = "Win64";
 #else
-  typedef BOOL (WINAPI *PFNISWOW64PROCESS2)(HANDLE, USHORT *, USHORT *);
-  PFNISWOW64PROCESS2 pfnIsWow64Process2 = (PFNISWOW64PROCESS2)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process2");
-
-  typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
-  PFNISWOW64PROCESS pfnIsWow64Process = (PFNISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
-
+  USHORT nativeMachine = WowNativeMachine();
   std::stringstream native_desc;
 
-  USHORT processMachine, nativeMachine;
-  if ((pfnIsWow64Process2) &&
-      (pfnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine))) {
-    switch (nativeMachine)
-      {
-      case IMAGE_FILE_MACHINE_I386:
-        bitness = "Win32";
-        break;
-      case IMAGE_FILE_MACHINE_AMD64:
-        bitness = "WoW64";
-        break;
-      case IMAGE_FILE_MACHINE_ARM64:
-        bitness = "WoW64-ARM64";
-        break;
-      default:
-        native_desc << "WoW64-" << std::hex << nativeMachine;
-        bitness = native_desc.str();
-      }
-  } else if (pfnIsWow64Process) {
-    BOOL bIsWow64 = FALSE;
-    if (pfnIsWow64Process(GetCurrentProcess(), &bIsWow64))
-      bitness = bIsWow64 ? "WoW64" : "Win32";
-  }
+  switch (nativeMachine)
+    {
+    case IMAGE_FILE_MACHINE_I386:
+      bitness = "Win32";
+      break;
+    case IMAGE_FILE_MACHINE_AMD64:
+      bitness = "WoW64";
+      break;
+    case IMAGE_FILE_MACHINE_ARM64:
+      bitness = "WoW64-ARM64";
+      break;
+    default:
+      native_desc << "WoW64-" << std::hex << nativeMachine;
+      bitness = native_desc.str();
+    }
 #endif
   default_useragent = std::string("Cygwin-Setup/") + setup_version + " (" + os.str() + ";" + bitness + ")";
   return default_useragent;
diff --git a/win32.cc b/win32.cc
index 6a551bac..45c7bf1b 100644
--- a/win32.cc
+++ b/win32.cc
@@ -393,3 +393,29 @@ VersionInfo& GetVer ()
   static VersionInfo *vi = new VersionInfo ();
   return *vi;
 }
+
+/* Identify native machine arch if we are running under WoW */
+USHORT
+WowNativeMachine ()
+{
+#ifdef __x86_64__
+  return IMAGE_FILE_MACHINE_AMD64;
+#else
+  typedef BOOL (WINAPI *PFNISWOW64PROCESS2)(HANDLE, USHORT *, USHORT *);
+  PFNISWOW64PROCESS2 pfnIsWow64Process2 = (PFNISWOW64PROCESS2)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process2");
+
+  typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
+  PFNISWOW64PROCESS pfnIsWow64Process = (PFNISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
+
+  USHORT processMachine, nativeMachine;
+  if ((pfnIsWow64Process2) &&
+      (pfnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)))
+    return nativeMachine;
+  else if (pfnIsWow64Process) {
+    BOOL bIsWow64 = FALSE;
+    if (pfnIsWow64Process(GetCurrentProcess(), &bIsWow64))
+      return bIsWow64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386;
+  }
+  return IMAGE_FILE_MACHINE_I386;
+#endif
+}
diff --git a/win32.h b/win32.h
index 1b9db490..a7d025d2 100644
--- a/win32.h
+++ b/win32.h
@@ -177,6 +177,8 @@ VersionInfo& GetVer ();
 #define OSMinorVersion() (GetVer ().minor ())
 #define OSBuildNumber() (GetVer ().buildNumber ())
 
+USHORT WowNativeMachine ();
+
 static inline void
 GetDlgItemRect (HWND h, int item, LPRECT r)
 {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.