+#define MINGW_NAME "Minimalist GNU for Windows"
+#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
+
+extern char *stpcpy (char *dst, const char *src);
+
+/* Ensure that the executable pathname uses Win32 backslashes. This
+ is not necessary on NT, but on W9x, forward slashes causes
+ failure of spawn* and exec* functions (and probably any function
+ that calls CreateProcess) *iff* the executable pathname (argv[0])
+ is a quoted string. And quoting is necessary in case a pathname
+ contains embedded white space. You can't win. */
+static void
+backslashify (char *s)
+{
+ while ((s = strchr (s, '/')) != NULL)
+ *s = '\\';
+ return;
+}
+
+static int pex_win32_open_read (struct pex_obj *, const char *, int);
+static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
+static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
+ char * const *, char * const *,
+ int, int, int, int,
+ const char **, int *);
+static int pex_win32_close (struct pex_obj *, int);
+static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
+ struct pex_time *, int, const char **, int *);
+static int pex_win32_pipe (struct pex_obj *, int *, int);
+static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
+
+/* The list of functions we pass to the common routines. */
+
+const struct pex_funcs funcs =
+{
+ pex_win32_open_read,
+ pex_win32_open_write,
+ pex_win32_exec_child,
+ pex_win32_close,
+ pex_win32_wait,
+ pex_win32_pipe,
+ pex_win32_fdopenr,
+ pex_win32_fdopenw,
+ NULL /* cleanup */
+};
+
+/* Return a newly initialized pex_obj structure. */
+
+struct pex_obj *
+pex_init (int flags, const char *pname, const char *tempbase)
+{
+ return pex_init_common (flags, pname, tempbase, &funcs);
+}
+
+/* Open a file for reading. */
+
+static int
+pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary)
+{
+ return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
+}
+
+/* Open a file for writing. */
+
+static int
+pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary, int append)
+{
+ /* Note that we can't use O_EXCL here because gcc may have already
+ created the temporary file via make_temp_file. */
+ if (append)
+ return -1;
+ return _open (name,
+ (_O_WRONLY | _O_CREAT | _O_TRUNC
+ | (binary ? _O_BINARY : _O_TEXT)),
+ _S_IREAD | _S_IWRITE);
+}
+
+/* Close a file. */
+
+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);
+ free (namebuf);
+ 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)