1 /*
2    Copyright (c) by Valery Goryachev (Wal)
3 */
4 
5 
6 #include "wal_sys_api.h"
7 
8 #include <stdio.h>
9 #include <stdarg.h>
10 
11 #ifdef _WIN32
12 #include <process.h>
13 #else
14 #include <stdlib.h>
15 #include <string.h>
16 #endif
17 #include <locale>
18 namespace wal
19 {
20 
21 	static void sys_locale_init();
22 
23 #ifdef _DEBUG
24 
dbg_printf(const char * format,...)25 	void dbg_printf( const char* format, ... )
26 	{
27 		char s[1024];
28 		va_list ap;
29 		va_start( ap, format );
30 		Lvsnprintf( s, sizeof( s ), format, ap );
31 		va_end( ap );
32 #ifdef _WIN32
33 		OutputDebugString( s );
34 #else
35 		printf( "%s", s );
36 #endif
37 	}
38 
39 #endif
40 
41 
42 #ifdef _WIN32
43 
44 #define INFMETA 0x19701027
45 
46 	struct _thread_info
47 	{
48 		unsigned meta;
49 		HANDLE handle;
50 		void* ( *f )( void* );
51 		void* data;
52 		void* ret;
53 	};
54 
55 	static DWORD tlsId = TLS_OUT_OF_INDEXES;
56 
57 
_thRun(void * a)58 	static /*void*/ unsigned __stdcall _thRun( void* a )
59 	{
60 		_thread_info* p = ( _thread_info* )a;
61 
62 		if ( !TlsSetValue( tlsId, p ) )
63 		{
64 			;//???
65 		}
66 
67 		try
68 		{
69 			p->ret = p->f( p->data );
70 		}
71 		catch ( ... )
72 		{
73 			p->ret = 0;
74 		}
75 
76 		if ( !( p->handle ) ) { free( p ); }
77 
78 		return 0;
79 	}
80 
thread_create(thread_t * th,void * (* f)(void *),void * arg,bool detached)81 	int thread_create( thread_t* th, void* ( *f )( void* ), void* arg, bool detached )
82 	{
83 		if ( tlsId == TLS_OUT_OF_INDEXES )
84 		{
85 			tlsId = TlsAlloc();
86 
87 			if ( tlsId == TLS_OUT_OF_INDEXES ) { return -1; }
88 
89 			TlsSetValue( tlsId, 0 );
90 		}
91 
92 		_thread_info* tinfo = ( _thread_info* )malloc( sizeof( _thread_info ) );
93 
94 		if ( !tinfo )
95 		{
96 			SetLastError( ERROR_NOT_ENOUGH_MEMORY );
97 			return -1;
98 		};
99 
100 		tinfo->meta = INFMETA;
101 
102 		tinfo->f = f;
103 
104 		tinfo->data = arg;
105 
106 		tinfo->ret = 0;
107 
108 		tinfo->handle = 0; //for detached - 0
109 
110 		uintptr_t r = _beginthreadex( 0, 0, _thRun, tinfo, detached ? 0 : CREATE_SUSPENDED, 0 );
111 
112 		if ( r == -1L )
113 		{
114 			free( tinfo );
115 			SetLastError( ERROR_TOO_MANY_TCBS );
116 			return -1;
117 		}
118 
119 		if ( detached )
120 		{
121 			CloseHandle( ( HANDLE )r );
122 
123 			if ( th ) { *th = 0; }
124 
125 			return 0;
126 		}
127 		else
128 		{
129 			tinfo->handle = ( HANDLE )r;
130 
131 			if ( th ) { *th = tinfo; }
132 
133 			ResumeThread( ( HANDLE )r );
134 		}
135 
136 		return 0;
137 	}
138 
thread_self()139 	thread_t thread_self()
140 	{
141 		if ( tlsId == TLS_OUT_OF_INDEXES ) { return 0; }
142 
143 		return ( thread_t )TlsGetValue( tlsId );
144 	}
145 
thread_join(thread_t th,void ** val)146 	int thread_join( thread_t th, void** val )
147 	{
148 		if ( !th || th->meta != INFMETA || th->handle == 0 )
149 		{
150 			SetLastError( ERROR_INVALID_PARAMETER );
151 			return -1;
152 		}
153 
154 		if ( WaitForSingleObject( th->handle, INFINITE ) != WAIT_OBJECT_0 )
155 		{
156 			return -1;   //неясно что делать с p
157 		}
158 
159 		if ( val ) { *val = th->ret; }
160 
161 		CloseHandle( th->handle );
162 		free( th );
163 		return 0;
164 	}
165 
cond_create(cond_t * c)166 	int cond_create( cond_t* c )
167 	{
168 		c->ev[0] = c->ev[1] = 0;
169 
170 		if ( !( c->ev[0] = CreateEvent( NULL, TRUE, FALSE, NULL ) ) || !( c->ev[1] = CreateEvent( NULL, FALSE, FALSE, NULL ) ) )
171 		{
172 			DWORD e = GetLastError();
173 
174 			if ( c->ev[0] ) { CloseHandle( c->ev[0] ); c->ev[0] = 0; }
175 
176 			if ( c->ev[1] ) { CloseHandle( c->ev[1] ); c->ev[1] = 0; }
177 
178 			SetLastError( e );
179 			return -1;
180 		}
181 
182 		return 0;
183 	}
184 
cond_delete(cond_t * c)185 	int cond_delete( cond_t* c )
186 	{
187 		DWORD e0 = ( CloseHandle( c->ev[0] ) == S_OK ) ? 0 : GetLastError();
188 		DWORD e1 = ( CloseHandle( c->ev[1] ) == S_OK ) ? 0 : GetLastError();
189 
190 		if ( e0 ) { SetLastError( e0 ); return -1; }
191 
192 		if ( e1 ) { SetLastError( e1 ); return -1; }
193 
194 		return 0;
195 	}
196 
cond_wait(cond_t * c,mutex_t * m)197 	int cond_wait( cond_t* c, mutex_t* m )
198 	{
199 		if ( mutex_unlock( m ) ) { return -1; }
200 
201 		DWORD ret = WaitForMultipleObjects( 2, c->ev, FALSE, INFINITE );
202 
203 		if ( mutex_lock( m ) ) { return -1; }
204 
205 		if ( ret == WAIT_OBJECT_0 || ret == WAIT_OBJECT_0 + 1 ) { return 0; }
206 
207 		return -1;
208 	}
209 
cond_signal(cond_t * c)210 	int cond_signal( cond_t* c ) { return SetEvent( c->ev[1] ) ? 0 : -1; }
cond_broadcast(cond_t * c)211 	int cond_broadcast( cond_t* c ) {    return PulseEvent( c->ev[0] ) ? 0 : -1; };
212 
213 
214 
215 
216 //return count of characters (length of buffer for conversion to unicode)
sys_symbol_count(const sys_char_t * s,int len)217 	int sys_symbol_count( const sys_char_t* s, int len )
218 	{
219 		if ( len < 0 )
220 		{
221 			for ( len = 0; *s; s++ ) { len++; }
222 		}
223 
224 		return len;
225 	}
226 
227 //return count of sys_chars for saving s
sys_string_buffer_len(const unicode_t * s,int ulen)228 	int sys_string_buffer_len( const unicode_t* s, int ulen ) //not including \0
229 	{
230 		if ( ulen < 0 )
231 		{
232 			for ( ulen = 0; *s; s++ ) { ulen++; }
233 		}
234 
235 		return ulen;
236 	}
237 
238 // return point of appended \0
sys_to_unicode(unicode_t * buf,const sys_char_t * s,int len,int * badCount)239 	unicode_t* sys_to_unicode(
240 	   unicode_t* buf,
241 	   const sys_char_t* s, int len,
242 	   int* badCount )
243 	{
244 		if ( len < 0 )
245 		{
246 			for ( ; *s; s++, buf++ ) { *buf = *s; }
247 		}
248 		else
249 		{
250 			for ( int i = 0; i < len; i++, s++, buf++ ) { *buf = *s; }
251 		}
252 
253 		*buf = 0;
254 
255 		if ( badCount ) { *badCount = 0; }
256 
257 		return buf;
258 	}
259 
260 // return point of appended \0
unicode_to_sys(sys_char_t * s,const unicode_t * buf,int ulen,int * badCount)261 	sys_char_t* unicode_to_sys(
262 	   sys_char_t* s,
263 	   const unicode_t* buf, int ulen,
264 	   int* badCount )
265 	{
266 		if ( ulen < 0 )
267 		{
268 			for ( ; *buf; s++, buf++ ) { *s = *buf; }
269 		}
270 		else
271 		{
272 			for ( int i = 0; i < ulen; i++, s++, buf++ ) { *s = *buf; }
273 		}
274 
275 		*s = 0;
276 
277 		if ( badCount ) { *badCount = 0; }
278 
279 		return s;
280 	}
281 
sys_error_str(int err,sys_char_t * buf,int size)282 	sys_char_t* sys_error_str( int err, sys_char_t* buf, int size )
283 	{
284 		if ( err == 0 ) { err = GetLastError(); }
285 
286 		if ( FormatMessageW(
287 		        FORMAT_MESSAGE_FROM_SYSTEM |
288 		        FORMAT_MESSAGE_IGNORE_INSERTS,
289 		        NULL,
290 		        err,
291 		        MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
292 		        buf,
293 		        size,
294 		        NULL
295 		     ) < 2 )
296 		{
297 #if defined( _MSC_VER )
298 			_snwprintf_s( buf, size, _TRUNCATE, L"Error code: %i", int( err ) );
299 #else
300 			_snwprintf( buf, size, L"Error code: %i", int( err ) );
301 #endif
302 		}
303 
304 		if ( size > 0 ) { buf[size - 1] = 0; }
305 
306 		for ( sys_char_t* s = buf; *s; s++ ) if ( *s == '\r' ) { *s = ' '; }
307 
308 		return buf;
309 	}
310 
InitSystemLocales()311 	bool InitSystemLocales()
312 	{
313 		sys_locale_init();
314 		return true;
315 	}
316 
317 #else
318 
319 	int sys_charset_id = CS_LATIN1;
320 
321 	extern unicode_t* latin1_to_unicode( unicode_t* buf, const char* s, int size, int* badCount );
322 	extern char* unicode_to_latin1( char* s, const unicode_t* buf, int usize, int* badCount );
323 	extern int cp8_symbol_count( const char* s, int size );
324 	extern int cp8_string_buffer_len( const unicode_t* buf, int ulen );
325 
326 	unicode_t* ( *fp_sys_to_unicode )( unicode_t* buf, const sys_char_t* s, int size, int* badCount ) = latin1_to_unicode;
327 	sys_char_t* ( *fp_unicode_to_sys )( sys_char_t* s, const unicode_t* buf, int usize, int* badCount ) = unicode_to_latin1;
328 	int ( *fp_sys_symbol_count )( const sys_char_t* s, int size ) = cp8_symbol_count;
329 	int ( *fp_sys_string_buffer_len )( const unicode_t* s, int ulen ) = cp8_string_buffer_len;
330 
331 
332 	struct LacaleCharsetAlias
333 	{
334 		const char* alias;
335 		int id;
336 	};
337 
338 	static LacaleCharsetAlias csAliasTable[] =
339 	{
340 		{"UTF-8",   CS_UTF8},
341 		{"CP1251",  CS_WIN1251},
342 		{"CP866",   CS_CP866},
343 		{"KOI8-R",  CS_KOI8R},
344 		{"KOI8R",   CS_KOI8R},
345 		{0, 0}
346 	};
347 
set_sys_charset(int id)348 	static void set_sys_charset( int id )
349 	{
350 		charset_struct* p = charset_table[id];
351 		fp_sys_to_unicode = p->cs_to_unicode;
352 		fp_unicode_to_sys = p->unicode_to_cs;
353 		fp_sys_symbol_count = p->symbol_count;
354 		fp_sys_string_buffer_len = p->string_buffer_len;
355 		sys_charset_id = id;
356 	};
357 
InitSystemLocales()358 	bool InitSystemLocales()
359 	{
360 		sys_locale_init();
361 
362 		set_sys_charset( CS_UTF8 );
363 
364 		char* s = getenv( "LANG" );
365 
366 		if ( !s )
367 		{
368 			return true;
369 		}
370 
371 		while ( *s && *s != '.' ) { s++; }
372 
373 		if ( *s == '.' ) { s++; }
374 
375 		for ( LacaleCharsetAlias* p = csAliasTable; p->alias; p++ )
376 			if ( !strcasecmp( s, p->alias ) )
377 			{
378 				set_sys_charset( p->id );
379 				return true;
380 			}
381 
382 
383 		printf( "'%s' (charset not found)\n", s );
384 
385 		return true;
386 	}
387 
sys_error_str(int err,sys_char_t * buf,int size)388 	sys_char_t* sys_error_str( int err, sys_char_t* buf, int size )
389 	{
390 		if ( size > 0 )
391 		{
392 			buf[0] = 0;
393 
394 
395 #if defined(__APPLE__) || \
396    defined(__FreeBSD__) || \
397    defined(__OpenBSD__) || \
398    defined(_POSIX_C_SOURCE) && defined(_XOPEN_SOURCE) && defined(_GNU_SOURCE) && (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
399 			strerror_r( err, buf, size );
400 #else
401 			return strerror_r( err, buf, size );
402 #endif
403 
404 		}
405 
406 		return buf;
407 	}
408 #endif
409 
410 	static char locale_lang[32] = "";
411 	static char locale_ter[32] = "";
412 	static char locale_lang_ter[32] = "";
413 	static const char* locale_str = 0;
414 
415 #ifdef _WIN32
416 	struct W32LCNode
417 	{
418 		int n;
419 		const char* lang;
420 	};
421 
422 	static W32LCNode w32LCNode[] =
423 	{
424 		{0x0001, "ar"}, {0x0002, "bg"}, {0x0003, "ca"}, {0x0004, "zh_Hans"},  {0x0005, "cs"},
425 		{0x0006, "da"}, {0x0007, "de"}, {0x0008, "el"}, {0x0009, "en"}, {0x000a, "es"},
426 		{0x000b, "fi"}, {0x000c, "fr"}, {0x000d, "he"}, {0x000e, "hu"}, {0x000f, "is"},
427 		{0x0010, "it"}, {0x0011, "ja"}, {0x0012, "ko"}, {0x0013, "nl"}, {0x0014, "no"},
428 		{0x0015, "pl"}, {0x0016, "pt"}, {0x0017, "rm"}, {0x0018, "ro"}, {0x0019, "ru"},
429 		{0x001a, "bs"}, {0x001b, "sk"}, {0x001c, "sq"}, {0x001d, "sv"}, {0x001e, "th"},
430 		{0x001f, "tr"}, {0x0020, "ur"}, {0x0021, "id"}, {0x0022, "uk"}, {0x0023, "be"},
431 		{0x0024, "sl"}, {0x0025, "et"}, {0x0026, "lv"}, {0x0027, "lt"}, {0x0028, "tg"},
432 		{0x0029, "fa"}, {0x002a, "vi"}, {0x002b, "hy"}, {0x002c, "az"}, {0x002d, "eu"},
433 		{0x002e, "dsb"},   {0x002f, "mk"}, {0x0030, "st"}, {0x0031, "ts"}, {0x0032, "tn"},
434 		{0x0033, "ve"}, {0x0034, "xh"}, {0x0035, "zu"}, {0x0036, "af"}, {0x0037, "ka"},
435 		{0x0038, "fo"}, {0x0039, "hi"}, {0x003a, "mt"}, {0x003b, "se"}, {0x003c, "ga"},
436 		{0x003d, "yi"}, {0x003e, "ms"}, {0x003f, "kk"}, {0x0040, "ky"}, {0x0041, "sw"},
437 		{0x0042, "tk"}, {0x0043, "uz"}, {0x0044, "tt"}, {0x0045, "bn"}, {0x0046, "pa"},
438 		{0x0047, "gu"}, {0x0048, "or"}, {0x0049, "ta"}, {0x004a, "te"}, {0x004b, "kn"},
439 		{0x004c, "ml"}, {0x004d, "as"}, {0x004e, "mr"}, {0x004f, "sa"}, {0x0050, "mn"},
440 		{0x0051, "bo"}, {0x0052, "cy"}, {0x0053, "km"}, {0x0054, "lo"}, {0x0055, "my"},
441 		{0x0056, "gl"}, {0x0057, "kok"},   {0x0058, "mni"},   {0x0059, "sd"}, {0x005a, "syr"},
442 		{0x005b, "si"}, {0x005c, "chr"},   {0x005d, "iu"}, {0x005e, "am"}, {0x005f, "tzm"},
443 		{0x0060, "ks"}, {0x0061, "ne"}, {0x0062, "fy"}, {0x0063, "ps"}, {0x0064, "fil"},
444 		{0x0065, "dv"}, {0x0066, "bin"},   {0x0067, "ff"}, {0x0068, "ha"}, {0x0069, "ibb"},
445 		{0x006a, "yo"}, {0x006b, "quz"},   {0x006c, "nso"},   {0x006d, "ba"}, {0x006e, "lb"},
446 		{0x006f, "kl"}, {0x0070, "ig"}, {0x0071, "kr"}, {0x0072, "om"}, {0x0073, "ti"},
447 		{0x0074, "gn"}, {0x0075, "haw"},   {0x0076, "la"}, {0x0077, "so"}, {0x0078, "ii"},
448 		{0x0079, "pap"},   {0x007a, "arn"},   {0x007b, "Neither"},  {0x007c, "moh"},   {0x007d, "Neither"},
449 		{0x007e, "br"}, {0x007f, "Reserved"}, {0x0080, "ug"}, {0x0081, "mi"}, {0x0082, "oc"},
450 		{0x0083, "co"}, {0x0084, "gsw"},   {0x0085, "sah"},   {0x0086, "qut"},   {0x0087, "rw"},
451 		{0x0088, "wo"}, {0x0089, "Neither"},  {0x008a, "Neither"},  {0x008b, "Neither"},  {0x008c, "prs"},
452 		{0x008d, "Neither"},  {0x008e, "Neither"},  {0x008f, "Neither"},  {0x0090, "Neither"},  {0x0091, "gd"},
453 		{0x0092, "ku"}, {0x0093, "quc"},   {0x0401, "ar_SA"}, {0x0402, "bg_BG"}, {0x0403, "ca_ES"},
454 		{0x0404, "zh_TW"}, {0x0405, "cs_CZ"}, {0x0406, "da_DK"}, {0x0407, "de_DE"}, {0x0408, "el_GR"},
455 		{0x0409, "en_US"}, {0x040a, "es_ES_tradnl"},   {0x040b, "fi_FI"}, {0x040c, "fr_FR"}, {0x040d, "he_IL"},
456 		{0x040e, "hu_HU"}, {0x040f, "is_IS"}, {0x0410, "it_IT"}, {0x0411, "ja_JP"}, {0x0412, "ko_KR"},
457 		{0x0413, "nl_NL"}, {0x0414, "nb_NO"}, {0x0415, "pl_PL"}, {0x0416, "pt_BR"}, {0x0417, "rm_CH"},
458 		{0x0418, "ro_RO"}, {0x0419, "ru_RU"}, {0x041a, "hr_HR"}, {0x041b, "sk_SK"}, {0x041c, "sq_AL"},
459 		{0x041d, "sv_SE"}, {0x041e, "th_TH"}, {0x041f, "tr_TR"}, {0x0420, "ur_PK"}, {0x0421, "id_ID"},
460 		{0x0422, "uk_UA"}, {0x0423, "be_BY"}, {0x0424, "sl_SI"}, {0x0425, "et_EE"}, {0x0426, "lv_LV"},
461 		{0x0427, "lt_LT"}, {0x0428, "tg_Cyrl_TJ"},  {0x0429, "fa_IR"}, {0x042a, "vi_VN"}, {0x042b, "hy_AM"},
462 		{0x042c, "az_Latn_AZ"},  {0x042d, "eu_ES"}, {0x042e, "hsb_DE"},   {0x042f, "mk_MK"}, {0x0430, "st_ZA"},
463 		{0x0431, "ts_ZA"}, {0x0432, "tn_ZA"}, {0x0433, "ve_ZA"}, {0x0434, "xh_ZA"}, {0x0435, "zu_ZA"},
464 		{0x0436, "af_ZA"}, {0x0437, "ka_GE"}, {0x0438, "fo_FO"}, {0x0439, "hi_IN"}, {0x043a, "mt_MT"},
465 		{0x043b, "se_NO"}, {0x043d, "yi_Hebr"},  {0x043e, "ms_MY"}, {0x043f, "kk_KZ"}, {0x0440, "ky_KG"},
466 		{0x0441, "sw_KE"}, {0x0442, "tk_TM"}, {0x0443, "uz_Latn_UZ"},  {0x0444, "tt_RU"}, {0x0445, "bn_IN"},
467 		{0x0446, "pa_IN"}, {0x0447, "gu_IN"}, {0x0448, "or_IN"}, {0x0449, "ta_IN"}, {0x044a, "te_IN"},
468 		{0x044b, "kn_IN"}, {0x044c, "ml_IN"}, {0x044d, "as_IN"}, {0x044e, "mr_IN"}, {0x044f, "sa_IN"},
469 		{0x0450, "mn_MN"}, {0x0451, "bo_CN"}, {0x0452, "cy_GB"}, {0x0453, "km_KH"}, {0x0454, "lo_LA"},
470 		{0x0455, "my_MM"}, {0x0456, "gl_ES"}, {0x0457, "kok_IN"},   {0x0458, "mni_IN"},   {0x0459, "sd_Deva_IN"},
471 		{0x045a, "syr_SY"},   {0x045b, "si_LK"}, {0x045c, "chr_Cher_US"}, {0x045d, "iu_Cans_CA"},  {0x045e, "am_ET"},
472 		{0x045f, "tzm_Arab_MA"}, {0x0460, "ks_Arab"},  {0x0461, "ne_NP"}, {0x0462, "fy_NL"}, {0x0463, "ps_AF"},
473 		{0x0464, "fil_PH"},   {0x0465, "dv_MV"}, {0x0466, "bin_NG"},   {0x0467, "fuv_NG"},   {0x0468, "ha_Latn_NG"},
474 		{0x0469, "ibb_NG"},   {0x046a, "yo_NG"}, {0x046b, "quz_BO"},   {0x046c, "nso_ZA"},   {0x046d, "ba_RU"},
475 		{0x046e, "lb_LU"}, {0x046f, "kl_GL"}, {0x0470, "ig_NG"}, {0x0471, "kr_NG"}, {0x0472, "om_ET"},
476 		{0x0473, "ti_ET"}, {0x0474, "gn_PY"}, {0x0475, "haw_US"},   {0x0476, "la_Latn"},  {0x0477, "so_SO"},
477 		{0x0478, "ii_CN"}, {0x0479, "pap_029"},  {0x047a, "arn_CL"},   {0x047c, "moh_CA"},   {0x047e, "br_FR"},
478 		{0x0480, "ug_CN"}, {0x0481, "mi_NZ"}, {0x0482, "oc_FR"}, {0x0483, "co_FR"}, {0x0484, "gsw_FR"},
479 		{0x0485, "sah_RU"},   {0x0486, "qut_GT"},   {0x0487, "rw_RW"}, {0x0488, "wo_SN"}, {0x048c, "prs_AF"},
480 		{0x048d, "plt_MG"},   {0x048e, "zh_yue_HK"},   {0x048f, "tdd_Tale_CN"}, {0x0490, "khb_Talu_CN"}, {0x0491, "gd_GB"},
481 		{0x0492, "ku_Arab_IQ"},  {0x0493, "quc_CO"},   {0x0501, "qps_ploc"}, {0x05fe, "qps_ploca"},   {0x0801, "ar_IQ"},
482 		{0x0803, "ca_ES_valencia"}, {0x0804, "zh_CN"}, {0x0807, "de_CH"}, {0x0809, "en_GB"}, {0x080a, "es_MX"},
483 		{0x080c, "fr_BE"}, {0x0810, "it_CH"}, {0x0811, "ja_Ploc_JP"},  {0x0813, "nl_BE"}, {0x0814, "nn_NO"},
484 		{0x0816, "pt_PT"}, {0x0818, "ro_MD"}, {0x0819, "ru_MD"}, {0x081a, "sr_Latn_CS"},  {0x081d, "sv_FI"},
485 		{0x0820, "ur_IN"}, {0x0827, "Neither"},  {0x082c, "az_Cyrl_AZ"},  {0x082e, "dsb_DE"},   {0x0832, "tn_BW"},
486 		{0x083b, "se_SE"}, {0x083c, "ga_IE"}, {0x083e, "ms_BN"}, {0x0843, "uz_Cyrl_UZ"},  {0x0845, "bn_BD"},
487 		{0x0846, "pa_Arab_PK"},  {0x0849, "ta_LK"}, {0x0850, "mn_Mong_CN"},  {0x0851, "bo_BT"}, {0x0859, "sd_Arab_PK"},
488 		{0x085d, "iu_Latn_CA"},  {0x085f, "tzm_Latn_DZ"}, {0x0860, "ks_Deva"},  {0x0861, "ne_IN"}, {0x0867, "ff_Latn_SN"},
489 		{0x086b, "quz_EC"},   {0x0873, "ti_ER"}, {0x09ff, "qps_plocm"},   {0x0c01, "ar_EG"}, {0x0c04, "zh_HK"},
490 		{0x0c07, "de_AT"}, {0x0c09, "en_AU"}, {0x0c0a, "es_ES"}, {0x0c0c, "fr_CA"}, {0x0c1a, "sr_Cyrl_CS"},
491 		{0x0c3b, "se_FI"}, {0x0c50, "mn_Mong_MN"},  {0x0c5f, "tmz_MA"},   {0x0c6b, "quz_PE"},   {0x1001, "ar_LY"},
492 		{0x1004, "zh_SG"}, {0x1007, "de_LU"}, {0x1009, "en_CA"}, {0x100a, "es_GT"}, {0x100c, "fr_CH"},
493 		{0x101a, "hr_BA"}, {0x103b, "smj_NO"},   {0x105f, "tzm_Tfng_MA"}, {0x1401, "ar_DZ"}, {0x1404, "zh_MO"},
494 		{0x1407, "de_LI"}, {0x1409, "en_NZ"}, {0x140a, "es_CR"}, {0x140c, "fr_LU"}, {0x141a, "bs_Latn_BA"},
495 		{0x143b, "smj_SE"},   {0x1801, "ar_MA"}, {0x1809, "en_IE"}, {0x180a, "es_PA"}, {0x180c, "fr_MC"},
496 		{0x181a, "sr_Latn_BA"},  {0x183b, "sma_NO"},   {0x1c01, "ar_TN"}, {0x1c09, "en_ZA"}, {0x1c0a, "es_DO"},
497 		{0x1c0c, "Neither"},  {0x1c1a, "sr_Cyrl_BA"},  {0x1c3b, "sma_SE"},   {0x2001, "ar_OM"}, {0x2008, "Neither"},
498 		{0x2009, "en_JM"}, {0x200a, "es_VE"}, {0x200c, "fr_RE"}, {0x201a, "bs_Cyrl_BA"},  {0x203b, "sms_FI"},
499 		{0x2401, "ar_YE"}, {0x2409, "en_029"},   {0x240a, "es_CO"}, {0x240c, "fr_CD"}, {0x241a, "sr_Latn_RS"},
500 		{0x243b, "smn_FI"},   {0x2801, "ar_SY"}, {0x2809, "en_BZ"}, {0x280a, "es_PE"}, {0x280c, "fr_SN"},
501 		{0x281a, "sr_Cyrl_RS"},  {0x2c01, "ar_JO"}, {0x2c09, "en_TT"}, {0x2c0a, "es_AR"}, {0x2c0c, "fr_CM"},
502 		{0x2c1a, "sr_Latn_ME"},  {0x3001, "ar_LB"}, {0x3009, "en_ZW"}, {0x300a, "es_EC"}, {0x300c, "fr_CI"},
503 		{0x301a, "sr_Cyrl_ME"},  {0x3401, "ar_KW"}, {0x3409, "en_PH"}, {0x340a, "es_CL"}, {0x340c, "fr_ML"},
504 		{0x3801, "ar_AE"}, {0x3809, "en_ID"}, {0x380a, "es_UY"}, {0x380c, "fr_MA"}, {0x3c01, "ar_BH"},
505 		{0x3c09, "en_HK"}, {0x3c0a, "es_PY"}, {0x3c0c, "fr_HT"}, {0x4001, "ar_QA"}, {0x4009, "en_IN"},
506 		{0x400a, "es_BO"}, {0x4401, "ar_Ploc_SA"},  {0x4409, "en_MY"}, {0x440a, "es_SV"}, {0x4801, "ar_145"},
507 		{0x4809, "en_SG"}, {0x480a, "es_HN"}, {0x4c09, "en_AE"}, {0x4c0a, "es_NI"}, {0x5009, "en_BH"},
508 		{0x500a, "es_PR"}, {0x5409, "en_EG"}, {0x540a, "es_US"}, {0x5809, "en_JO"}, {0x580a, "es_419"},
509 		{0x5c09, "en_KW"}, {0x6009, "en_TR"}, {0x6409, "en_YE"}, {0x641a, "bs_Cyrl"},  {0x681a, "bs_Latn"},
510 		{0x6c1a, "sr_Cyrl"},  {0x701a, "sr_Latn"},  {0x703b, "smn"},      {0x742c, "az_Cyrl"},  {0x743b, "sms"},
511 		{0x7804, "zh"},    {0x7814, "nn"},    {0x781a, "bs"},    {0x782c, "az_Latn"},  {0x783b, "sma"},
512 		{0x7843, "uz_Cyrl"},  {0x7850, "mn_Cyrl"},  {0x785d, "iu_Cans"},  {0x785f, "tzm_Tfng"}, {0x7c04, "zh_Hant"},
513 		{0x7c14, "nb"},    {0x7c1a, "sr"},    {0x7c28, "tg_Cyrl"},  {0x7c2e, "dsb"},      {0x7c3b, "smj"},
514 		{0x7c43, "uz_Latn"},  {0x7c46, "pa_Arab"},  {0x7c50, "mn_Mong"},  {0x7c59, "sd_Arab"},  {0x7c5c, "chr_Cher"},
515 		{0x7c5d, "iu_Latn"},  {0x7c5f, "tzm_Latn"}, {0x7c67, "ff_Latn"},  {0x7c68, "ha_Latn"},  {0x7c92, "ku_Arab"},
516 		{0, 0}
517 	};
518 
519 
520 #endif
521 
sys_locale_init()522 	static void sys_locale_init()
523 	{
524 		if ( !locale_str )
525 		{
526 #ifdef _WIN32
527 			unsigned lcid = GetUserDefaultLCID();
528 
529 			for ( W32LCNode* p = w32LCNode; p->n && p->lang; p++ )
530 				if ( p->n == lcid )
531 				{
532 					locale_str = p->lang;
533 					break;
534 				};
535 
536 #else
537 			locale_str = getenv( "LANG" );
538 
539 #endif
540 
541 			if ( !locale_str ) { locale_str = "en"; }
542 
543 			if ( locale_str )
544 			{
545 				const char* s = locale_str;
546 				int i;
547 
548 				for ( i = 0 ; i < sizeof( locale_lang ) - 1 && *s && *s != '_' && *s != '.'; i++, s++ ) { locale_lang[i] = *s; }
549 
550 				locale_lang[i] = 0;
551 
552 				for ( i = 0 ; i < sizeof( locale_ter ) - 1 && *s && *s != '.'; i++, s++ ) { locale_ter[i] = *s; }
553 
554 				locale_ter[i] = 0;
555 
556 				s = locale_str;
557 
558 				for ( i = 0 ; i < sizeof( locale_lang_ter ) - 1 && *s && *s != '.'; i++, s++ ) { locale_lang_ter[i] = *s; }
559 
560 				locale_lang_ter[i] = 0;
561 			}
562 		};
563 	}
564 
sys_locale_lang()565 	const char* sys_locale_lang() { return locale_lang; }
sys_locale_ter()566 	const char* sys_locale_ter() { return locale_ter;}
sys_locale_lang_ter()567 	const char* sys_locale_lang_ter() { return locale_lang_ter; }
568 }; //namespace wal
569 
570