diff --git a/configure b/configure index 9084db3401..a5ff285a8d 100755 --- a/configure +++ b/configure @@ -21090,6 +21090,12 @@ esac ;; esac + case " $LIBOBJS " in + *" win32setlocale.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS win32setlocale.$ac_objext" + ;; +esac + cat >>confdefs.h <<\_ACEOF #define HAVE_SYMLINK 1 diff --git a/configure.in b/configure.in index d8b7c9edb8..126f841ea6 100644 --- a/configure.in +++ b/configure.in @@ -1374,6 +1374,7 @@ if test "$PORTNAME" = "win32"; then AC_LIBOBJ(open) AC_LIBOBJ(win32env) AC_LIBOBJ(win32error) + AC_LIBOBJ(win32setlocale) AC_DEFINE([HAVE_SYMLINK], 1, [Define to 1 if you have the `symlink' function.]) AC_CHECK_TYPES(MINIDUMP_TYPE, [pgac_minidump_type=yes], [pgac_minidump_type=no], [ diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile index cdf84c3b09..2b2ffb6207 100644 --- a/src/interfaces/ecpg/ecpglib/Makefile +++ b/src/interfaces/ecpg/ecpglib/Makefile @@ -26,7 +26,7 @@ LIBS := $(filter-out -lpgport, $(LIBS)) OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \ connect.o misc.o path.o pgstrcasecmp.o \ - $(filter snprintf.o strlcpy.o, $(LIBOBJS)) + $(filter snprintf.o strlcpy.o win32setlocale.o, $(LIBOBJS)) # thread.c is needed only for non-WIN32 implementation of path.c ifneq ($(PORTNAME), win32) @@ -57,7 +57,7 @@ include $(top_srcdir)/src/Makefile.shlib # necessarily use the same object files as the backend uses. Instead, # symlink the source files in here and build our own object file. -path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c: % : $(top_srcdir)/src/port/% +path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c win32setlocale.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . misc.o: misc.c $(top_builddir)/src/port/pg_config_paths.h @@ -74,6 +74,6 @@ uninstall: uninstall-lib clean distclean: clean-lib rm -f $(OBJS) - rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c + rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c win32setlocale.c maintainer-clean: distclean maintainer-clean-lib diff --git a/src/port/chklocale.c b/src/port/chklocale.c index cd911b84ce..e4f3dc99e0 100644 --- a/src/port/chklocale.c +++ b/src/port/chklocale.c @@ -356,109 +356,3 @@ pg_get_encoding_from_locale(const char *ctype, bool write_message) } #endif /* (HAVE_LANGINFO_H && CODESET) || WIN32 */ - -#ifdef WIN32 -/* - * Windows has a problem with locale names that have a dot in the country - * name. For example: - * - * "Chinese (Traditional)_Hong Kong S.A.R..950" - * - * For some reason, setlocale() doesn't accept that. Fortunately, Windows' - * setlocale() accepts various alternative names for such countries, so we - * provide a wrapper setlocale() function that maps the troublemaking locale - * names to accepted aliases. - */ - -#undef setlocale - -struct locale_map -{ - const char *locale_name_part; /* string in locale name to replace */ - const char *replacement; /* string to replace it with */ -}; - -static const struct locale_map locale_map_list[] = { - - /* - * "HKG" is listed here: - * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx - * (Country/Region Strings). - * - * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the - * above list, but seems to work anyway. - */ - { "Hong Kong S.A.R.", "HKG" }, - { "U.A.E.", "ARE" }, - - /* - * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't - * seem to recognize that. And Macau isn't listed in the table of - * accepted abbreviations linked above. Fortunately, "ZHM" seems to be - * accepted as an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm - * not sure where "ZHM" comes from, must be some legacy naming scheme. But - * hey, it works. - * - * Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale - * name, not just the country part. - * - * Some versions of Windows spell it "Macau", others "Macao". - */ - { "Chinese (Traditional)_Macau S.A.R..950", "ZHM" }, - { "Chinese_Macau S.A.R..950", "ZHM" }, - { "Chinese (Traditional)_Macao S.A.R..950", "ZHM" }, - { "Chinese_Macao S.A.R..950", "ZHM" } -}; - -char * -pgwin32_setlocale(int category, const char *locale) -{ - char *result; - char *alias; - int i; - - if (locale == NULL) - return setlocale(category, locale); - - /* Check if the locale name matches any of the problematic ones. */ - alias = NULL; - for (i = 0; i < lengthof(locale_map_list); i++) - { - const char *needle = locale_map_list[i].locale_name_part; - const char *replacement = locale_map_list[i].replacement; - char *match; - - match = strstr(locale, needle); - if (match != NULL) - { - /* Found a match. Replace the matched string. */ - int matchpos = match - locale; - int replacementlen = strlen(replacement); - char *rest = match + strlen(needle); - int restlen = strlen(rest); - - alias = malloc(matchpos + replacementlen + restlen + 1); - if (!alias) - return NULL; - - memcpy(&alias[0], &locale[0], matchpos); - memcpy(&alias[matchpos], replacement, replacementlen); - memcpy(&alias[matchpos + replacementlen], rest, restlen + 1); /* includes null terminator */ - - break; - } - } - - /* Call the real setlocale() function */ - if (alias) - { - result = setlocale(category, alias); - free(alias); - } - else - result = setlocale(category, locale); - - return result; -} - -#endif /* WIN32 */ diff --git a/src/port/win32setlocale.c b/src/port/win32setlocale.c new file mode 100644 index 0000000000..a301e769a7 --- /dev/null +++ b/src/port/win32setlocale.c @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------- + * + * win32setlocale.c + * Wrapper to work around bugs in Windows setlocale() implementation + * + * Copyright (c) 2011, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/win32setlocale.c + * + * + * Windows has a problem with locale names that have a dot in the country + * name. For example: + * + * "Chinese (Traditional)_Hong Kong S.A.R..950" + * + * For some reason, setlocale() doesn't accept that. Fortunately, Windows' + * setlocale() accepts various alternative names for such countries, so we + * provide a wrapper setlocale() function that maps the troublemaking locale + * names to accepted aliases. + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#undef setlocale + +struct locale_map +{ + const char *locale_name_part; /* string in locale name to replace */ + const char *replacement; /* string to replace it with */ +}; + +static const struct locale_map locale_map_list[] = { + + /* + * "HKG" is listed here: + * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx + * (Country/Region Strings). + * + * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the + * above list, but seems to work anyway. + */ + { "Hong Kong S.A.R.", "HKG" }, + { "U.A.E.", "ARE" }, + + /* + * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't + * seem to recognize that. And Macau isn't listed in the table of + * accepted abbreviations linked above. Fortunately, "ZHM" seems to be + * accepted as an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm + * not sure where "ZHM" comes from, must be some legacy naming scheme. But + * hey, it works. + * + * Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale + * name, not just the country part. + * + * Some versions of Windows spell it "Macau", others "Macao". + */ + { "Chinese (Traditional)_Macau S.A.R..950", "ZHM" }, + { "Chinese_Macau S.A.R..950", "ZHM" }, + { "Chinese (Traditional)_Macao S.A.R..950", "ZHM" }, + { "Chinese_Macao S.A.R..950", "ZHM" } +}; + +char * +pgwin32_setlocale(int category, const char *locale) +{ + char *result; + char *alias; + int i; + + if (locale == NULL) + return setlocale(category, locale); + + /* Check if the locale name matches any of the problematic ones. */ + alias = NULL; + for (i = 0; i < lengthof(locale_map_list); i++) + { + const char *needle = locale_map_list[i].locale_name_part; + const char *replacement = locale_map_list[i].replacement; + char *match; + + match = strstr(locale, needle); + if (match != NULL) + { + /* Found a match. Replace the matched string. */ + int matchpos = match - locale; + int replacementlen = strlen(replacement); + char *rest = match + strlen(needle); + int restlen = strlen(rest); + + alias = malloc(matchpos + replacementlen + restlen + 1); + if (!alias) + return NULL; + + memcpy(&alias[0], &locale[0], matchpos); + memcpy(&alias[matchpos], replacement, replacementlen); + memcpy(&alias[matchpos + replacementlen], rest, restlen + 1); /* includes null terminator */ + + break; + } + } + + /* Call the real setlocale() function */ + if (alias) + { + result = setlocale(category, alias); + free(alias); + } + else + result = setlocale(category, locale); + + return result; +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 1d10ee98e8..61656e6d6e 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -53,7 +53,7 @@ sub mkvcbuild snprintf.c strlcat.c strlcpy.c dirmod.c exec.c noblock.c path.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c getopt.c getopt_long.c dirent.c rint.c win32env.c - win32error.c); + win32error.c win32setlocale.c); $libpgport = $solution->AddProject('libpgport','lib','misc'); $libpgport->AddDefine('FRONTEND');