@@ -185,6 +185,8 @@ static int locale_date_order(const char *locale);
185
185
static bool check_locale_name (const char * locale );
186
186
static bool check_locale_encoding (const char * locale , int encoding );
187
187
static void setlocales (void );
188
+ static void strreplace (char * str , char * needle , char * replacement );
189
+ static char * localemap (char * locale );
188
190
static void usage (const char * progname );
189
191
190
192
#ifdef WIN32
@@ -2250,6 +2252,79 @@ check_locale_encoding(const char *locale, int user_enc)
2250
2252
return true;
2251
2253
}
2252
2254
2255
+ /*
2256
+ * Replace 'needle' with 'replacement' in 'str' . Note that the replacement
2257
+ * is done in-place, so 'replacement' must be shorter than 'needle'.
2258
+ */
2259
+ static void
2260
+ strreplace (char * str , char * needle , char * replacement )
2261
+ {
2262
+ char * s ;
2263
+
2264
+ s = strstr (str , needle );
2265
+ if (s != NULL )
2266
+ {
2267
+ int replacementlen = strlen (replacement );
2268
+ char * rest = s + strlen (needle );
2269
+
2270
+ memcpy (s , replacement , replacementlen );
2271
+ memmove (s + replacementlen , rest , strlen (rest ) + 1 );
2272
+ }
2273
+ }
2274
+
2275
+ /*
2276
+ * Windows has a problem with locale names that have a dot or apostrophe in
2277
+ * the country name. For example:
2278
+ *
2279
+ * "Chinese (Traditional)_Hong Kong S.A.R..950"
2280
+ *
2281
+ * For some reason, setlocale() doesn't accept that. Fortunately, Windows'
2282
+ * setlocale() accepts various alternative names for such countries, so we
2283
+ * map the full country names to accepted aliases.
2284
+ *
2285
+ * The returned string is always malloc'd - if no mapping is done it is
2286
+ * just a malloc'd copy of the original.
2287
+ */
2288
+ static char *
2289
+ localemap (char * locale )
2290
+ {
2291
+ locale = xstrdup (locale );
2292
+
2293
+ #ifdef WIN32
2294
+ /*
2295
+ * Map the full country name to an abbreviation that setlocale() accepts
2296
+ * "China" and "HKG" are listed here:
2297
+ * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx
2298
+ * (Country/Region Strings).
2299
+ *
2300
+ * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the
2301
+ * above list, but seems to work anyway.
2302
+ */
2303
+ strreplace (locale , "People's Republic of China" , "China" );
2304
+ strreplace (locale , "Hong Kong S.A.R." , "HKG" );
2305
+ strreplace (locale , "U.A.E." , "ARE" );
2306
+
2307
+ /*
2308
+ * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't
2309
+ * seem to recognize that. And Macau isn't listed in the table of
2310
+ * accepted abbreviations linked above.
2311
+ *
2312
+ * Fortunately, "ZHM" seems to be accepted as an alias for
2313
+ * "Chinese (Traditional)_Macau S.A.R..950", so we use that. Note that
2314
+ * it's unlike HKG and ARE, ZHM is an alias for the whole locale name,
2315
+ * not just the country part. I'm not sure where that "ZHM" comes from,
2316
+ * must be some legacy naming scheme. But hey, it works.
2317
+ *
2318
+ * Some versions of Windows spell it "Macau", others "Macao".
2319
+ */
2320
+ strreplace (locale , "Chinese (Traditional)_Macau S.A.R..950" , "ZHM" );
2321
+ strreplace (locale , "Chinese_Macau S.A.R..950" , "ZHM" );
2322
+ strreplace (locale , "Chinese (Traditional)_Macao S.A.R..950" , "ZHM" );
2323
+ strreplace (locale , "Chinese_Macao S.A.R..950" , "ZHM" );
2324
+ #endif
2325
+
2326
+ return locale ;
2327
+ }
2253
2328
2254
2329
/*
2255
2330
* set up the locale variables
@@ -2282,25 +2357,25 @@ setlocales(void)
2282
2357
*/
2283
2358
2284
2359
if (strlen (lc_ctype ) == 0 || !check_locale_name (lc_ctype ))
2285
- lc_ctype = xstrdup (setlocale (LC_CTYPE , NULL ));
2360
+ lc_ctype = localemap (setlocale (LC_CTYPE , NULL ));
2286
2361
if (strlen (lc_collate ) == 0 || !check_locale_name (lc_collate ))
2287
- lc_collate = xstrdup (setlocale (LC_COLLATE , NULL ));
2362
+ lc_collate = localemap (setlocale (LC_COLLATE , NULL ));
2288
2363
if (strlen (lc_numeric ) == 0 || !check_locale_name (lc_numeric ))
2289
- lc_numeric = xstrdup (setlocale (LC_NUMERIC , NULL ));
2364
+ lc_numeric = localemap (setlocale (LC_NUMERIC , NULL ));
2290
2365
if (strlen (lc_time ) == 0 || !check_locale_name (lc_time ))
2291
- lc_time = xstrdup (setlocale (LC_TIME , NULL ));
2366
+ lc_time = localemap (setlocale (LC_TIME , NULL ));
2292
2367
if (strlen (lc_monetary ) == 0 || !check_locale_name (lc_monetary ))
2293
- lc_monetary = xstrdup (setlocale (LC_MONETARY , NULL ));
2368
+ lc_monetary = localemap (setlocale (LC_MONETARY , NULL ));
2294
2369
if (strlen (lc_messages ) == 0 || !check_locale_name (lc_messages ))
2295
2370
#if defined(LC_MESSAGES ) && !defined(WIN32 )
2296
2371
{
2297
2372
/* when available get the current locale setting */
2298
- lc_messages = xstrdup (setlocale (LC_MESSAGES , NULL ));
2373
+ lc_messages = localemap (setlocale (LC_MESSAGES , NULL ));
2299
2374
}
2300
2375
#else
2301
2376
{
2302
2377
/* when not available, get the CTYPE setting */
2303
- lc_messages = xstrdup (setlocale (LC_CTYPE , NULL ));
2378
+ lc_messages = localemap (setlocale (LC_CTYPE , NULL ));
2304
2379
}
2305
2380
#endif
2306
2381
0 commit comments