+static int
+pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
+{
+ return _close (fd);
+}
+
+#ifdef USE_MINGW_MSYS
+static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
+
+/* Tack the executable on the end of a (possibly slash terminated) buffer
+ and convert everything to \. */
+static const char *
+tack_on_executable (char *buf, const char *executable)
+{
+ char *p = strchr (buf, '\0');
+ if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
+ p[-1] = '\0';
+ backslashify (strcat (buf, executable));
+ return buf;
+}
+
+/* Walk down a registry hierarchy until the end. Return the key. */
+static HKEY
+openkey (HKEY hStart, const char *keys[])
+{
+ HKEY hKey, hTmp;
+ for (hKey = hStart; *keys; keys++)
+ {
+ LONG res;
+ hTmp = hKey;
+ res = RegOpenKey (hTmp, *keys, &hKey);
+
+ if (hTmp != HKEY_LOCAL_MACHINE)
+ RegCloseKey (hTmp);
+
+ if (res != ERROR_SUCCESS)
+ return NULL;
+ }
+ return hKey;
+}
+
+/* Return the "mingw root" as derived from the mingw uninstall information. */
+static const char *
+mingw_rootify (const char *executable)
+{
+ HKEY hKey, hTmp;
+ DWORD maxlen;
+ char *namebuf, *foundbuf;
+ DWORD i;
+ LONG res;
+
+ /* Open the uninstall "directory". */
+ hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
+
+ /* Not found. */
+ if (!hKey)
+ return executable;
+
+ /* Need to enumerate all of the keys here looking for one the most recent
+ one for MinGW. */
+ if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
+ NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+ {
+ RegCloseKey (hKey);
+ return executable;
+ }
+ namebuf = XNEWVEC (char, ++maxlen);
+ foundbuf = XNEWVEC (char, maxlen);
+ foundbuf[0] = '\0';
+ if (!namebuf || !foundbuf)
+ {
+ RegCloseKey (hKey);
+ if (namebuf)
+ free (namebuf);
+ if (foundbuf)
+ free (foundbuf);
+ return executable;
+ }
+
+ /* Look through all of the keys for one that begins with Minimal GNU...
+ Try to get the latest version by doing a string compare although that
+ string never really works with version number sorting. */
+ for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
+ {
+ int match = strcasecmp (namebuf, MINGW_NAME);
+ if (match < 0)
+ continue;
+ if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
+ continue;
+ if (strcasecmp (namebuf, foundbuf) > 0)
+ strcpy (foundbuf, namebuf);
+ }
+ free (namebuf);
+
+ /* If foundbuf is empty, we didn't find anything. Punt. */
+ if (!foundbuf[0])
+ {
+ free (foundbuf);
+ RegCloseKey (hKey);
+ return executable;
+ }
+
+ /* Open the key that we wanted */
+ res = RegOpenKey (hKey, foundbuf, &hTmp);
+ RegCloseKey (hKey);
+ free (foundbuf);
+
+ /* Don't know why this would fail, but you gotta check */
+ if (res != ERROR_SUCCESS)
+ return executable;
+
+ maxlen = 0;
+ /* Get the length of the value pointed to by InstallLocation */
+ if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
+ &maxlen) != ERROR_SUCCESS || maxlen == 0)
+ {
+ RegCloseKey (hTmp);
+ return executable;
+ }
+
+ /* Allocate space for the install location */
+ foundbuf = XNEWVEC (char, maxlen + strlen (executable));
+ if (!foundbuf)
+ {
+ free (foundbuf);
+ RegCloseKey (hTmp);
+ }
+
+ /* Read the install location into the buffer */
+ res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
+ &maxlen);
+ RegCloseKey (hTmp);
+ if (res != ERROR_SUCCESS)
+ {
+ free (foundbuf);
+ return executable;
+ }
+
+ /* Concatenate the install location and the executable, turn all slashes
+ to backslashes, and return that. */
+ return tack_on_executable (foundbuf, executable);
+}
+
+/* Read the install location of msys from it's installation file and
+ rootify the executable based on that. */
+static const char *
+msys_rootify (const char *executable)
+{
+ size_t bufsize = 64;
+ size_t execlen = strlen (executable) + 1;
+ char *buf;
+ DWORD res = 0;
+ for (;;)
+ {
+ buf = XNEWVEC (char, bufsize + execlen);
+ if (!buf)
+ break;
+ res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
+ buf, bufsize, "msys.ini");
+ if (!res)
+ break;
+ if (strlen (buf) < bufsize)
+ break;
+ res = 0;
+ free (buf);
+ bufsize *= 2;
+ if (bufsize > 65536)
+ {
+ buf = NULL;
+ break;