Header And Logo

PostgreSQL
| The world's most advanced open source database.

win32setlocale.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * win32setlocale.c
00004  *      Wrapper to work around bugs in Windows setlocale() implementation
00005  *
00006  * Copyright (c) 2011-2013, PostgreSQL Global Development Group
00007  *
00008  * IDENTIFICATION
00009  *    src/port/win32setlocale.c
00010  *
00011  *
00012  * Windows has a problem with locale names that have a dot in the country
00013  * name. For example:
00014  *
00015  * "Chinese (Traditional)_Hong Kong S.A.R..950"
00016  *
00017  * For some reason, setlocale() doesn't accept that. Fortunately, Windows'
00018  * setlocale() accepts various alternative names for such countries, so we
00019  * provide a wrapper setlocale() function that maps the troublemaking locale
00020  * names to accepted aliases.
00021  *-------------------------------------------------------------------------
00022  */
00023 
00024 #include "c.h"
00025 
00026 #undef setlocale
00027 
00028 struct locale_map
00029 {
00030     const char *locale_name_part;       /* string in locale name to replace */
00031     const char *replacement;    /* string to replace it with */
00032 };
00033 
00034 static const struct locale_map locale_map_list[] = {
00035     /*
00036      * "HKG" is listed here:
00037      * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx
00038      * (Country/Region Strings).
00039      *
00040      * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the
00041      * above list, but seems to work anyway.
00042      */
00043     {"Hong Kong S.A.R.", "HKG"},
00044     {"U.A.E.", "ARE"},
00045 
00046     /*
00047      * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't
00048      * seem to recognize that. And Macau isn't listed in the table of accepted
00049      * abbreviations linked above. Fortunately, "ZHM" seems to be accepted as
00050      * an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm not sure
00051      * where "ZHM" comes from, must be some legacy naming scheme. But hey, it
00052      * works.
00053      *
00054      * Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale
00055      * name, not just the country part.
00056      *
00057      * Some versions of Windows spell it "Macau", others "Macao".
00058      */
00059     {"Chinese (Traditional)_Macau S.A.R..950", "ZHM"},
00060     {"Chinese_Macau S.A.R..950", "ZHM"},
00061     {"Chinese (Traditional)_Macao S.A.R..950", "ZHM"},
00062     {"Chinese_Macao S.A.R..950", "ZHM"}
00063 };
00064 
00065 char *
00066 pgwin32_setlocale(int category, const char *locale)
00067 {
00068     char       *result;
00069     char       *alias;
00070     int         i;
00071 
00072     if (locale == NULL)
00073         return setlocale(category, locale);
00074 
00075     /* Check if the locale name matches any of the problematic ones. */
00076     alias = NULL;
00077     for (i = 0; i < lengthof(locale_map_list); i++)
00078     {
00079         const char *needle = locale_map_list[i].locale_name_part;
00080         const char *replacement = locale_map_list[i].replacement;
00081         char       *match;
00082 
00083         match = strstr(locale, needle);
00084         if (match != NULL)
00085         {
00086             /* Found a match. Replace the matched string. */
00087             int         matchpos = match - locale;
00088             int         replacementlen = strlen(replacement);
00089             char       *rest = match + strlen(needle);
00090             int         restlen = strlen(rest);
00091 
00092             alias = malloc(matchpos + replacementlen + restlen + 1);
00093             if (!alias)
00094                 return NULL;
00095 
00096             memcpy(&alias[0], &locale[0], matchpos);
00097             memcpy(&alias[matchpos], replacement, replacementlen);
00098             memcpy(&alias[matchpos + replacementlen], rest, restlen + 1);       /* includes null
00099                                                                                  * terminator */
00100 
00101             break;
00102         }
00103     }
00104 
00105     /* Call the real setlocale() function */
00106     if (alias)
00107     {
00108         result = setlocale(category, alias);
00109         free(alias);
00110     }
00111     else
00112         result = setlocale(category, locale);
00113 
00114     return result;
00115 }