1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "bl_locale.h"
4
5 #include <stdio.h> /* sprintf */
6 #include <locale.h> /* setlocale() */
7
8 /* for bl_get_codeset_win32() */
9 #ifdef HAVE_WINDOWS_H
10 #include <windows.h>
11 #endif
12
13 #include "bl_langinfo.h" /* bl_langinfo() */
14 #include "bl_debug.h"
15 #include "bl_mem.h" /* alloca */
16 #include "bl_str.h"
17 #include "bl_util.h" /* BL_MIN */
18
19 #if 0
20 #define __DEBUG
21 #endif
22
23 typedef struct lang_codeset_table {
24 char *lang;
25 char *codeset;
26
27 } lang_codeset_table_t;
28
29 typedef struct alias_codeset_table {
30 char *codeset;
31 char *locale;
32
33 char *alias;
34
35 } alias_codeset_table_t;
36
37 /* --- static variables --- */
38
39 static char *sys_locale = NULL;
40 static char *sys_lang = NULL;
41 static char *sys_country = NULL;
42 static char *sys_codeset = NULL;
43
44 /* for sys_lang and sys_country memory */
45 static char *sys_lang_country = NULL;
46
47 #ifndef USE_WIN32API
48 static lang_codeset_table_t lang_codeset_table[] = {
49 { "en", "ISO8859-1", },
50 { "da", "ISO8859-1", },
51 { "de", "ISO8859-1", },
52 { "fi", "ISO8859-1", },
53 { "fr", "ISO8859-1", },
54 { "is", "ISO8859-1", },
55 { "it", "ISO8859-1", },
56 { "nl", "ISO8859-1", },
57 { "no", "ISO8859-1", },
58 { "pt", "ISO8859-1", },
59 { "sv", "ISO8859-1", },
60 { "cs", "ISO8859-2", },
61 { "hr", "ISO8859-2", },
62 { "hu", "ISO8859-2", },
63 { "la", "ISO8859-2", },
64 { "lt", "ISO8859-2", },
65 { "pl", "ISO8859-2", },
66 { "sl", "ISO8859-2", },
67 { "el", "ISO8859-7", },
68 { "ru", "KOI8-R", },
69 { "uk", "KOI8-U", },
70 { "vi", "VISCII", },
71 { "th", "TIS-620", },
72 { "ja", "eucJP", },
73 { "ko", "eucKR", },
74 { "zh_CN", "eucCN", },
75 { "zh_TW", "Big5", },
76 { "zh_HK", "Big5HKSCS", },
77 };
78 #endif
79
80 static alias_codeset_table_t alias_codeset_table[] = {
81 { "EUC", "ja_JP.EUC", "eucJP", },
82 { "EUC", "ko_KR.EUC", "eucKR", },
83 };
84
85 /* --- global functions --- */
86
bl_locale_init(const char * locale)87 int bl_locale_init(const char *locale) {
88 char *locale_p;
89 int result;
90
91 if (sys_locale && locale && strcmp(locale, sys_locale) == 0) {
92 return 1;
93 }
94
95 if ((locale = setlocale(LC_CTYPE, locale)) == NULL) {
96 #ifdef DEBUG
97 bl_warn_printf(BL_DEBUG_TAG " setlocale() failed.\n");
98 #endif
99
100 if (sys_locale) {
101 /* restoring locale info. nothing is changed. */
102 setlocale(LC_CTYPE, sys_locale);
103
104 return 0;
105 } else if ((locale = getenv("LC_ALL")) == NULL && (locale = getenv("LC_CTYPE")) == NULL &&
106 (locale = getenv("LANG")) == NULL) {
107 /* nothing is changed */
108
109 return 0;
110 }
111
112 result = 0;
113 } else {
114 result = 1;
115 }
116
117 if (sys_locale) {
118 free(sys_locale);
119 sys_locale = NULL;
120 }
121
122 if (sys_lang_country) {
123 free(sys_lang_country);
124 sys_lang_country = NULL;
125 }
126
127 /*
128 * If external library calls setlocale(), this 'locale' variable
129 * can be free'ed, so strdup() shoule be called.
130 */
131 sys_locale = strdup(locale);
132
133 if ((locale_p = sys_lang_country = strdup(locale)) == NULL) {
134 sys_locale = NULL;
135
136 return 0;
137 }
138
139 if ((sys_lang = bl_str_sep(&locale_p, "_")) == NULL) {
140 /* this never happends */
141
142 return 0;
143 }
144
145 sys_country = bl_str_sep(&locale_p, ".");
146
147 sys_codeset = bl_langinfo(CODESET);
148
149 if (strcmp(sys_codeset, "") == 0) {
150 if (locale_p && *locale_p) {
151 sys_codeset = locale_p;
152 } else {
153 sys_codeset = NULL;
154 }
155 }
156
157 if (sys_codeset) {
158 /*
159 * normalizing codeset name.
160 */
161
162 int count;
163
164 for (count = 0; count < sizeof(alias_codeset_table) / sizeof(alias_codeset_table[0]); count++) {
165 if (strcmp(sys_codeset, alias_codeset_table[count].codeset) == 0 &&
166 strcmp(locale, alias_codeset_table[count].locale) == 0) {
167 sys_codeset = alias_codeset_table[count].alias;
168
169 break;
170 }
171 }
172 }
173
174 #ifdef __DEBUG
175 bl_debug_printf("locale setttings -> locale %s lang %s country %s codeset %s\n", sys_locale,
176 sys_lang, sys_country, sys_codeset);
177 #endif
178
179 return result;
180 }
181
bl_locale_final(void)182 void bl_locale_final(void) {
183 if (sys_locale) {
184 free(sys_locale);
185 sys_locale = NULL;
186 }
187
188 if (sys_lang_country) {
189 free(sys_lang_country);
190 sys_lang_country = NULL;
191 }
192 }
193
bl_get_locale(void)194 char *bl_get_locale(void) {
195 if (sys_locale) {
196 return sys_locale;
197 } else {
198 return "C";
199 }
200 }
201
bl_get_lang(void)202 char *bl_get_lang(void) {
203 if (sys_lang) {
204 return sys_lang;
205 } else {
206 return "en";
207 }
208 }
209
bl_get_country(void)210 char *bl_get_country(void) {
211 if (sys_country) {
212 return sys_country;
213 } else {
214 return "US";
215 }
216 }
217
218 #ifndef USE_WIN32API
219
bl_get_codeset(void)220 char *bl_get_codeset(void) {
221 if (sys_codeset) {
222 return sys_codeset;
223 } else if (sys_lang) {
224 int count;
225 char *lang;
226 u_int lang_len;
227
228 lang_len = strlen(sys_lang) + 1;
229 if (sys_country) {
230 /* "+ 1" is for '_' */
231 lang_len += strlen(sys_country) + 1;
232 }
233
234 if ((lang = alloca(lang_len)) == NULL) {
235 return "ISO8859-1";
236 }
237
238 if (sys_country) {
239 sprintf(lang, "%s_%s", sys_lang, sys_country);
240 } else {
241 sprintf(lang, "%s", sys_lang);
242 }
243
244 #ifdef __DEBUG
245 bl_debug_printf("lang -> %s\n", lang);
246 #endif
247
248 for (count = 0; count < sizeof(lang_codeset_table) / sizeof(lang_codeset_table[0]); count++) {
249 if (strncmp(lang, lang_codeset_table[count].lang,
250 /* lang_len *- 1* is excluing NULL */
251 BL_MIN(lang_len - 1, strlen(lang_codeset_table[count].lang))) == 0) {
252 return lang_codeset_table[count].codeset;
253 }
254 }
255 }
256
257 return "ISO8859-1";
258 }
259
260 #endif /* USE_WIN32API */
261
262 #ifdef HAVE_WINDOWS_H
263
264 typedef struct cp_cs_table {
265 int codepage;
266 char *codeset;
267
268 } cp_cs_table_t;
269
270 static cp_cs_table_t cp_cs_table[] = {
271 {
272 1250, "CP1250",
273 }, /* EastEurope_CHARSET */
274 {
275 1251, "CP1251",
276 }, /* RUSSIAN_CHARSET */
277 {
278 1252, "CP1252",
279 }, /* ANSI_CHARSET */
280 {
281 1253, "CP1253",
282 }, /* GREEK_CHARSET */
283 {
284 1254, "CP1254",
285 }, /* TURKISH_CHARSET */
286 {
287 1255, "CP1255",
288 }, /* HEBREW_CHARSET */
289 {
290 1256, "CP1256",
291 }, /* ARABIC_CHARSET */
292 {
293 1257, "CP1257",
294 }, /* BALTIC_CHARSET */
295 {
296 1258, "CP1258",
297 }, /* VIETNAMESE_CHARSET */
298 {
299 874, "ISO8859-11",
300 }, /* THAI_CHARSET XXX CP874 is extended from ISO8859-11 */
301 {
302 932, "SJIS",
303 }, /* SHIFTJIS_CHARSET */
304 {
305 936, "GBK",
306 }, /* GB2313_CHARSET */
307 {
308 949, "UHC",
309 }, /* HANGEUL_CHARSET */
310 {
311 950, "BIG5",
312 }, /* CHINESEBIG5_CHARSET */
313 };
314
bl_get_codeset_win32(void)315 char *bl_get_codeset_win32(void) {
316 int count;
317 int codepage;
318
319 codepage = GetACP();
320
321 for (count = 0; count < sizeof(cp_cs_table) / sizeof(cp_cs_table_t); count++) {
322 if (cp_cs_table[count].codepage == codepage) {
323 return cp_cs_table[count].codeset;
324 }
325 }
326
327 return "ISO8859-1";
328 }
329
330 #endif /* HAVE_WINDOWS_H */
331