--- bash.c~0	2008-01-18 20:07:02.000000000 +0200
+++ bash.c	2012-02-09 12:14:56.084255500 +0200
@@ -21,7 +21,13 @@
 
 #include "sys.h"
 #include "posixstat.h"
+#if defined (HAVE_PWD_H)
 #include <pwd.h>
+#endif
+#ifdef __MINGW32__
+#include <windows.h>
+#include <lmcons.h>
+#endif
 #include "bash.h"
 
 /* Use the type that was determined by configure. */
@@ -32,7 +38,9 @@
  * Perhaps these need new configure.in entries.
  * The following macro's are used in bash, and below:
  */
+#ifndef __MINGW32__
 #define HAVE_GETGROUPS
+#endif
 #undef SHELL
 #undef AFS
 #undef NOGROUP
@@ -47,7 +55,6 @@
  * - exported functions needed in which.c
  */
 static int group_member (GID_T gid);
-static char* extract_colon_unit (char const* string, int* p_index);
 
 /*===========================================================================
  *
@@ -76,6 +83,159 @@ struct user_info current_user =
 /* From bash-3.2 / general.h / line 153 */
 #define FREE(s)  do { if (s) free (s); } while (0)
 
+#ifdef __MINGW32__
+#include <windows.h>
+#include <lmcons.h>
+
+/* The following 2 functions were shamelessly stolen from Emacs's
+   w32.c.  */
+
+static DWORD
+get_rid (PSID sid)
+{
+  unsigned n_subauthorities;
+
+  /* Use the last sub-authority value of the RID, the relative
+     portion of the SID, as user/group ID. */
+  n_subauthorities = *GetSidSubAuthorityCount (sid);
+  if (n_subauthorities < 1)
+    return 0;	/* the "World" RID */
+  return *GetSidSubAuthority (sid, n_subauthorities - 1);
+}
+
+static int
+init_user_info (void)
+{
+  char         uname[UNLEN+1], domain[1025];
+  DWORD        ulength = sizeof (uname), dlength = sizeof (domain), needed;
+  HANDLE       token = NULL;
+  SID_NAME_USE user_type;
+  unsigned char *buf = NULL;
+  DWORD        blen = 0;
+  TOKEN_USER   user_token;
+  TOKEN_PRIMARY_GROUP group_token;
+  BOOL         result;
+  HMODULE      hm;
+
+  if ((hm = LoadLibrary ("Advapi32.dll")) == NULL
+      || GetProcAddress (hm, "OpenProcessToken") == NULL
+      || GetProcAddress (hm, "GetTokenInformation") == NULL
+      || GetProcAddress (hm, "LookupAccountSidA") == NULL)
+    result = 0;
+  else
+    result = OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token);
+  if (result)
+    {
+      result = GetTokenInformation (token, TokenUser, NULL, 0, &blen);
+      if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+	{
+	  buf = xmalloc (blen);
+	  result = GetTokenInformation (token, TokenUser,
+					(LPVOID)buf, blen, &needed);
+	  if (result)
+	    {
+	      memcpy (&user_token, buf, sizeof (user_token));
+	      result = LookupAccountSid (NULL, user_token.User.Sid,
+					 uname, &ulength,
+					 domain, &dlength, &user_type);
+	    }
+	}
+      else
+	result = 0;
+    }
+  if (result)
+    {
+      current_user.user_name = savestring (uname);
+      /* Determine a reasonable uid value.  */
+      if (strcasecmp ("administrator", uname) == 0)
+	{
+	  /* Well-known Administrator RID.  */
+	  current_user.uid = current_user.euid = 500;
+	  /* Well-known None group RID.  */
+	  current_user.gid = current_user.egid = 513;
+	}
+      else
+	{
+	  /* Use the last sub-authority value of the RID, the relative
+	     portion of the SID, as user/group ID. */
+	  current_user.uid = current_user.euid = get_rid (user_token.User.Sid);
+
+	  /* Get group id and name.  */
+	  result = GetTokenInformation (token, TokenPrimaryGroup,
+					(LPVOID)buf, blen, &needed);
+	  if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+	    {
+	      buf = xrealloc (buf, blen = needed);
+	      result = GetTokenInformation (token, TokenPrimaryGroup,
+					    (LPVOID)buf, blen, &needed);
+	    }
+	  if (result)
+	    {
+	      memcpy (&group_token, buf, sizeof (group_token));
+	      current_user.gid = get_rid (group_token.PrimaryGroup);
+	      current_user.egid = current_user.gid;
+	    }
+	  else
+	    current_user.gid = current_user.egid = current_user.uid;
+	}
+    }
+  /* If security calls are not supported (presumably because we
+     are running under Windows 9X), fallback to this: */
+  else if (GetUserName (uname, &ulength))
+    {
+      current_user.user_name = savestring (uname);
+      if (strcasecmp ("administrator", uname) == 0)
+	current_user.uid = 500;
+      else
+	current_user.uid = 42;
+      current_user.euid = current_user.uid;
+      current_user.gid = current_user.egid = current_user.uid;
+    }
+  else
+    {
+      current_user.user_name = savestring ("I have no name!");
+      current_user.uid = current_user.euid = 42;
+      current_user.gid = current_user.egid = 42;
+    }
+
+  free (buf);
+  if (token)
+    CloseHandle (token);
+}
+
+uid_t
+getuid (void)
+{
+  if (current_user.user_name == NULL)
+    init_user_info ();
+  return current_user.uid;
+}
+
+uid_t
+geteuid (void)
+{
+  if (current_user.user_name == NULL)
+    init_user_info ();
+  return current_user.euid;
+}
+
+gid_t
+getgid (void)
+{
+  if (current_user.user_name == NULL)
+    init_user_info ();
+  return current_user.gid;
+}
+
+gid_t
+getegid (void)
+{
+  if (current_user.user_name == NULL)
+    init_user_info ();
+  return current_user.egid;
+}
+#endif	/* __MINGW32__ */
+
 /* From bash-3.2 / shell.c / line 1136 */
 /* Fetch the current set of uids and gids and return 1 if we're running
    setuid or setgid. */
@@ -315,7 +475,12 @@ file_status (char const* name)
 int
 absolute_program (char const* string)
 {
-  return ((char *)strchr (string, '/') != (char *)NULL);
+  return ((char *)strchr (string, '/') != (char *)NULL
+#ifdef __MINGW32__
+	  || (char *)strchr (string, '\\') != (char *)NULL
+	  || (string[0] && string[1] == ':')
+#endif
+	  );
 }
 
 /* From bash-3.2 / stringlib.c / line 124 */
@@ -358,10 +523,10 @@ extract_colon_unit (char const* string, 
      `:'.  If I is 0, then the path has a leading colon.  Trailing colons
      are handled OK by the `else' part of the if statement; an empty
      string is returned in that case. */
-  if (i && string[i] == ':')
+  if (i && string[i] == PATH_SEP)
     i++;
 
-  for (start = i; string[i] && string[i] != ':'; i++)
+  for (start = i; string[i] && string[i] != PATH_SEP; i++)
     ;
 
   *p_index = i;
@@ -408,16 +573,19 @@ get_next_path_element (char const* path_
 /* Turn PATH, a directory, and NAME, a filename, into a full pathname.
    This allocates new memory and returns it. */
 char *
-make_full_pathname (const char *path, const char *name, int name_len)
+make_full_pathname (const char *path, const char *name, const char *ext, int name_len)
 {
   char *full_path;
   int path_len;
 
   path_len = strlen (path);
-  full_path = (char *) xmalloc (2 + path_len + name_len);
+  full_path = (char *) xmalloc (2 + path_len + name_len
+				+ (ext ? strlen (ext) : 0));
   strcpy (full_path, path);
   full_path[path_len] = '/';
   strcpy (full_path + path_len + 1, name);
+  if (ext)
+    strcpy (full_path + path_len + 1 + name_len, ext);
   return (full_path);
 }
 
@@ -425,28 +593,57 @@ make_full_pathname (const char *path, co
 static void
 get_current_user_info ()
 {
-  struct passwd *entry;
+  struct passwd *entry = NULL;
 
   /* Don't fetch this more than once. */
-  if (current_user.user_name == 0)
+  if (current_user.user_name == 0
+      || current_user.home_dir == 0
+      || current_user.shell == 0)
     {
+#if defined (HAVE_GETPWUID)
       entry = getpwuid (current_user.uid);
       if (entry)
         {
           current_user.user_name = savestring (entry->pw_name);
           current_user.shell = (entry->pw_shell && entry->pw_shell[0])
                                 ? savestring (entry->pw_shell)
+#ifdef __MINGW32__
+                                : savestring ("cmd.exe");
+#else
                                 : savestring ("/bin/sh");
+#endif
           current_user.home_dir = savestring (entry->pw_dir);
         }
       else
+#endif	/* HAVE_GETPWUID */
         {
+#ifdef __MINGW32__
+	  char user_name[UNLEN+1];
+	  DWORD length = sizeof (user_name);
+	  char *homedir;
+
+	  if (GetUserName (user_name, &length))
+	    current_user.user_name = user_name;
+	  else
+	    current_user.user_name = "I have no name!";
+          current_user.user_name = savestring (current_user.user_name);
+          current_user.shell = savestring ("cmd.exe");
+	  homedir = getenv ("HOME");
+	  if (!homedir)
+	    homedir = getenv ("USERPROFILE");
+	  if (!homedir)
+	    homedir = "C:\\";
+          current_user.home_dir = savestring (homedir);
+#else
           current_user.user_name = "I have no name!";
           current_user.user_name = savestring (current_user.user_name);
           current_user.shell = savestring ("/bin/sh");
           current_user.home_dir = savestring ("/");
+#endif
         }
+#if defined (HAVE_GETPWENT)
       endpwent ();
+#endif
     }
 }
 
--- bash.h~0	2008-01-18 20:07:02.000000000 +0200
+++ bash.h	2012-02-08 09:48:41.861266400 +0200
@@ -13,7 +13,8 @@
 
 extern int file_status(const char *name);
 extern int absolute_program(const char *string);
+extern char *extract_colon_unit (char const* string, int* p_index);
 extern char *get_next_path_element(char const* path_list, int *path_index_pointer);
-extern char *make_full_pathname(const char *path, const char *name, int name_len);
+extern char *make_full_pathname(const char *path, const char *name, const char *ext, int name_len);
 extern int uidget();
 extern char* sh_get_home_dir(void);
--- posixstat.h~0	2007-05-26 01:13:24.000000000 +0300
+++ posixstat.h	2012-01-15 08:29:53.629320700 +0200
@@ -146,4 +146,13 @@
 #define S_IWUGO		(S_IWUSR | S_IWGRP | S_IWOTH)
 #define S_IXUGO		(S_IXUSR | S_IXGRP | S_IXOTH)
 
+#ifdef __MINGW32__
+#  define S_IXGRP	(S_IXUSR >> 3)
+#  define S_IRGRP	(S_IRUSR >> 3)
+#  define S_IWGRP	(S_IWUSR >> 3)
+#  define S_IXOTH	(S_IXUSR >> 6)
+#  define S_IROTH	(S_IRUSR >> 6)
+#  define S_IWOTH	(S_IWUSR >> 6)
+#endif	/* __MINGW32__ */
+
 #endif /* _POSIXSTAT_H */
--- sys.h~0	2007-05-26 01:13:24.000000000 +0300
+++ sys.h	2012-01-12 16:48:47.549351100 +0200
@@ -51,3 +51,15 @@ extern void *xrealloc(void *ptr, size_t 
 #   error "You either need getcwd(3) or getwd(3)"
 # endif
 #endif
+
+#ifdef __MINGW32__
+#define IS_SLASH(C)	((C) == '/' || (C) == '\\')
+#define IS_ABSOLUTE(N)	(((N)[0] != '\0' && (N)[1] == ':') || IS_SLASH((N)[0]))
+#define ISATTY(F)	(isatty(F) && lseek (F, SEEK_CUR, 0) == -1)
+#define PATH_SEP	';'
+#else  /* !__MINGW32__ */
+#define IS_SLASH(C)	((C) == '/')
+#define IS_ABSOLUTE(N)	IS_SLASH((N)[0])
+#define ISATTY(F)	isatty(F)
+#define PATH_SEP	':'
+#endif	/* !__MINGW32__ */
--- tilde/shell.c~0	2008-01-16 19:51:57.000000000 +0200
+++ tilde/shell.c	2012-01-15 08:22:28.679043400 +0200
@@ -43,7 +43,9 @@
 #  include <strings.h>
 #endif /* !HAVE_STRING_H */
 
+#if defined (HAVE_PWD_H)
 #include <pwd.h>
+#endif
 
 #if !defined (HAVE_GETPW_DECLS)
 extern struct passwd *getpwuid ();
@@ -59,12 +61,13 @@ get_env_value (varname)
 char *
 get_home_dir ()
 {
-  char *home_dir;
+  char *home_dir = (char *)NULL;
+#if defined (HAVE_GETPWUID)
   struct passwd *entry;
 
-  home_dir = (char *)NULL;
   entry = getpwuid (getuid ());
   if (entry)
     home_dir = entry->pw_dir;
+#endif
   return (home_dir);
 }
--- tilde/tilde.c~0	2008-01-16 19:51:57.000000000 +0200
+++ tilde/tilde.c	2012-02-09 08:56:48.470372500 +0200
@@ -171,7 +171,7 @@ tilde_find_suffix (string)
 
   for (i = 0; i < string_len; i++)
     {
-#if defined (__MSDOS__)
+#if defined (__MSDOS__) || defined (__MINGW32__)
       if (string[i] == '/' || string[i] == '\\' /* || !string[i] */)
 #else
       if (string[i] == '/' /* || !string[i] */)
@@ -271,7 +271,7 @@ isolate_tilde_prefix (fname, lenp)
   int i;
 
   ret = (char *)xmalloc (strlen (fname));
-#if defined (__MSDOS__)
+#if defined (__MSDOS__) || defined (__MINGW32__)
   for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
 #else
   for (i = 1; fname[i] && fname[i] != '/'; i++)
--- which.c~0	2008-01-18 20:07:02.000000000 +0200
+++ which.c	2012-02-09 13:26:29.802535900 +0200
@@ -23,6 +23,10 @@
 #include "tilde/tilde.h"
 #include "bash.h"
 
+#ifdef __MINGW32__
+#include <direct.h>
+#endif
+
 static const char *progname;
 
 static void print_usage(FILE *out)
@@ -53,6 +57,7 @@ static void print_usage(FILE *out)
 static void print_version(void)
 {
   fprintf(stdout, "GNU which v" VERSION ", Copyright (C) 1999 - 2008 Carlo Wood.\n");
+  fprintf(stdout, "(Modified for MS-Windows/MinGW by Eli Zaretskii.)\n");
   fprintf(stdout, "GNU which comes with ABSOLUTELY NO WARRANTY;\n");
   fprintf(stdout, "This program is free software; your freedom to use, change\n");
   fprintf(stdout, "and distribute this program is protected by the GPL.\n");
@@ -63,10 +68,10 @@ static void print_fail(const char *name,
   fprintf(stderr, "%s: no %s in (%s)\n", progname, name, path_list);
 }
 
-static char home[256];
+static char home[FILENAME_MAX];
 static size_t homelen = 0;
 
-static int absolute_path_given;
+static int absolute_path_given, ext_given;
 static int found_path_starts_with_dot;
 static char *abs_path;
 
@@ -74,10 +79,66 @@ static int skip_dot = 0, skip_tilde = 0,
 static int show_dot = 0, show_tilde = 0, show_all = 0, tty_only = 0;
 static int skip_functions = 0, read_functions = 0;
 
-static char *find_command_in_path(const char *name, const char *path_list, int *path_index)
+static char *pathext;
+
+/* Functions to compare file names.  */
+static int
+fncmp(const char *s1, const char *s2)
+{
+#ifdef __MINGW32__
+  /* Compare case-insensitively and treat / and \ styles of slashes as
+     equal. */
+  while (*s1 && *s2)
+    {
+      if (!(tolower(*s1) == tolower(*s2)
+	    || IS_SLASH (*s1) && IS_SLASH (*s2)))
+	break;
+      s1++;
+      s2++;
+    }
+  if (IS_SLASH (*s1) && IS_SLASH (*s2))
+    return 0;
+  return (int)tolower((unsigned char)*s1) - (int)tolower((unsigned char)*s2);
+#else
+  return strcmp(s1, s2);
+#endif
+}
+
+static int
+fncmpn(const char *s1, const char *s2, size_t n)
+{
+#ifdef __MINGW32__
+  /* Compare case-insensitively and treat / and \ styles of slashes as
+     equal. */
+  if (n <= 0)
+    return 0;
+
+  while (*s1 && *s2)
+    {
+      if (!(tolower(*s1) == tolower(*s2)
+	    || IS_SLASH (*s1) && IS_SLASH (*s2)))
+	break;
+      n--;
+      if (n == 0)
+	break;
+      s1++;
+      s2++;
+    }
+  if (IS_SLASH (*s1) && IS_SLASH (*s2))
+    return 0;
+  return (int)tolower((unsigned char)*s1) - (int)tolower((unsigned char)*s2);
+#else
+  return strncmp(s1, s2, n);
+#endif
+}
+
+static char *find_command_in_path(const char *name, const char *path_list, int *path_index, const char *path_ext, int *ext_index)
 {
   char *found = NULL, *full_path;
   int status, name_len;
+  char *file_ext;
+  char *p;
+  char *pext = (char *)path_ext;
 
   name_len = strlen(name);
 
@@ -85,18 +146,42 @@ static char *find_command_in_path(const 
     absolute_path_given = 0;
   else
   {
-    char *p;
     absolute_path_given = 1;
 
     if (abs_path)
       free(abs_path);
 
-    if (*name != '.' && *name != '/' && *name != '~')
+    if (*name != '.' && !IS_ABSOLUTE(name) && *name != '~')
     {
       abs_path = (char *)xmalloc(3 + name_len);
       strcpy(abs_path, "./");
       strcat(abs_path, name);
     }
+#ifdef __MINGW32__
+    else if (*name && name[1] == ':' && !IS_SLASH(name[2]))
+    {
+      char dcwd[MAX_PATH];
+
+      /* Replace "X:" with "X:\current\dir\on\drive\X".  */
+      if (_getdcwd(toupper(*name) - 'A' + 1, dcwd, MAX_PATH) != NULL)
+      {
+	int dcwd_len = strlen(dcwd);
+
+	abs_path = (char *)xmalloc(1+ dcwd_len + 1 + name_len - 2);
+	strcpy(abs_path, dcwd);
+	if (!IS_SLASH (dcwd[dcwd_len - 1]))
+	  strcat(abs_path, "/");
+	strcat(abs_path, name + 2);
+      }
+      else
+      {
+	abs_path = (char *)xmalloc(3 + name_len);
+	strncpy(abs_path, name, 2);
+	strncpy(abs_path + 2, "./", 2);
+	strcpy(abs_path + 4, name + 2);
+      }
+    }
+#endif
     else
     {
       abs_path = (char *)xmalloc(1 + name_len);
@@ -105,13 +190,28 @@ static char *find_command_in_path(const 
 
     path_list = abs_path;
     p = strrchr(abs_path, '/');
+#ifdef __MINGW32__
+    if (!p || strrchr(abs_path, '\\') > p)
+      p = strrchr(abs_path, '\\');
+#endif	/* __MINGW32__ */
     *p++ = 0;
     name = p;
+    name_len = strlen(name);
+  }
+
+  /* If NAME includes an extension, use only that extension and don't
+     try appending others.  */
+  ext_given = 0;
+  if ((p = strchr(name, '.')) != 0)
+  {
+    ext_given = 1;
+    pext = savestring(p);
   }
 
   while (path_list && path_list[*path_index])
   {
     char *path;
+    int prev_path_index = *path_index;
 
     if (absolute_path_given)
     {
@@ -137,7 +237,7 @@ static char *find_command_in_path(const 
       }
     }
 
-    if (skip_dot && *path != '/')
+    if (skip_dot && !IS_ABSOLUTE (path))
     {
       free(path);
       continue;
@@ -145,24 +245,62 @@ static char *find_command_in_path(const 
 
     found_path_starts_with_dot = (*path == '.');
 
-    full_path = make_full_pathname(path, name, name_len);
-    free(path);
+    while (pext && pext[*ext_index])
+    {
+      if (ext_given)
+      {
+	file_ext = NULL;
+	*ext_index = strlen(pext);
+      }
+      else
+      {
+	file_ext = extract_colon_unit(pext, ext_index);
+	if (!file_ext)
+	  break;
+      }
 
-    status = file_status(full_path);
+      full_path = make_full_pathname(path, name, file_ext, name_len);
 
-    if ((status & FS_EXISTS) && (status & FS_EXECABLE))
-    {
-      found = full_path;
-      break;
+      status = file_status(full_path);
+
+      if ((status & FS_EXISTS)
+	  && ((status & FS_EXECABLE)
+#ifdef __MINGW32__
+	      /* On Windows, any file with an extension from PATHEXT
+		 is executable, as long as it is not a directory.  */
+	      || !(status & FS_DIRECTORY)
+#endif
+	      ))
+      {
+	found = full_path;
+	*path_index = prev_path_index;
+	if (file_ext)
+	  free(file_ext);
+	break;
+      }
+      free(full_path);
+      full_path = NULL;
+      if (file_ext)
+	free(file_ext);
     }
+    free(path);
+    /* Reset the index of extensions array for searching the next
+       element of PATH_LIST.  */
+    if (!found && pext && !pext[*ext_index])
+      *ext_index = 0;
 
-    free(full_path);
+    if (found)
+      break;
+    if (full_path)
+      free(full_path);
   }
 
+  if (ext_given)
+    free(pext);
   return (found);
 }
 
-static char cwd[256];
+static char cwd[FILENAME_MAX];
 static size_t cwdlen;
 
 static void get_current_working_directory(void)
@@ -177,7 +315,7 @@ static void get_current_working_director
       strcpy(cwd, pwd);
   }
 
-  if (*cwd != '/')
+  if (!IS_ABSOLUTE (cwd))
   {
     fprintf(stderr, "Can't get current working directory\n");
     exit(-1);
@@ -185,7 +323,7 @@ static void get_current_working_director
 
   cwdlen = strlen(cwd);
 
-  if (cwd[cwdlen - 1] != '/')
+  if (!IS_SLASH (cwd[cwdlen - 1]))
   {
     cwd[cwdlen++] = '/';
     cwd[cwdlen] = 0;
@@ -194,14 +332,14 @@ static void get_current_working_director
 
 static char *path_clean_up(const char *path)
 {
-  static char result[256];
+  static char result[MAX_PATH];
 
   const char *p1 = path;
   char *p2 = result;
 
   int saw_slash = 0, saw_slash_dot = 0, saw_slash_dot_dot = 0;
 
-  if (*p1 != '/')
+  if (!IS_ABSOLUTE (p1))
   {
     get_current_working_directory();
     strcpy(result, cwd);
@@ -215,11 +353,11 @@ static char *path_clean_up(const char *p
      * Two leading slashes are allowed, having an OS implementation-defined meaning.
      * See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
      */
-    if (!saw_slash || *p1 != '/' || (p1 == path + 1 && p1[1] != '/'))
+    if (!saw_slash || !IS_SLASH (*p1) || (p1 == path + 1 && !IS_SLASH (p1[1])))
       *p2++ = *p1;
-    if (saw_slash_dot && (*p1 == '/'))
+    if (saw_slash_dot && IS_SLASH (*p1))
       p2 -= 2;
-    if (saw_slash_dot_dot && (*p1 == '/'))
+    if (saw_slash_dot_dot && IS_SLASH (*p1))
     {
       int cnt = 0;
       do
@@ -227,9 +365,9 @@ static char *path_clean_up(const char *p
 	if (--p2 < result)
 	{
 	  strcpy(result, path);
-	  return result;
+	  goto done;
 	}
-	if (*p2 == '/')
+	if (IS_SLASH (*p2))
 	  ++cnt;
       }
       while (cnt != 3);
@@ -237,10 +375,22 @@ static char *path_clean_up(const char *p
     }
     saw_slash_dot_dot = saw_slash_dot && (*p1 == '.');
     saw_slash_dot = saw_slash && (*p1 == '.');
-    saw_slash = (*p1 == '/');
+    saw_slash = IS_SLASH (*p1);
   }
   while (*p1++);
 
+ done:
+#ifdef __MINGW32__
+  /* Mixed forward- and back-slashes look ugly, so convert everything
+     to forward slashes.  */
+  p2 = result;
+  while (*p2)
+  {
+    if (*p2 == '\\')
+      *p2 = '/';
+    p2++;
+  }
+#endif
   return result;
 }
 
@@ -294,17 +444,18 @@ int path_search(int indent, const char *
   {
     int next;
     int path_index = 0;
+    int ext_index = 0;
     do
     {
       next = show_all;
-      result = find_command_in_path(cmd, path_list, &path_index);
+      result = find_command_in_path(cmd, path_list, &path_index, pathext, &ext_index);
       if (result)
       {
 	const char *full_path = path_clean_up(result);
-	int in_home = (show_tilde || skip_tilde) && !strncmp(full_path, home, homelen);
+	int in_home = (show_tilde || skip_tilde) && !fncmpn(full_path, home, homelen);
 	if (indent)
 	  fprintf(stdout, "\t");
-	if (!(skip_tilde && in_home) && show_dot && found_path_starts_with_dot && !strncmp(full_path, cwd, cwdlen))
+	if (!(skip_tilde && in_home) && show_dot && found_path_starts_with_dot && !fncmpn(full_path, cwd, cwdlen))
 	{
 	  full_path += cwdlen;
 	  fprintf(stdout, "./");
@@ -343,7 +494,7 @@ void process_alias(const char *str, int 
 
   while(*p == ' ' || *p == '\t')
     ++p;
-  if (!strncmp("alias", p, 5))
+  if (!fncmpn("alias", p, 5))
     p += 5;
   while(*p == ' ' || *p == '\t')
     ++p;
@@ -355,7 +506,7 @@ void process_alias(const char *str, int 
     char q = 0;
     char *cmd;
 
-    if (!*argv || len != strlen(*argv) || strncmp(*argv, &p[-len], len))
+    if (!*argv || len != strlen(*argv) || fncmpn(*argv, &p[-len], len))
       continue;
 
     fputs(str, stdout);
@@ -385,9 +536,14 @@ void process_alias(const char *str, int 
       cmd = (char *)xmalloc(len + 1);
       strncpy(cmd, &p[-len], len);
       cmd[len] = 0;
-      if (*argv && !strcmp(cmd, *argv))
+      if (*argv && !fncmp(cmd, *argv))
         *argv = NULL;
-      if (read_functions && !strchr(cmd, '/'))
+      if (read_functions
+	  && !strchr(cmd, '/')
+#ifdef __MINGW32__
+	  && !strchr(cmd, '\\')
+#endif
+	  )
         found = func_search(1, cmd, functions, function_start_type);
       if (show_all || !found)
 	path_search(1, cmd, path_list);
@@ -423,8 +579,12 @@ enum opts {
 /* According to Tom Bates, <tom.bates@hp.com> */
 static uid_t const superuser = 65535;
 #else
+#ifdef __MINGW32__
+static uid_t const superuser = 500;
+#else
 static uid_t const superuser = 0;
 #endif
+#endif
 
 int main(int argc, char *argv[])
 {
@@ -515,7 +675,7 @@ int main(int argc, char *argv[])
     strncpy(home, h, sizeof(home));
     home[sizeof(home) - 1] = 0;
     homelen = strlen(home);
-    if (home[homelen - 1] != '/' && homelen < sizeof(home) - 1)
+    if (!IS_SLASH (home[homelen - 1]) && homelen < sizeof(home) - 1)
     {
       strcat(home, "/");
       ++homelen;
@@ -537,13 +697,34 @@ int main(int argc, char *argv[])
     return -1;
   }
 
+#ifdef __MINGW32__
+  /* On Windows, the current directory is always implicitly in
+     PATH.  */
+  {
+    char *p = (char *)xmalloc(strlen(path_list) + sizeof(".;"));
+
+    strcpy(p, ".;");
+    strcat(p, path_list);
+    /* Omit the final ';', since extract_colon_unit will return an
+       empty string in that case.  */
+    if (p[strlen(p) - 1] == PATH_SEP)
+      p[strlen(p) - 1] = '\0';
+    path_list = p;
+    pathext = getenv("PATHEXT");
+    if (!pathext || !*pathext)
+      pathext = ".COM;.EXE;.BAT;.CMD";
+  }
+#else
+  pathext = ":";
+#endif
+
   int function_start_type = 0;
   if (read_alias || read_functions)
   {
     char buf[1024];
     int processing_aliases = read_alias;
 
-    if (isatty(0))
+    if (ISATTY(0))
     {
       fprintf(stderr, "%s: %s: Warning: stdin is a tty.\n", progname,
           (read_functions ? read_alias ? "--read-functions, --read-alias, -i" : "--read-functions" : "--read-alias, -i"));
@@ -572,7 +753,7 @@ int main(int argc, char *argv[])
 	if (*p == ')' && p[-1] == '(' && p[-2] == ' ')
 	{
 	  looks_like_function_start = 1;
-	  function_start_has_declare = (strncmp("declare -", buf, 9) == 0);
+	  function_start_has_declare = (fncmpn("declare -", buf, 9) == 0);
 	}
 	// Add some zsh support here.
 	// zsh does output a pattern for `str' like
@@ -590,7 +771,7 @@ int main(int argc, char *argv[])
       if (processing_aliases && !looks_like_function_start)
       {
 	// bash version 2.0.5b can throw in lines like "declare -fx FUNCTION_NAME", eat them.
-	if (!strncmp("declare -", buf, 9))
+	if (!fncmpn("declare -", buf, 9))
 	  continue;
 	if (alias_count == max_alias_count)
 	{
@@ -661,12 +842,30 @@ int main(int argc, char *argv[])
     if (!*argv)
       continue;
 
-    if (read_functions && !strchr(*argv, '/'))
+    if (read_functions
+	&& !strchr(*argv, '/')
+#ifdef __MINGW32__
+	&& !strchr(*argv, '\\')
+#endif
+	)
       found_something = func_search(0, *argv, functions, function_start_type);
 
     if ((show_all || !found_something) && !path_search(0, *argv, path_list) && !found_something)
     {
-      print_fail(absolute_path_given ? strrchr(*argv, '/') + 1 : *argv, absolute_path_given ? abs_path : path_list);
+      char *arg = *argv;
+
+      if (absolute_path_given)
+	{
+	  arg = strrchr(*argv, '/');
+#ifdef __MINGW32__
+	  if (!arg || strrchr(*argv, '\\') > arg)
+	    arg = strrchr(*argv, '\\');
+	  if (!arg && (*argv)[0] && (*argv)[1] == ':')
+	    arg = *argv + 2;
+#endif
+	  arg++;
+	}
+      print_fail(arg, absolute_path_given ? abs_path : path_list);
       ++fail_count;
     }
   }
