From f0632550eeef8a2d4f773bf95abfc74ea51c4096 Mon Sep 17 00:00:00 2001
From: Ray Donnelly <mingw.android@gmail.com>
Date: Sun, 10 Apr 2016 21:47:41 +0100
Subject: [PATCH 20/N] environ.cc: New facility/environment variable
 MSYS2_ENV_CONV_EXCL

Works very much like MSYS2_ARG_CONV_EXCL. In fact it uses the same
function, arg_heuristic_with_exclusions (). Also refactors parsing
the env. variables to use new function, string_split_delimited ().

The env. that is searched through is the merged (POSIX + Windows)
one. It remains to be seen if this should be made an option or not.

This feature was prompted because the R language (Windows exe) calls
bash to run configure.win, which then calls back into R to read its
config variables (LOCAL_SOFT) and when this happens, msys2-runtime
converts R_ARCH from "/x64" to an absolute Windows path and appends
it to another absolute path, R_HOME, forming an invalid path.
---
 winsup/cygwin/environ.cc                 | 34 +++++++++++++++++-------
 winsup/cygwin/local_includes/miscfuncs.h |  2 ++
 winsup/cygwin/miscfuncs.cc               | 20 ++++++++++++++
 winsup/cygwin/path.cc                    |  1 -
 winsup/cygwin/spawn.cc                   | 12 ++-------
 5 files changed, 48 insertions(+), 21 deletions(-)

diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 1175313..a9cce96 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -1173,6 +1173,10 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc,
 
   int tl = 0;
   char **pass_dstp;
+#ifdef __MSYS__
+  char *msys2_env_conv_excl_env = NULL;
+  size_t msys2_env_conv_excl_count = 0;
+#endif
   char **pass_env = (char **) alloca (sizeof (char *)
 				      * (n + winnum + SPENVS_SIZE + 1));
   /* Iterate over input list, generating a new environment list and refreshing
@@ -1181,16 +1185,25 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc,
     {
       bool calc_tl = !no_envblock;
 #ifdef __MSYS__
-      /* Don't pass timezone environment to non-msys applications */
-      if (!keep_posix && ascii_strncasematch(*srcp, "TZ=", 3))
+      if (!keep_posix)
         {
-          const char *v = *srcp + 3;
-          if (*v == ':')
-            goto next1;
-          for (; *v; v++)
-            if (!isalpha(*v) && !isdigit(*v) &&
-                *v != '-' && *v != '+' && *v != ':')
-              goto next1;
+          /* Don't pass timezone environment to non-msys applications */
+          if (ascii_strncasematch(*srcp, "TZ=", 3))
+            {
+              const char *v = *srcp + 3;
+              if (*v == ':')
+                goto next1;
+              for (; *v; v++)
+                if (!isalpha(*v) && !isdigit(*v) &&
+                    *v != '-' && *v != '+' && *v != ':')
+                  goto next1;
+            }
+          else if (ascii_strncasematch(*srcp, "MSYS2_ENV_CONV_EXCL=", 20))
+            {
+              msys2_env_conv_excl_env = (char*)alloca (strlen(&(*srcp)[20])+1);
+              strcpy (msys2_env_conv_excl_env, &(*srcp)[20]);
+              msys2_env_conv_excl_count = string_split_delimited (msys2_env_conv_excl_env, ';');
+            }
         }
 #endif
       /* Look for entries that require special attention */
@@ -1315,7 +1328,8 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc,
 	    }
 #ifdef __MSYS__
 	  else if (!keep_posix) {
-	    char *win_arg = arg_heuristic(*srcp);
+	    char *win_arg = arg_heuristic_with_exclusions
+		   (*srcp, msys2_env_conv_excl_env, msys2_env_conv_excl_count);
 	    debug_printf("WIN32_PATH is %s", win_arg);
 	    p = cstrdup1(win_arg);
 	    if (win_arg != *srcp)
diff --git a/winsup/cygwin/local_includes/miscfuncs.h b/winsup/cygwin/local_includes/miscfuncs.h
index d52deba..c4dbe02 100644
--- a/winsup/cygwin/local_includes/miscfuncs.h
+++ b/winsup/cygwin/local_includes/miscfuncs.h
@@ -81,6 +81,8 @@ void backslashify (const char *, char *, bool);
 void slashify (const char *, char *, bool);
 #define isslash(c) ((c) == '/')
 
+size_t string_split_delimited (char * string, char delimiter);
+
 extern void transform_chars (PWCHAR, PWCHAR);
 extern inline void
 transform_chars (PUNICODE_STRING upath, USHORT start_idx)
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index 4220f62..5446654 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -311,6 +311,26 @@ NT_readline::gets ()
     }
 }
 
+/* Searches through string for delimiter replacing each instance with '\0'
+   and returning the number of such delimited substrings. This function
+   Will return 0 for the NULL string and at least 1 otherwise. */
+
+size_t
+string_split_delimited (char * string, char delimiter)
+{
+  if ( string == NULL )
+      return 0;
+  size_t count = 1;
+  string = strchr ( string, delimiter );
+  while (string)
+    {
+      *string = '\0';
+      ++count;
+      string = strchr ( string + 1, delimiter );
+    }
+  return count;
+}
+
 /* Signal the thread name to any attached debugger
 
    (See "How to: Set a Thread Name in Native Code"
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index ee5a27b..b6d8397 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -4050,7 +4050,6 @@ arg_heuristic_with_exclusions (char const * const arg, char const * exclusions,
     return arg_result;
   }
 
-  debug_printf("Input value: (%s)", arg);
   for (size_t excl = 0; excl < exclusions_count; ++excl)
     {
       /* Since we've got regex linked we should maybe switch to that, but
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index d7affaa..5b3cbeb 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -293,8 +293,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
   int res = -1;
 
   /* Environment variable MSYS2_ARG_CONV_EXCL contains a list
-     of ';' separated argument prefixes to pass un-modified..
-     It isn't applied to env. variables; only spawn arguments.
+     of ';' separated argument prefixes to pass un-modified.
      A value of * means don't convert any arguments. */
   char* msys2_arg_conv_excl_env = getenv("MSYS2_ARG_CONV_EXCL");
   char* msys2_arg_conv_excl = NULL;
@@ -303,14 +302,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
     {
       msys2_arg_conv_excl = (char*)alloca (strlen(msys2_arg_conv_excl_env)+1);
       strcpy (msys2_arg_conv_excl, msys2_arg_conv_excl_env);
-      msys2_arg_conv_excl_count = 1;
-      msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl, ';' );
-      while (msys2_arg_conv_excl_env)
-        {
-          *msys2_arg_conv_excl_env = '\0';
-          ++msys2_arg_conv_excl_count;
-          msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl_env + 1, ';' );
-        }
+      msys2_arg_conv_excl_count = string_split_delimited (msys2_arg_conv_excl, ';');
     }
 
   /* Check if we have been called from exec{lv}p or spawn{lv}p and mask
