Merge branch 'js/mingw-utf8-env'
authorJunio C Hamano <gitster@pobox.com>
Tue, 13 Nov 2018 13:37:21 +0000 (22:37 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 13 Nov 2018 13:37:21 +0000 (22:37 +0900)
Windows fix.

* js/mingw-utf8-env:
mingw: reencode environment variables on the fly (UTF-16 <-> UTF-8)
t7800: fix quoting

1  2 
compat/mingw.c
compat/mingw.h
t/t7800-difftool.sh
diff --cc compat/mingw.c
index e8e538a2e048a17ff7e07c411cd7b51021c90a4a,c1de85f11893bf5ac71b313aa4b2ad21370f5de5..d2f4fabb44b898ea6049b8b3fecadc26ddbb6253
@@@ -1184,54 -1085,78 +1216,99 @@@ static int wenvcmp(const void *a, cons
   */
  static wchar_t *make_environment_block(char **deltaenv)
  {
-       wchar_t *wenvblk = NULL;
-       char **tmpenv;
-       int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
+       wchar_t *wenv = GetEnvironmentStringsW(), *wdeltaenv, *result, *p;
+       size_t wlen, s, delta_size, size;
  
-       while (deltaenv && deltaenv[i])
-               i++;
+       wchar_t **array = NULL;
+       size_t alloc = 0, nr = 0, i;
  
-       /* copy the environment, leaving space for changes */
-       ALLOC_ARRAY(tmpenv, size + i);
-       memcpy(tmpenv, environ, size * sizeof(char*));
+       size = 1; /* for extra NUL at the end */
+       /* If there is no deltaenv to apply, simply return a copy. */
+       if (!deltaenv || !*deltaenv) {
+               for (p = wenv; p && *p; ) {
+                       size_t s = wcslen(p) + 1;
+                       size += s;
+                       p += s;
+               }
  
-       /* merge supplied environment changes into the temporary environment */
-       for (i = 0; deltaenv && deltaenv[i]; i++)
-               size = do_putenv(tmpenv, deltaenv[i], size, 0);
+               ALLOC_ARRAY(result, size);
+               memcpy(result, wenv, size * sizeof(*wenv));
+               FreeEnvironmentStringsW(wenv);
+               return result;
+       }
  
-       /* create environment block from temporary environment */
-       for (i = 0; tmpenv[i]; i++) {
-               size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
-               ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
-               wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
+       /*
+        * If there is a deltaenv, let's accumulate all keys into `array`,
+        * sort them using the stable git_qsort() and then copy, skipping
+        * duplicate keys
+        */
+       for (p = wenv; p && *p; ) {
+               ALLOC_GROW(array, nr + 1, alloc);
+               s = wcslen(p) + 1;
+               array[nr++] = p;
+               p += s;
+               size += s;
        }
-       /* add final \0 terminator */
-       wenvblk[wenvpos] = 0;
-       free(tmpenv);
-       return wenvblk;
+       /* (over-)assess size needed for wchar version of deltaenv */
+       for (delta_size = 0, i = 0; deltaenv[i]; i++)
+               delta_size += strlen(deltaenv[i]) * 2 + 1;
+       ALLOC_ARRAY(wdeltaenv, delta_size);
+       /* convert the deltaenv, appending to array */
+       for (i = 0, p = wdeltaenv; deltaenv[i]; i++) {
+               ALLOC_GROW(array, nr + 1, alloc);
+               wlen = xutftowcs(p, deltaenv[i], wdeltaenv + delta_size - p);
+               array[nr++] = p;
+               p += wlen + 1;
+       }
+       git_qsort(array, nr, sizeof(*array), wenvcmp);
+       ALLOC_ARRAY(result, size + delta_size);
+       for (p = result, i = 0; i < nr; i++) {
+               /* Skip any duplicate keys; last one wins */
+               while (i + 1 < nr && !wenvcmp(array + i, array + i + 1))
+                      i++;
+               /* Skip "to delete" entry */
+               if (!wcschr(array[i], L'='))
+                       continue;
+               size = wcslen(array[i]) + 1;
+               memcpy(p, array[i], size * sizeof(*p));
+               p += size;
+       }
+       *p = L'\0';
+       free(array);
+       free(wdeltaenv);
+       FreeEnvironmentStringsW(wenv);
+       return result;
  }
  
 +static void do_unset_environment_variables(void)
 +{
 +      static int done;
 +      char *p = unset_environment_variables;
 +
 +      if (done || !p)
 +              return;
 +      done = 1;
 +
 +      for (;;) {
 +              char *comma = strchr(p, ',');
 +
 +              if (comma)
 +                      *comma = '\0';
 +              unsetenv(p);
 +              if (!comma)
 +                      break;
 +              p = comma + 1;
 +      }
 +}
 +
  struct pinfo_t {
        struct pinfo_t *next;
        pid_t pid;
diff --cc compat/mingw.h
Simple merge
Simple merge