Make win32 builds always do SetEnvironmentVariable() when doing putenv().
authorMagnus Hagander <[email protected]>
Wed, 21 Jan 2009 10:30:02 +0000 (10:30 +0000)
committerMagnus Hagander <[email protected]>
Wed, 21 Jan 2009 10:30:02 +0000 (10:30 +0000)
Also, if linked against other versions than the default MSVCRT library
(for example the MSVC build which links against MSVCRT80), also update
the cache in the default MSVCRT at the same time.

This should fix the issues with setting LC_MESSAGES on the MSVC build.

Original patch from Hiroshi Inoue and Hiroshi Saito, much rewritten
by me.

configure
configure.in
src/backend/utils/adt/pg_locale.c
src/include/port/win32.h
src/port/win32env.c [new file with mode: 0644]
src/tools/msvc/Mkvcbuild.pm

index 38f24ffa2e22b24c266cae136183e8c8a6aa8e3a..0c25c09912bef83bb7ab9d12f387b7ba0a3ff866 100755 (executable)
--- a/configure
+++ b/configure
@@ -17919,6 +17919,12 @@ case " $LIBOBJS " in
  ;;
 esac
 
+case " $LIBOBJS " in
+  *" win32env.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS win32env.$ac_objext"
+ ;;
+esac
+
 case " $LIBOBJS " in
   *" win32error.$ac_objext "* ) ;;
   *) LIBOBJS="$LIBOBJS win32error.$ac_objext"
index 7c9aa029960578b93f892aa1de7863960d963c7d..736953ac87cfc39a5733cff667ee1e4711794e35 100644 (file)
@@ -1274,6 +1274,7 @@ AC_REPLACE_FUNCS(gettimeofday)
 AC_LIBOBJ(kill)
 AC_LIBOBJ(open)
 AC_LIBOBJ(rand)
+AC_LIBOBJ(win32env)
 AC_LIBOBJ(win32error)
 AC_DEFINE([HAVE_SYMLINK], 1,
           [Define to 1 if you have the `symlink' function.])
index b8f553fbf74f74d98dcddd1943d0898eb3365f23..199d83553a9c656158f9730fa57f62a5c18abb17 100644 (file)
@@ -55,6 +55,9 @@
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 
+#ifdef WIN32
+#include <shlwapi.h>
+#endif
 
 #define                MAX_L10N_DATA           80
 
@@ -89,6 +92,10 @@ static char lc_monetary_envbuf[LC_ENV_BUFSIZE];
 static char lc_numeric_envbuf[LC_ENV_BUFSIZE];
 static char lc_time_envbuf[LC_ENV_BUFSIZE];
 
+#ifdef WIN32
+static char *IsoLocaleName(const char *); /* MSVC specific */
+#endif
+
 
 /*
  * pg_perm_setlocale
@@ -148,8 +155,13 @@ pg_perm_setlocale(int category, const char *locale)
                case LC_MESSAGES:
                        envvar = "LC_MESSAGES";
                        envbuf = lc_messages_envbuf;
+#ifdef WIN32
+                       result = IsoLocaleName(locale);
+                       if (result == NULL)
+                               result = locale;
+#endif /* WIN32 */
                        break;
-#endif
+#endif /* LC_MESSAGES */
                case LC_MONETARY:
                        envvar = "LC_MONETARY";
                        envbuf = lc_monetary_envbuf;
@@ -166,25 +178,13 @@ pg_perm_setlocale(int category, const char *locale)
                        elog(FATAL, "unrecognized LC category: %d", category);
                        envvar = NULL;          /* keep compiler quiet */
                        envbuf = NULL;
-                       break;
+                       return NULL;
        }
 
        snprintf(envbuf, LC_ENV_BUFSIZE - 1, "%s=%s", envvar, result);
 
-#ifndef WIN32
        if (putenv(envbuf))
                return NULL;
-#else
-
-       /*
-        * On Windows, we need to modify both the process environment and the
-        * cached version in msvcrt
-        */
-       if (!SetEnvironmentVariable(envvar, result))
-               return NULL;
-       if (_putenv(envbuf))
-               return NULL;
-#endif
 
        return result;
 }
@@ -599,3 +599,53 @@ cache_locale_time(void)
 
        CurrentLCTimeValid = true;
 }
+
+
+#ifdef WIN32
+/*
+ *     Convert Windows locale name to the ISO formatted one
+ *     if possible.
+ *
+ *     This function returns NULL if conversion is impossible,
+ *     otherwise returns the pointer to a static area which
+ *     contains the iso formatted locale name.
+ */
+static
+char *IsoLocaleName(const char *winlocname)
+{
+#if (_MSC_VER >= 1400) /* VC8.0 or later */
+       static char     iso_lc_messages[32];
+       _locale_t       loct = NULL;
+
+       if (pg_strcasecmp("c", winlocname) == 0 ||
+               pg_strcasecmp("posix", winlocname) == 0)
+       {
+               strcpy(iso_lc_messages, "C");
+               return iso_lc_messages;
+       }
+
+       loct = _create_locale(LC_CTYPE, winlocname);
+       if (loct != NULL)
+       {
+               char    isolang[32], isocrty[32];
+               LCID    lcid;
+
+               lcid = loct->locinfo->lc_handle[LC_CTYPE];
+               if (lcid == 0)
+                       lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+               _free_locale(loct);
+
+               if (!GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, isolang, sizeof(isolang)))
+                       return NULL;
+               if (!GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, isocrty, sizeof(isocrty)))'
+                       return NULL;
+               snprintf(iso_lc_messages, sizeof(iso_lc_messages) - 1, "%s_%s", isolang, isocrty);
+               return iso_lc_messages;
+       }
+       return NULL;
+#else
+       return NULL; /* Not supported on this version of msvc/mingw */
+#endif /* _MSC_VER >= 1400 */
+}
+#endif /* WIN32 */
+
index 256b71fbdc05c74758ab169e16596410ab44d80b..d4ef39848400040f377440beca4a1413f5fe9742 100644 (file)
@@ -291,6 +291,11 @@ extern int pgwin32_is_service(void);
 /* in port/win32error.c */
 extern void _dosmaperr(unsigned long);
 
+/* in port/win32env.c */
+extern int pgwin32_putenv(const char *);
+extern void pgwin32_unsetenv(const char *);
+#define putenv(x) pgwin32_putenv(x)
+#define unsetenv(x) pgwin32_unsetenv(x)
 
 /* Things that exist in MingW headers, but need to be added to MSVC */
 #ifdef WIN32_ONLY_COMPILER
diff --git a/src/port/win32env.c b/src/port/win32env.c
new file mode 100644 (file)
index 0000000..9e8565a
--- /dev/null
@@ -0,0 +1,93 @@
+/*-------------------------------------------------------------------------
+ *
+ * win32env.c
+ *    putenv() and unsetenv() for win32, that updates both process
+ *    environment and the cached versions in (potentially multiple)
+ *    MSVCRT.
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       $PostgreSQL$
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+int
+pgwin32_putenv(const char *envval)
+{
+       char   *envcpy;
+       char   *cp;
+
+       /*
+        * Each version of MSVCRT has its own _putenv() call in the runtime
+        * library.
+        *
+        * If we're in VC 7.0 or later (means != mingw), update in
+        * the 6.0 MSVCRT.DLL environment as well, to work with third party
+        * libraries linked against it (such as gnuwin32 libraries).
+        */
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+       typedef int             (_cdecl *PUTENVPROC)(const char *);
+       HMODULE                         hmodule;
+       static PUTENVPROC       putenvFunc = NULL;
+       int                                     ret;
+
+       if (putenvFunc == NULL)
+       {
+               hmodule = GetModuleHandle("msvcrt");
+               if (hmodule == NULL)
+                       return 1;
+               putenvFunc = (PUTENVPROC)GetProcAddress(hmodule, "_putenv");
+               if (putenvFunc == NULL)
+                       return 1;
+       }
+       ret = putenvFunc(envval);
+       if (ret != 0)
+               return ret;
+#endif /* _MSC_VER >= 1300 */
+
+
+       /*
+        * Update the process environment - to make modifications visible
+        * to child processes.
+        *
+        * Need a copy of the string so we can modify it.
+        */
+       envcpy = strdup(envval);
+       cp = strchr(envcpy, '=');
+       if (cp == NULL)
+               return -1;
+       *cp = '\0';
+       cp++;
+       if (strlen(cp) == 0)
+               cp = NULL;
+       if (!SetEnvironmentVariable(envcpy, cp))
+       {
+               free(envcpy);
+               return -1;
+       }
+       free(envcpy);
+
+       /* Finally, update our "own" cache */
+       return _putenv(envval);
+}
+
+void
+pgwin32_unsetenv(const char *name)
+{
+       char   *envbuf;
+
+       envbuf = (char *) malloc(strlen(name)+2);
+       if (!envbuf)
+               return;
+
+       sprintf(envbuf, "%s=", name);
+       pgwin32_putenv(envbuf);
+       free(envbuf);
+}
+
index be81395715394e92ef1caddaa7a2d3314a9fb933..86082c3df41ba36d7751a7f2ba44bd005f8d8c0d 100644 (file)
@@ -44,10 +44,10 @@ sub mkvcbuild
 
     our @pgportfiles = qw(
       chklocale.c crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
-      unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
+      getaddrinfo.c gettimeofday.c kill.c open.c rand.c
       snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
       pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c
-      getopt.c getopt_long.c dirent.c rint.c win32error.c);
+      getopt.c getopt_long.c dirent.c rint.c win32env.c win32error.c);
 
     $libpgport = $solution->AddProject('libpgport','lib','misc');
     $libpgport->AddDefine('FRONTEND');