2008-09-15  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* which.c (main): Initialize progname with argv[0] before calling
	CANONICALIZE_PATH and remove old initilization.
	(make_posix_path_from_dos_path): Ignore ENOSYS.  ENOSYS means that
	the used OS do not implement the "Get Volume Information" function.


2008-08-30  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* which.c: Use FILENAME_MAX instead of hardcoded value (256) to define
	size of cwd[].
	Include <errno.h>.
	[__DJGPP__, __DJGPP_MINOR__]: For djdev204 use realpath to canonicalize
	the path, but for djdev203 use _fixpath for this purpose.
	(get_current_working_directory): Use CANONICALIZE_PATH to call getcwd().

	* which.texinfo: Fix it.


2008-08-29  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* getopt.c (_getopt_internal): Set explicit braces to avoid ambiguous
	'else'.
	* which.c (main): Set function_start_has_declare to a sane default.


2008-08-28  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* which.c: New macro CANONICALIZE_PATH.  For DJGPP expands to
	make_posix_path_from_dos_path, for all others it is empty.
	(make_posix_path_from_dos_path): New DJGPP specific function.
	Transform the paths in $PATH from DOS-style to POSIX-style.
	(get_current_working_directory): Use CANONICALIZE_PATH to call getenv().
	(main) [__DJGPP__]:  Use CANONICALIZE_PATH to call getenv().
	(find_command_in_path) [__DJGPP__]: Check also for program names with
	known DOS extensions.


2008-08-27  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* which.c [__DJGPP__]: Include <string.h>.
	(make_dos_extensions_list): New DJGPP specific function. Make an array
	with all DOS extensions to be recognized.  At least the ones known by
	the DJGPP port of bash 2.05b will be always be recognized.
	(print_usage) [__DJGPP__]: Print the recognized DOS extensions.
	(main) [__DJGPP__]: Call make_dos_extensions_list.






diff -aprNU5 which-2.20.orig/getopt.c which-2.20/getopt.c
--- which-2.20.orig/getopt.c	2007-05-25 21:13:24 +0000
+++ which-2.20/getopt.c	2008-09-15 21:37:32 +0000
@@ -700,20 +700,22 @@ _getopt_internal (argc, argv, optstring,
 	      if (pfound->has_arg)
 		optarg = nameend + 1;
 	      else
 		{
 		  if (opterr)
+		  {
 		   if (argv[optind - 1][1] == '-')
 		    /* --option */
 		    fprintf (stderr,
 		     _("%s: option `--%s' doesn't allow an argument\n"),
 		     argv[0], pfound->name);
 		   else
 		    /* +option or -option */
 		    fprintf (stderr,
 		     _("%s: option `%c%s' doesn't allow an argument\n"),
 		     argv[0], argv[optind - 1][0], pfound->name);
+		  }
 
 		  nextchar += strlen (nextchar);
 
 		  optopt = pfound->val;
 		  return '?';
diff -aprNU5 which-2.20.orig/which.c which-2.20/which.c
--- which-2.20.orig/which.c	2008-01-18 18:07:02 +0000
+++ which-2.20/which.c	2008-09-15 22:07:36 +0000
@@ -21,14 +21,37 @@
 #include <ctype.h>
 #include "getopt.h"
 #include "tilde/tilde.h"
 #include "bash.h"
 
+#ifdef __DJGPP__
+# include <errno.h>
+# include <string.h>
+#endif
+
+#ifdef __DJGPP__
+# if __DJGPP_MINOR__ < 4
+#  undef  realpath
+#  define realpath _fixpath
+# endif
+# define CANONICALIZE_PATH(p)  make_posix_path_from_dos_path((p))
+#else
+# define CANONICALIZE_PATH(p)  (p)
+#endif
+
+#ifdef __DJGPP__
+static char **exec_extension;
+#endif
+
 static const char *progname;
 
 static void print_usage(FILE *out)
 {
+#ifdef __DJGPP__
+  int i;
+#endif
+
   fprintf(out, "Usage: %s [options] [--] COMMAND [...]\n", progname);
   fprintf(out, "Write the full path of COMMAND(s) to standard output.\n\n");
   fprintf(out, "  --version, -[vV] Print version and exit successfully.\n");
   fprintf(out, "  --help,          Print this help and exit successfully.\n");
   fprintf(out, "  --skip-dot       Skip directories in PATH that start with a dot.\n");
@@ -39,10 +62,22 @@ static void print_usage(FILE *out)
   fprintf(out, "  --all, -a        Print all matches in PATH, not just the first\n");
   fprintf(out, "  --read-alias, -i Read list of aliases from stdin.\n");
   fprintf(out, "  --skip-alias     Ignore option --read-alias; don't read stdin.\n");
   fprintf(out, "  --read-functions Read shell functions from stdin.\n");
   fprintf(out, "  --skip-functions Ignore option --read-functions; don't read stdin.\n\n");
+#ifdef __DJGPP__
+  fprintf(out, "\n"
+               "This DJGPP port of which in addition to searching for programname,\n"
+               "will also search for\n\n");
+  for (i = 0; exec_extension[i]; i++)
+    fprintf(out, "   programname%s\n", exec_extension[i]);
+  fprintf(out, "\n"
+               "Set the WHICH environment variable to add extra extensions:\n"
+               "\n"
+               "   SET WHICH=.pl .cmd\n"
+               "\n");
+#endif
   fprintf(out, "Recommended use is to write the output of (alias; declare -f) to standard\n");
   fprintf(out, "input, so that which can show aliases and shell functions. See which(1) for\n");
   fprintf(out, "examples.\n\n");
   fprintf(out, "If the options --read-alias and/or --read-functions are specified then the\n");
   fprintf(out, "output can be a full alias or function definition, optionally followed by\n");
@@ -76,10 +111,14 @@ static int skip_functions = 0, read_func
 
 static char *find_command_in_path(const char *name, const char *path_list, int *path_index)
 {
   char *found = NULL, *full_path;
   int status, name_len;
+#ifdef DJGPP
+  int i;
+  size_t full_path_len;
+#endif
 
   name_len = strlen(name);
 
   if (!absolute_program(name))
     absolute_path_given = 0;
@@ -154,31 +193,117 @@ static char *find_command_in_path(const 
     {
       found = full_path;
       break;
     }
 
+#ifdef DJGPP
+    /*
+     *  This searches through a list of alternate versions of name with
+     *  various extensions (.exe, .com, .bat, .btm.) added.
+     */
+    full_path_len = strlen(full_path);
+    for (i = 0; exec_extension[i]; i++)
+    {
+      /*
+       *  Realloc space for the path + extension.
+       *  Do this every time to account for varying length extensions.
+       */
+      full_path = xrealloc(full_path, 1 + strlen(exec_extension[i]) + strlen(full_path));
+      strcpy(full_path + full_path_len, exec_extension[i]);
+
+      status = file_status(full_path);
+
+      if ((status & FS_EXISTS) && (status & FS_EXECABLE))
+        return full_path;
+    }
+#endif
+
     free(full_path);
   }
 
   return (found);
 }
 
-static char cwd[256];
+#ifdef __DJGPP__
+static char *make_posix_path_from_dos_path(char *in_path)
+{
+  /*
+   *  Transform a path from DOS-style syntax e.g.: X:\foo\bar;z:\bar\foo
+   *  to POSIX-style syntax e.g.: /dec/c/foo/bar:/dev/d/bar/foo
+   *  The DOS-style path will be passed to realpath() to solve for symlinks
+   *  and other issues and then drive letter and colon combinations like
+   *  "X:" will be translated to "/dev/x" and semicolons will be translated
+   *  to colons as path separator character.
+   */
+
+  char *dos_path, *posix_path;
+  size_t posix_path_len;
+
+
+  posix_path_len = 1;  //  For the terminating zero.
+  posix_path = xmalloc(posix_path_len);
+  *posix_path = '\0';
+
+  if ((dos_path = strtok(in_path, ";")) == NULL)
+    dos_path = in_path;
+  do {
+    char canonicalized_path[FILENAME_MAX];
+
+    errno = 0;
+    realpath(dos_path, canonicalized_path);
+    if (errno && errno != ENOSYS)
+    {
+      /*
+       *  realpath/_fixpath calls _use_lfn that sets errno = ENOSYS
+       *  iff the OS used does not implement INT 21h function 0x71a0.
+       *  This is always the case for all plain DOS systems.
+       *  The setting of ENOSYS does not imply that the canonicalization
+       *  of the passed path went wrong and must be ignored.
+       */
+      fprintf(stderr, "%s: Can not canonicalize DOS path \"%s\"", progname, dos_path);
+      exit(-1);
+    }
+    posix_path_len += sizeof("/dev/") - 1 + strlen(canonicalized_path);
+    posix_path = xrealloc(posix_path, posix_path_len);
+    canonicalized_path[1] = '\0';  //  Separate the drive letter.
+    strcat(posix_path, "/dev/");
+    strcat(posix_path, canonicalized_path);
+    strcat(posix_path, canonicalized_path + 2);
+    strcat(posix_path, ":");
+  } while ((dos_path = strtok(NULL, ";")));
+  posix_path[posix_path_len - 2] = '\0';
+
+  return posix_path;
+}
+#endif
+
+static char cwd[FILENAME_MAX];
 static size_t cwdlen;
 
 static void get_current_working_directory(void)
 {
   if (cwdlen)
     return;
 
   if (!getcwd(cwd, sizeof(cwd)))
   {
-    const char *pwd = getenv("PWD");
+    const char *pwd = CANONICALIZE_PATH(getenv("PWD"));
     if (pwd && strlen(pwd) < sizeof(cwd))
       strcpy(cwd, pwd);
   }
 
+#ifdef __DJGPP__
+  {
+    char *dst, *src;
+
+    dst = cwd;
+    src = CANONICALIZE_PATH(cwd);
+    while ((*dst++ = *src++))
+      ;
+  }
+#endif
+
   if (*cwd != '/')
   {
     fprintf(stderr, "Can't get current working directory\n");
     exit(-1);
   }
@@ -424,13 +549,90 @@ enum opts {
 static uid_t const superuser = 65535;
 #else
 static uid_t const superuser = 0;
 #endif
 
+#ifdef __DJGPP__
+static void make_dos_extensions_list(void)
+{
+  /*
+   *  The array of the known DOS extensions is build up
+   *  with the same four extensions that the DJGPP port
+   *  of bash 2.05b recongnizes (exe, com, bat, btm) and
+   *  the extra extensions provided by the user via the
+   *  WHICH environment variable.
+   */
+
+  const char *known_exts[] = {
+    ".exe",
+    ".com",
+    ".bat",
+    ".btm"
+  };
+  char *env_exts = getenv("WHICH");
+  int i = sizeof(known_exts) / sizeof(known_exts[0]);
+
+
+  if (env_exts)
+  {
+    char *ext, *exts = strdup(env_exts);
+
+    if (!exts)
+    {
+      fprintf(stderr, "%s: Out of memory", progname);
+      exit(-1);
+    }
+
+    for (ext = strtok(exts, " ,;"); ext; ext = strtok(NULL, " ,;"))
+      i++;
+
+    free(exts);
+  }
+
+  exec_extension = xmalloc((i + 1) * sizeof(*exec_extension));
+  exec_extension[i] = NULL;
+  for (i = 0; i < sizeof(known_exts) / sizeof(known_exts[0]); i++)
+    if ((exec_extension[i] = strdup(known_exts[i])) == NULL)
+    {
+      fprintf(stderr, "%s: Out of memory", progname);
+      exit(-1);
+    }
+  if ((env_exts))
+  {
+    char *ext, *exts = strdup(env_exts);
+
+    if (!exts)
+    {
+      fprintf(stderr, "%s: Out of memory", progname);
+      exit(-1);
+    }
+
+    for (ext = strtok(exts, " ,;"); ext && exec_extension[i]; ext = strtok(NULL, " ,;"), i++)
+    {
+      char *extension;
+      size_t ext_len;
+
+      ext_len = strlen(ext) + 2;  // Just in case the leading dot is missed.
+      exec_extension[i] = xmalloc(ext_len * sizeof(*exec_extension[0]));
+      extension = exec_extension[i];
+
+      if (*ext != '.')
+      {
+        extension[0] = '.';
+        extension++;
+      }
+      strcpy(extension, ext);
+    }
+
+    free(exts);
+  }
+}
+#endif
+
 int main(int argc, char *argv[])
 {
-  const char *path_list = getenv("PATH");
+  const char *path_list = (progname = argv[0], CANONICALIZE_PATH(getenv("PATH")));
   int short_option, fail_count = 0;
   static int long_option;
   struct option longopts[] = {
     {"help", 0, &long_option, opt_help},
     {"version", 0, &long_option, opt_version},
@@ -445,11 +647,14 @@ int main(int argc, char *argv[])
     {"read-functions", 0, &long_option, opt_read_functions},
     {"skip-functions", 0, &long_option, opt_skip_functions},
     {NULL, 0, NULL, 0}
   };
 
-  progname = argv[0];
+#ifdef __DJGPP__
+  make_dos_extensions_list();
+#endif
+
   while ((short_option = getopt_long(argc, argv, "aivV", longopts, NULL)) != -1)
   {
     switch (short_option)
     {
       case 0:
@@ -550,11 +755,11 @@ int main(int argc, char *argv[])
     }
 
     while (fgets(buf, sizeof(buf), stdin))
     {
       int looks_like_function_start = 0;
-      int function_start_has_declare;
+      int function_start_has_declare = 0;
       if (read_functions)
       {
 	// bash version 2.0.5a and older output a pattern for `str' like
 	// declare -fx FUNCTION_NAME ()
 	// {
diff -aprNU5 which-2.20.orig/which.texinfo which-2.20/which.texinfo
--- which-2.20.orig/which.texinfo	2008-01-16 17:51:56 +0000
+++ which-2.20/which.texinfo	2008-09-15 21:37:32 +0000
@@ -64,22 +64,24 @@ Carlo Wood, Run on IRC <carlo@@alinoe.co
 RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
 Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
 
 @end titlepage
 
-@ifinfo
 @node Top, Which Program, (dir), (dir)
+@ifinfo
 @top @command{which}: Show the full path of commands
+@end ifinfo
 
+@ifnottex
 The @command{which} program
 @c !BEGIN NAME
 shows the full path of (shell) commands.
 @c !END NAME
 
 @noindent
 This file documents @command{which} version @value{VERSION}, updated @value{UPDATED}.
-@end ifinfo
+@end ifnottex
 
 @menu
 * Which Program::               The @command{which} Program
 * Invoking Which::              How to invoke @command{which}
 * Option Summary::              Overview of commandline options
