xref: /onnv-gate/usr/src/lib/libast/common/comp/setlocale.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin 
244887Schin /*
254887Schin  * setlocale() intercept
264887Schin  * maintains a bitmask of non-default categories
274887Schin  * and a permanent locale namespace for pointer comparison
284887Schin  * and persistent private data for locale related functions
294887Schin  */
304887Schin 
314887Schin #include <ast_standards.h>
324887Schin 
334887Schin #include "lclib.h"
344887Schin 
354887Schin #include <ast_wchar.h>
364887Schin #include <ctype.h>
374887Schin #include <mc.h>
384887Schin #include <namval.h>
394887Schin 
404887Schin #if ( _lib_wcwidth || _lib_wctomb ) && _hdr_wctype
414887Schin #include <wctype.h>
424887Schin #endif
434887Schin 
444887Schin #if _lib_wcwidth
454887Schin #undef	wcwidth
464887Schin #else
474887Schin #define wcwidth			0
484887Schin #endif
494887Schin 
504887Schin #if _lib_wctomb
514887Schin #undef	wctomb
524887Schin #else
534887Schin #define wctomb			0
544887Schin #endif
554887Schin 
564887Schin #ifdef mblen
574887Schin #undef	mblen
584887Schin extern int		mblen(const char*, size_t);
594887Schin #endif
604887Schin 
614887Schin #undef	mbtowc
624887Schin #undef	setlocale
634887Schin #undef	strcmp
644887Schin #undef	strcoll
654887Schin #undef	strxfrm
664887Schin #undef	valid
674887Schin 
684887Schin #ifndef AST_LC_CANONICAL
694887Schin #define AST_LC_CANONICAL	LC_abbreviated
704887Schin #endif
714887Schin 
7210898Sroland.mainz@nrubsig.org #ifndef AST_LC_test
7310898Sroland.mainz@nrubsig.org #define AST_LC_test		(1L<<27)
7410898Sroland.mainz@nrubsig.org #endif
7510898Sroland.mainz@nrubsig.org 
764887Schin #if _UWIN
774887Schin 
784887Schin #include <ast_windows.h>
794887Schin 
804887Schin #undef	_lib_setlocale
814887Schin #define _lib_setlocale		1
824887Schin 
834887Schin #define setlocale(c,l)		native_setlocale(c,l)
844887Schin 
854887Schin extern char*			uwin_setlocale(int, const char*);
864887Schin 
874887Schin /*
884887Schin  * convert locale to native locale name in buf
894887Schin  */
904887Schin 
914887Schin static char*
native_locale(const char * locale,char * buf,size_t siz)924887Schin native_locale(const char* locale, char* buf, size_t siz)
934887Schin {
944887Schin 	Lc_t*				lc;
954887Schin 	const Lc_attribute_list_t*	ap;
964887Schin 	int				i;
974887Schin 	unsigned long			lcid;
984887Schin 	unsigned long			lang;
994887Schin 	unsigned long			ctry;
1004887Schin 	char				lbuf[128];
1014887Schin 	char				cbuf[128];
1024887Schin 
1034887Schin 	if (locale && *locale)
1044887Schin 	{
1054887Schin 		if (!(lc = lcmake(locale)))
1064887Schin 			return 0;
1074887Schin 		lang = lc->language->index;
1084887Schin 		ctry = 0;
1094887Schin 		for (ap = lc->attributes; ap; ap = ap->next)
1104887Schin 			if (ctry = ap->attribute->index)
1114887Schin 				break;
1124887Schin 		if (!ctry)
1134887Schin 		{
1144887Schin 			for (i = 0; i < elementsof(lc->territory->languages); i++)
1154887Schin 				if (lc->territory->languages[i] == lc->language)
1164887Schin 				{
1174887Schin 					ctry = lc->territory->indices[i];
1184887Schin 					break;
1194887Schin 				}
1204887Schin 			if (!ctry)
12110898Sroland.mainz@nrubsig.org 			{
12210898Sroland.mainz@nrubsig.org 				if (!lang)
12310898Sroland.mainz@nrubsig.org 					return 0;
1244887Schin 				ctry = SUBLANG_DEFAULT;
12510898Sroland.mainz@nrubsig.org 			}
1264887Schin 		}
1274887Schin 		lcid = MAKELCID(MAKELANGID(lang, ctry), SORT_DEFAULT);
1284887Schin 	}
1294887Schin 	else
1304887Schin 		lcid = GetUserDefaultLCID();
1314887Schin 	if (GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, lbuf, sizeof(lbuf)) <= 0 ||
1324887Schin 	    GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, cbuf, sizeof(cbuf)) <= 0)
1334887Schin 		return 0;
1344887Schin 	if (lc->charset->ms)
1354887Schin 		sfsprintf(buf, siz, "%s_%s.%s", lbuf, cbuf, lc->charset->ms);
1364887Schin 	else
1374887Schin 		sfsprintf(buf, siz, "%s_%s", lbuf, cbuf);
1384887Schin 	return buf;
1394887Schin }
1404887Schin 
1414887Schin /*
1424887Schin  * locale!=0 here
1434887Schin  */
1444887Schin 
1454887Schin static char*
native_setlocale(int category,const char * locale)1464887Schin native_setlocale(int category, const char* locale)
1474887Schin {
1484887Schin 	char*		usr;
1494887Schin 	char*		sys;
1504887Schin 	char		buf[256];
1514887Schin 
15210898Sroland.mainz@nrubsig.org 	if (!(usr = native_locale(locale, buf, sizeof(buf))))
15310898Sroland.mainz@nrubsig.org 		return 0;
15410898Sroland.mainz@nrubsig.org 
1554887Schin 	/*
1564887Schin 	 * win32 doesn't have LC_MESSAGES
1574887Schin 	 */
1584887Schin 
1594887Schin 	if (category == LC_MESSAGES)
1604887Schin 		return (char*)locale;
1614887Schin 	sys = uwin_setlocale(category, usr);
1624887Schin 	if (ast.locale.set & AST_LC_debug)
1638462SApril.Chin@Sun.COM 		sfprintf(sfstderr, "locale uwin %17s %-24s %-24s\n", lc_categories[lcindex(category, 0)].name, usr, sys);
1644887Schin 	return sys;
1654887Schin }
1664887Schin 
1674887Schin #else
1684887Schin 
1694887Schin #define native_locale(a,b,c)	((char*)0)
1704887Schin 
1714887Schin #endif
1724887Schin 
1734887Schin /*
1744887Schin  * LC_COLLATE and LC_CTYPE native support
1754887Schin  */
1764887Schin 
1774887Schin #if !_lib_mbtowc || MB_LEN_MAX <= 1
1784887Schin #define mblen		0
1794887Schin #define mbtowc		0
1804887Schin #endif
1814887Schin 
1824887Schin #if !_lib_strcoll
1834887Schin #define	strcoll		0
1844887Schin #endif
1854887Schin 
1864887Schin #if !_lib_strxfrm
1874887Schin #define	strxfrm		0
1884887Schin #endif
1894887Schin 
1904887Schin /*
1914887Schin  * LC_COLLATE and LC_CTYPE debug support
1924887Schin  *
1934887Schin  * mutibyte debug encoding
1944887Schin  *
1954887Schin  *	DL0 [ '0' .. '4' ] c1 ... c4 DR0
1964887Schin  *	DL1 [ '0' .. '4' ] c1 ... c4 DR1
1974887Schin  *
1984887Schin  * with these ligatures
1994887Schin  *
2004887Schin  *	ch CH sst SST
2014887Schin  *
2024887Schin  * and private collation order
2034887Schin  *
2044887Schin  * wide character display width is the low order 3 bits
2054887Schin  * wctomb() uses DL1...DR1
2064887Schin  */
2074887Schin 
2084887Schin #define DEBUG_MB_CUR_MAX	7
2094887Schin 
2104887Schin #if DEBUG_MB_CUR_MAX < MB_LEN_MAX
2114887Schin #undef	DEBUG_MB_CUR_MAX
2124887Schin #define DEBUG_MB_CUR_MAX	MB_LEN_MAX
2134887Schin #endif
2144887Schin 
2154887Schin #define DL0	'<'
2164887Schin #define DL1	0xab		/* 8-bit mini << on xterm	*/
2174887Schin #define DR0	'>'
2184887Schin #define DR1	0xbb		/* 8-bit mini >> on xterm	*/
2194887Schin 
2204887Schin #define DB	((int)sizeof(wchar_t)*8-1)
2214887Schin #define DC	7		/* wchar_t embedded char bits	*/
2224887Schin #define DX	(DB/DC)		/* wchar_t max embedded chars	*/
2234887Schin #define DZ	(DB-DX*DC+1)	/* wchar_t embedded size bits	*/
2244887Schin #define DD	3		/* # mb delimiter chars <n...>	*/
2254887Schin 
2264887Schin static unsigned char debug_order[] =
2274887Schin {
2284887Schin 	  0,   1,   2,   3,   4,   5,   6,   7,
2294887Schin 	  8,   9,  10,  11,  12,  13,  14,  15,
2304887Schin 	 16,  17,  18,  19,  20,  21,  22,  23,
2314887Schin 	 24,  25,  26,  27,  28,  29,  30,  31,
2324887Schin 	 99, 100, 101, 102,  98, 103, 104, 105,
2334887Schin 	106, 107, 108,  43, 109,  44,  42, 110,
2344887Schin 	 32,  33,  34,  35,  36,  37,  38,  39,
2354887Schin 	 40,  41, 111, 112, 113, 114, 115, 116,
2364887Schin 	117,  71,  72,  73,  74,  75,  76,  77,
2374887Schin 	 78,  79,  80,  81,  82,  83,  84,  85,
2384887Schin 	 86,  87,  88,  89,  90,  91,  92,  93,
2394887Schin 	 94,  95,  96, 118, 119, 120, 121,  97,
2404887Schin 	122,  45,  46,  47,  48,  49,  50,  51,
2414887Schin 	 52,  53,  54,  55,  56,  57,  58,  59,
2424887Schin 	 60,  61,  62,  63,  64,  65,  66,  67,
2434887Schin 	 68,  69,  70, 123, 124, 125, 126, 127,
2444887Schin 	128, 129, 130, 131, 132, 133, 134, 135,
2454887Schin 	136, 137, 138, 139, 140, 141, 142, 143,
2464887Schin 	144, 145, 146, 147, 148, 149, 150, 151,
2474887Schin 	152, 153, 154, 155, 156, 157, 158, 159,
2484887Schin 	160, 161, 162, 163, 164, 165, 166, 167,
2494887Schin 	168, 169, 170, 171, 172, 173, 174, 175,
2504887Schin 	176, 177, 178, 179, 180, 181, 182, 183,
2514887Schin 	184, 185, 186, 187, 188, 189, 190, 191,
2524887Schin 	192, 193, 194, 195, 196, 197, 198, 199,
2534887Schin 	200, 201, 202, 203, 204, 205, 206, 207,
2544887Schin 	208, 209, 210, 211, 212, 213, 214, 215,
2554887Schin 	216, 217, 218, 219, 220, 221, 222, 223,
2564887Schin 	224, 225, 226, 227, 228, 229, 230, 231,
2574887Schin 	232, 233, 234, 235, 236, 237, 238, 239,
2584887Schin 	240, 241, 242, 243, 244, 245, 246, 247,
2594887Schin 	248, 249, 250, 251, 252, 253, 254, 255,
2604887Schin };
2614887Schin 
2624887Schin static int
debug_mbtowc(register wchar_t * p,register const char * s,size_t n)2634887Schin debug_mbtowc(register wchar_t* p, register const char* s, size_t n)
2644887Schin {
2654887Schin 	register const char*	q;
2664887Schin 	register const char*	r;
2674887Schin 	register int		w;
2684887Schin 	register int		dr;
2694887Schin 	wchar_t			c;
2704887Schin 
2714887Schin 	if (n < 1)
2724887Schin 		return -1;
2734887Schin 	if (!s || !*s)
2744887Schin 		return 0;
2754887Schin 	switch (((unsigned char*)s)[0])
2764887Schin 	{
2774887Schin 	case DL0:
2784887Schin 		dr = DR0;
2794887Schin 		break;
2804887Schin 	case DL1:
2814887Schin 		dr = DR1;
2824887Schin 		break;
2834887Schin 	default:
2844887Schin 		if (p)
2854887Schin 			*p = ((unsigned char*)s)[0] & ((1<<DC)-1);
2864887Schin 		return 1;
2874887Schin 	}
2884887Schin 	if (n < 2)
2894887Schin 		return -1;
2904887Schin 	if ((w = ((unsigned char*)s)[1]) == ((unsigned char*)s)[0])
2914887Schin 	{
2924887Schin 		if (p)
2934887Schin 			*p = w;
2944887Schin 		return 2;
2954887Schin 	}
2964887Schin 	if (w < '0' || w > ('0' + DX))
2974887Schin 		return -1;
2984887Schin 	if ((w -= '0' - DD) > n)
2994887Schin 		return -1;
3004887Schin 	r = s + w - 1;
3014887Schin 	q = s += 2;
3024887Schin 	while (q < r && *q)
3034887Schin 		q++;
3044887Schin 	if (q != r || *((unsigned char*)q) != dr)
3054887Schin 		return -1;
3064887Schin 	if (p)
3074887Schin 	{
3084887Schin 		c = 0;
3094887Schin 		while (--q >= s)
3104887Schin 		{
3114887Schin 			c <<= DC;
3124887Schin 			c |= *((unsigned char*)q);
3134887Schin 		}
3144887Schin 		c <<= DZ;
3154887Schin 		c |= w - DD;
3164887Schin 		*p = c;
3174887Schin 	}
3184887Schin 	return w;
3194887Schin }
3204887Schin 
3214887Schin static int
debug_wctomb(char * s,wchar_t c)3224887Schin debug_wctomb(char* s, wchar_t c)
3234887Schin {
3244887Schin 	int	w;
3254887Schin 	int	i;
3264887Schin 	int	k;
3274887Schin 
3284887Schin 	w = 0;
3294887Schin 	if (c >= 0 && c <= UCHAR_MAX)
3304887Schin 	{
3314887Schin 		w++;
3324887Schin 		if (s)
3334887Schin 			*s = c;
3344887Schin 	}
3354887Schin 	else if ((i = c & ((1<<DZ)-1)) > DX)
3364887Schin 		return -1;
3374887Schin 	else
3384887Schin 	{
3394887Schin 		w++;
3404887Schin 		if (s)
3414887Schin 			*s++ = DL1;
3424887Schin 		c >>= DZ;
3434887Schin 		w++;
3444887Schin 		if (s)
3454887Schin 			*s++ = i + '0';
3464887Schin 		while (i--)
3474887Schin 		{
3484887Schin 			w++;
3494887Schin 			if (s)
3504887Schin 				*s++ = (k = c & ((1<<DC)-1)) ? k : '?';
3514887Schin 			c >>= DC;
3524887Schin 		}
3534887Schin 		w++;
3544887Schin 		if (s)
3554887Schin 			*s++ = DR1;
3564887Schin 	}
3574887Schin 	return w;
3584887Schin }
3594887Schin 
3604887Schin static int
debug_mblen(const char * s,size_t n)3614887Schin debug_mblen(const char* s, size_t n)
3624887Schin {
3634887Schin 	return debug_mbtowc(NiL, s, n);
3644887Schin }
3654887Schin 
3664887Schin static int
debug_wcwidth(wchar_t c)3674887Schin debug_wcwidth(wchar_t c)
3684887Schin {
3694887Schin 	if (c >= 0 && c <= UCHAR_MAX)
3704887Schin 		return 1;
3714887Schin 	if ((c &= ((1<<DZ)-1)) > DX)
3724887Schin 		return -1;
3734887Schin 	return c + DD;
3744887Schin }
3754887Schin 
3764887Schin static size_t
debug_strxfrm(register char * t,register const char * s,size_t n)3774887Schin debug_strxfrm(register char* t, register const char* s, size_t n)
3784887Schin {
3794887Schin 	register const char*	q;
3804887Schin 	register const char*	r;
3814887Schin 	register char*		e;
3828462SApril.Chin@Sun.COM 	char*			o;
3834887Schin 	register size_t		z;
3844887Schin 	register int		w;
3854887Schin 
3868462SApril.Chin@Sun.COM 	o = t;
3874887Schin 	z = 0;
3884887Schin 	if (e = t)
3894887Schin 		e += n;
3904887Schin 	while (s[0])
3914887Schin 	{
3924887Schin 		if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC))
3934887Schin 		{
3944887Schin 			w -= '0';
3954887Schin 			q = s + 2;
3964887Schin 			r = q + w;
3974887Schin 			while (q < r && *q)
3984887Schin 				q++;
3994887Schin 			if (*((unsigned char*)q) == DR0 || *((unsigned char*)q) == DR1)
4004887Schin 			{
4014887Schin 				if (t)
4024887Schin 				{
4034887Schin 					for (q = s + 2; q < r; q++)
4044887Schin 						if (t < e)
4054887Schin 							*t++ = debug_order[*q];
4064887Schin 					while (w++ < DX)
4074887Schin 						if (t < e)
4084887Schin 							*t++ = 1;
4094887Schin 				}
4104887Schin 				s = r + 1;
4114887Schin 				z += DX;
4124887Schin 				continue;
4134887Schin 			}
4144887Schin 		}
4154887Schin 		if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H'))
4164887Schin 		{
4174887Schin 			if (t)
4184887Schin 			{
4194887Schin 				if (t < e)
4204887Schin 					*t++ = debug_order[s[0]];
4214887Schin 				if (t < e)
4224887Schin 					*t++ = debug_order[s[1]];
4234887Schin 				if (t < e)
4244887Schin 					*t++ = 1;
4254887Schin 				if (t < e)
4264887Schin 					*t++ = 1;
4274887Schin 			}
4284887Schin 			s += 2;
4294887Schin 			z += DX;
4304887Schin 			continue;
4314887Schin 		}
4324887Schin 		if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T'))
4334887Schin 		{
4344887Schin 			if (t)
4354887Schin 			{
4364887Schin 				if (t < e)
4374887Schin 					*t++ = debug_order[s[0]];
4384887Schin 				if (t < e)
4394887Schin 					*t++ = debug_order[s[1]];
4404887Schin 				if (t < e)
4414887Schin 					*t++ = debug_order[s[2]];
4424887Schin 				if (t < e)
4434887Schin 					*t++ = 1;
4444887Schin 			}
4454887Schin 			s += 3;
4464887Schin 			z += DX;
4474887Schin 			continue;
4484887Schin 		}
4494887Schin 		if (t)
4504887Schin 		{
4514887Schin 			if (t < e)
4524887Schin 				*t++ = debug_order[s[0]];
4534887Schin 			if (t < e)
4544887Schin 				*t++ = 1;
4554887Schin 			if (t < e)
4564887Schin 				*t++ = 1;
4574887Schin 			if (t < e)
4584887Schin 				*t++ = 1;
4594887Schin 		}
4604887Schin 		s++;
4614887Schin 		z += DX;
4624887Schin 	}
4638462SApril.Chin@Sun.COM 	if (!t)
4648462SApril.Chin@Sun.COM 		return z;
4654887Schin 	if (t < e)
4664887Schin 		*t = 0;
4678462SApril.Chin@Sun.COM 	return t - o;
4684887Schin }
4694887Schin 
4704887Schin static int
debug_strcoll(const char * a,const char * b)4714887Schin debug_strcoll(const char* a, const char* b)
4724887Schin {
4734887Schin 	char	ab[1024];
4744887Schin 	char	bb[1024];
4754887Schin 
4764887Schin 	debug_strxfrm(ab, a, sizeof(ab) - 1);
4774887Schin 	ab[sizeof(ab)-1] = 0;
4784887Schin 	debug_strxfrm(bb, b, sizeof(bb) - 1);
4794887Schin 	bb[sizeof(bb)-1] = 0;
4804887Schin 	return strcmp(ab, bb);
4814887Schin }
4824887Schin 
4834887Schin /*
4844887Schin  * default locale
4854887Schin  */
4864887Schin 
4874887Schin static int
default_wcwidth(wchar_t w)4884887Schin default_wcwidth(wchar_t w)
4894887Schin {
4904887Schin 	return w >= 0 && w <= 255 && !iscntrl(w) ? 1 : -1;
4914887Schin }
4924887Schin 
4934887Schin /*
4944887Schin  * called when LC_COLLATE initialized or changes
4954887Schin  */
4964887Schin 
4974887Schin static int
set_collate(Lc_category_t * cp)4984887Schin set_collate(Lc_category_t* cp)
4994887Schin {
5004887Schin 	if (locales[cp->internal]->flags & LC_debug)
5014887Schin 	{
5024887Schin 		ast.collate = debug_strcoll;
5034887Schin 		ast.mb_xfrm = debug_strxfrm;
5044887Schin 	}
5054887Schin 	else if (locales[cp->internal]->flags & LC_default)
5064887Schin 	{
5074887Schin 		ast.collate = strcmp;
5084887Schin 		ast.mb_xfrm = 0;
5094887Schin 	}
5104887Schin 	else
5114887Schin 	{
5124887Schin 		ast.collate = strcoll;
5134887Schin 		ast.mb_xfrm = strxfrm;
5144887Schin 	}
5154887Schin 	return 0;
5164887Schin }
5174887Schin 
5184887Schin /*
5198462SApril.Chin@Sun.COM  * workaround the interesting sjis that translates unshifted 7 bit ascii!
5208462SApril.Chin@Sun.COM  */
5218462SApril.Chin@Sun.COM 
5228462SApril.Chin@Sun.COM #if _hdr_wchar && _typ_mbstate_t && _lib_mbrtowc
5238462SApril.Chin@Sun.COM 
5248462SApril.Chin@Sun.COM #define mb_state_zero	((mbstate_t*)&ast.pad[sizeof(ast.pad)-2*sizeof(mbstate_t)])
5258462SApril.Chin@Sun.COM #define mb_state	((mbstate_t*)&ast.pad[sizeof(ast.pad)-sizeof(mbstate_t)])
5268462SApril.Chin@Sun.COM 
5278462SApril.Chin@Sun.COM static int
sjis_mbtowc(register wchar_t * p,register const char * s,size_t n)5288462SApril.Chin@Sun.COM sjis_mbtowc(register wchar_t* p, register const char* s, size_t n)
5298462SApril.Chin@Sun.COM {
5308462SApril.Chin@Sun.COM 	if (n && p && s && (*s == '\\' || *s == '~') && !memcmp(mb_state, mb_state_zero, sizeof(mbstate_t)))
5318462SApril.Chin@Sun.COM 	{
5328462SApril.Chin@Sun.COM 		*p = *s;
5338462SApril.Chin@Sun.COM 		return 1;
5348462SApril.Chin@Sun.COM 	}
5358462SApril.Chin@Sun.COM 	return mbrtowc(p, s, n, mb_state);
5368462SApril.Chin@Sun.COM }
5378462SApril.Chin@Sun.COM 
5388462SApril.Chin@Sun.COM #endif
5398462SApril.Chin@Sun.COM 
54010898Sroland.mainz@nrubsig.org #define utf8_wctomb	wctomb
54110898Sroland.mainz@nrubsig.org 
54210898Sroland.mainz@nrubsig.org static const uint32_t		utf8mask[] =
54310898Sroland.mainz@nrubsig.org {
54410898Sroland.mainz@nrubsig.org 	0x00000000,
54510898Sroland.mainz@nrubsig.org 	0x00000000,
54610898Sroland.mainz@nrubsig.org 	0xffffff80,
54710898Sroland.mainz@nrubsig.org 	0xfffff800,
54810898Sroland.mainz@nrubsig.org 	0xffff0000,
54910898Sroland.mainz@nrubsig.org 	0xffe00000,
55010898Sroland.mainz@nrubsig.org 	0xfc000000,
55110898Sroland.mainz@nrubsig.org };
55210898Sroland.mainz@nrubsig.org 
55310898Sroland.mainz@nrubsig.org static const signed char	utf8tab[256] =
55410898Sroland.mainz@nrubsig.org {
55510898Sroland.mainz@nrubsig.org 	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55610898Sroland.mainz@nrubsig.org 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55710898Sroland.mainz@nrubsig.org 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55810898Sroland.mainz@nrubsig.org 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55910898Sroland.mainz@nrubsig.org 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56010898Sroland.mainz@nrubsig.org 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56110898Sroland.mainz@nrubsig.org 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56210898Sroland.mainz@nrubsig.org 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56310898Sroland.mainz@nrubsig.org 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56410898Sroland.mainz@nrubsig.org 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56510898Sroland.mainz@nrubsig.org 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56610898Sroland.mainz@nrubsig.org 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56710898Sroland.mainz@nrubsig.org 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56810898Sroland.mainz@nrubsig.org 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56910898Sroland.mainz@nrubsig.org 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
57010898Sroland.mainz@nrubsig.org 	4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,-1,-1,
57110898Sroland.mainz@nrubsig.org };
57210898Sroland.mainz@nrubsig.org 
57310898Sroland.mainz@nrubsig.org static int
utf8_mbtowc(wchar_t * wp,const char * str,size_t n)57410898Sroland.mainz@nrubsig.org utf8_mbtowc(wchar_t* wp, const char* str, size_t n)
57510898Sroland.mainz@nrubsig.org {
57610898Sroland.mainz@nrubsig.org 	register unsigned char*	sp = (unsigned char*)str;
57710898Sroland.mainz@nrubsig.org 	register int		m;
57810898Sroland.mainz@nrubsig.org 	register int		i;
57910898Sroland.mainz@nrubsig.org 	register int		c;
58010898Sroland.mainz@nrubsig.org 	register wchar_t	w = 0;
58110898Sroland.mainz@nrubsig.org 
58210898Sroland.mainz@nrubsig.org 	if (!sp || !n)
58310898Sroland.mainz@nrubsig.org 		return 0;
58410898Sroland.mainz@nrubsig.org 	if ((m = utf8tab[*sp]) > 0)
58510898Sroland.mainz@nrubsig.org 	{
58610898Sroland.mainz@nrubsig.org 		if (m > n)
58710898Sroland.mainz@nrubsig.org 			return -1;
58810898Sroland.mainz@nrubsig.org 		if (wp)
58910898Sroland.mainz@nrubsig.org 		{
59010898Sroland.mainz@nrubsig.org 			if (m == 1)
59110898Sroland.mainz@nrubsig.org 			{
59210898Sroland.mainz@nrubsig.org 				*wp = *sp;
59310898Sroland.mainz@nrubsig.org 				return 1;
59410898Sroland.mainz@nrubsig.org 			}
59510898Sroland.mainz@nrubsig.org 			w = *sp & ((1<<(8-m))-1);
59610898Sroland.mainz@nrubsig.org 			for (i = m - 1; i > 0; i--)
59710898Sroland.mainz@nrubsig.org 			{
59810898Sroland.mainz@nrubsig.org 				c = *++sp;
59910898Sroland.mainz@nrubsig.org 				if ((c&0xc0) != 0x80)
60010898Sroland.mainz@nrubsig.org 					goto invalid;
60110898Sroland.mainz@nrubsig.org 				w = (w<<6) | (c&0x3f);
60210898Sroland.mainz@nrubsig.org 			}
60310898Sroland.mainz@nrubsig.org 			if (!(utf8mask[m] & w) || w >= 0xd800 && (w <= 0xdfff || w >= 0xfffe && w <= 0xffff))
60410898Sroland.mainz@nrubsig.org 				goto invalid;
60510898Sroland.mainz@nrubsig.org 			*wp = w;
60610898Sroland.mainz@nrubsig.org 		}
60710898Sroland.mainz@nrubsig.org 		return m;
60810898Sroland.mainz@nrubsig.org 	}
60910898Sroland.mainz@nrubsig.org 	if (!*sp)
61010898Sroland.mainz@nrubsig.org 		return 0;
61110898Sroland.mainz@nrubsig.org  invalid:
61210898Sroland.mainz@nrubsig.org #ifdef EILSEQ
61310898Sroland.mainz@nrubsig.org 	errno = EILSEQ;
61410898Sroland.mainz@nrubsig.org #endif
61510898Sroland.mainz@nrubsig.org 	ast.mb_sync = (const char*)sp - str;
61610898Sroland.mainz@nrubsig.org 	return -1;
61710898Sroland.mainz@nrubsig.org }
61810898Sroland.mainz@nrubsig.org 
61910898Sroland.mainz@nrubsig.org static int
utf8_mblen(const char * str,size_t n)62010898Sroland.mainz@nrubsig.org utf8_mblen(const char* str, size_t n)
62110898Sroland.mainz@nrubsig.org {
62210898Sroland.mainz@nrubsig.org 	wchar_t		w;
62310898Sroland.mainz@nrubsig.org 
62410898Sroland.mainz@nrubsig.org 	return utf8_mbtowc(&w, str, n);
62510898Sroland.mainz@nrubsig.org }
62610898Sroland.mainz@nrubsig.org 
6278462SApril.Chin@Sun.COM /*
6284887Schin  * called when LC_CTYPE initialized or changes
6294887Schin  */
6304887Schin 
6314887Schin static int
set_ctype(Lc_category_t * cp)6324887Schin set_ctype(Lc_category_t* cp)
6334887Schin {
63410898Sroland.mainz@nrubsig.org 	ast.mb_sync = 0;
6354887Schin 	if (locales[cp->internal]->flags & LC_debug)
6364887Schin 	{
6374887Schin 		ast.mb_cur_max = DEBUG_MB_CUR_MAX;
6384887Schin 		ast.mb_len = debug_mblen;
6394887Schin 		ast.mb_towc = debug_mbtowc;
6404887Schin 		ast.mb_width = debug_wcwidth;
6414887Schin 		ast.mb_conv = debug_wctomb;
6424887Schin 	}
6434887Schin 	else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc))
6444887Schin 	{
6454887Schin 		ast.mb_cur_max = 1;
6464887Schin 		ast.mb_len = 0;
6474887Schin 		ast.mb_towc = 0;
6484887Schin 		ast.mb_width = default_wcwidth;
6494887Schin 		ast.mb_conv = 0;
6504887Schin 	}
65110898Sroland.mainz@nrubsig.org 	else if ((locales[cp->internal]->flags & LC_utf8) && !(ast.locale.set & AST_LC_test))
65210898Sroland.mainz@nrubsig.org 	{
65310898Sroland.mainz@nrubsig.org 		ast.mb_cur_max = 6;
65410898Sroland.mainz@nrubsig.org 		ast.mb_len = utf8_mblen;
65510898Sroland.mainz@nrubsig.org 		ast.mb_towc = utf8_mbtowc;
65610898Sroland.mainz@nrubsig.org 		if (!(ast.mb_width = wcwidth))
65710898Sroland.mainz@nrubsig.org 			ast.mb_width = default_wcwidth;
65810898Sroland.mainz@nrubsig.org 		ast.mb_conv = utf8_wctomb;
65910898Sroland.mainz@nrubsig.org 	}
6604887Schin 	else
6614887Schin 	{
6624887Schin 		if (!(ast.mb_width = wcwidth))
6634887Schin 			ast.mb_width = default_wcwidth;
6644887Schin 		ast.mb_conv = wctomb;
6658462SApril.Chin@Sun.COM #ifdef mb_state
6668462SApril.Chin@Sun.COM 		{
6678462SApril.Chin@Sun.COM 			/*
6688462SApril.Chin@Sun.COM 			 * check for sjis that translates unshifted 7 bit ascii!
6698462SApril.Chin@Sun.COM 			 */
6708462SApril.Chin@Sun.COM 
6718462SApril.Chin@Sun.COM 			char*	s;
6728462SApril.Chin@Sun.COM 			char	buf[2];
6738462SApril.Chin@Sun.COM 
6748462SApril.Chin@Sun.COM 			mbinit();
6758462SApril.Chin@Sun.COM 			buf[1] = 0;
6768462SApril.Chin@Sun.COM 			*(s = buf) = '\\';
6778462SApril.Chin@Sun.COM 			if (mbchar(s) != buf[0])
6788462SApril.Chin@Sun.COM 			{
6798462SApril.Chin@Sun.COM 				memcpy(mb_state, mb_state_zero, sizeof(mbstate_t));
6808462SApril.Chin@Sun.COM 				ast.mb_towc = sjis_mbtowc;
6818462SApril.Chin@Sun.COM 			}
6828462SApril.Chin@Sun.COM 		}
6838462SApril.Chin@Sun.COM #endif
6844887Schin 	}
68510898Sroland.mainz@nrubsig.org 	if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
68610898Sroland.mainz@nrubsig.org 		sfprintf(sfstderr, "locale info %17s MB_CUR_MAX=%d%s%s%s%s\n"
68710898Sroland.mainz@nrubsig.org 			, cp->name
68810898Sroland.mainz@nrubsig.org 			, ast.mb_cur_max
68910898Sroland.mainz@nrubsig.org 			, ast.mb_len == debug_mblen ? " debug_mblen" : ast.mb_len == mblen ? " mblen" : ""
69010898Sroland.mainz@nrubsig.org 			, ast.mb_towc == debug_mbtowc ? " debug_mbtowc" : ast.mb_towc == mbtowc ? " mbtowc"
69110898Sroland.mainz@nrubsig.org #ifdef mb_state
69210898Sroland.mainz@nrubsig.org 				: ast.mb_towc == sjis_mbtowc ? " sjis_mbtowc"
69310898Sroland.mainz@nrubsig.org #endif
69410898Sroland.mainz@nrubsig.org 				: ""
69510898Sroland.mainz@nrubsig.org 			, ast.mb_width == debug_wcwidth ? " debug_wcwidth" : ast.mb_width == wcwidth ? " wcwidth" : ast.mb_width == default_wcwidth ? " default_wcwidth" : ""
69610898Sroland.mainz@nrubsig.org 			, ast.mb_conv == debug_wctomb ? " debug_wctomb" : ast.mb_conv == wctomb ? " wctomb" : ""
69710898Sroland.mainz@nrubsig.org 			);
6984887Schin 	return 0;
6994887Schin }
7004887Schin 
7014887Schin /*
7024887Schin  * called when LC_NUMERIC initialized or changes
7034887Schin  */
7044887Schin 
7054887Schin static int
set_numeric(Lc_category_t * cp)7064887Schin set_numeric(Lc_category_t* cp)
7074887Schin {
7084887Schin 	register int		category = cp->internal;
7094887Schin 	struct lconv*		lp;
7104887Schin 	Lc_numeric_t*		dp;
7114887Schin 
7124887Schin 	static Lc_numeric_t	default_numeric = { '.', -1 };
7134887Schin 
7144887Schin 	if (!LCINFO(category)->data)
7154887Schin 	{
7164887Schin 		if ((lp = localeconv()) && (dp = newof(0, Lc_numeric_t, 1, 0)))
7174887Schin 		{
7184887Schin 			dp->decimal = lp->decimal_point && *lp->decimal_point ? *(unsigned char*)lp->decimal_point : '.';
7194887Schin 			dp->thousand = lp->thousands_sep && *lp->thousands_sep ? *(unsigned char*)lp->thousands_sep : -1;
7204887Schin 		}
7214887Schin 		else
7224887Schin 			dp = &default_numeric;
7234887Schin 		LCINFO(category)->data = (void*)dp;
7244887Schin 		if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
7258462SApril.Chin@Sun.COM 			sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", lc_categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X');
7264887Schin 	}
7274887Schin 	return 0;
7284887Schin }
7294887Schin 
7304887Schin /*
7314887Schin  * this table is indexed by AST_LC_[A-Z]*
7324887Schin  */
7334887Schin 
7348462SApril.Chin@Sun.COM Lc_category_t		lc_categories[] =
7354887Schin {
7364887Schin { "LC_ALL",           LC_ALL,           AST_LC_ALL,           0               },
7374887Schin { "LC_COLLATE",       LC_COLLATE,       AST_LC_COLLATE,       set_collate     },
7384887Schin { "LC_CTYPE",         LC_CTYPE,         AST_LC_CTYPE,         set_ctype       },
7394887Schin { "LC_MESSAGES",      LC_MESSAGES,      AST_LC_MESSAGES,      0               },
7404887Schin { "LC_MONETARY",      LC_MONETARY,      AST_LC_MONETARY,      0               },
7414887Schin { "LC_NUMERIC",       LC_NUMERIC,       AST_LC_NUMERIC,       set_numeric     },
7424887Schin { "LC_TIME",          LC_TIME,          AST_LC_TIME,          0               },
7434887Schin { "LC_IDENTIFICATION",LC_IDENTIFICATION,AST_LC_IDENTIFICATION,0               },
7444887Schin { "LC_ADDRESS",       LC_ADDRESS,       AST_LC_ADDRESS,       0               },
7454887Schin { "LC_NAME",          LC_NAME,          AST_LC_NAME,          0               },
7464887Schin { "LC_TELEPHONE",     LC_TELEPHONE,     AST_LC_TELEPHONE,     0               },
7474887Schin { "LC_XLITERATE",     LC_XLITERATE,     AST_LC_XLITERATE,     0               },
7484887Schin { "LC_MEASUREMENT",   LC_MEASUREMENT,   AST_LC_MEASUREMENT,   0               },
7494887Schin { "LC_PAPER",         LC_PAPER,         AST_LC_PAPER,         0               },
7504887Schin };
7514887Schin 
75210898Sroland.mainz@nrubsig.org static Lc_t*		lang;
75310898Sroland.mainz@nrubsig.org static Lc_t*		lc_all;
75410898Sroland.mainz@nrubsig.org 
75510898Sroland.mainz@nrubsig.org typedef struct Unamval_s
75610898Sroland.mainz@nrubsig.org {
75710898Sroland.mainz@nrubsig.org 	char*		name;
75810898Sroland.mainz@nrubsig.org 	unsigned int	value;
75910898Sroland.mainz@nrubsig.org } Unamval_t;
76010898Sroland.mainz@nrubsig.org 
76110898Sroland.mainz@nrubsig.org static const Unamval_t	options[] =
7624887Schin {
7634887Schin 	"debug",		AST_LC_debug,
7644887Schin 	"find",			AST_LC_find,
7654887Schin 	"setlocale",		AST_LC_setlocale,
76610898Sroland.mainz@nrubsig.org 	"test",			AST_LC_test,
7674887Schin 	"translate",		AST_LC_translate,
7684887Schin 	0,			0
7694887Schin };
7704887Schin 
7714887Schin /*
7724887Schin  * called by stropt() to set options
7734887Schin  */
7744887Schin 
7754887Schin static int
setopt(void * a,const void * p,int n,const char * v)7764887Schin setopt(void* a, const void* p, int n, const char* v)
7774887Schin {
7784887Schin 	if (p)
7794887Schin 	{
7804887Schin 		if (n)
78110898Sroland.mainz@nrubsig.org 			ast.locale.set |= ((Unamval_t*)p)->value;
7824887Schin 		else
78310898Sroland.mainz@nrubsig.org 			ast.locale.set &= ~((Unamval_t*)p)->value;
7844887Schin 	}
7854887Schin 	return 0;
7864887Schin }
7874887Schin 
7884887Schin #if !_lib_setlocale
7894887Schin 
7904887Schin #define setlocale(c,l)		default_setlocale(c,l)
7914887Schin 
7924887Schin static char*
default_setlocale(int category,const char * locale)7934887Schin default_setlocale(int category, const char* locale)
7944887Schin {
7954887Schin 	Lc_t*		lc;
7964887Schin 
7974887Schin 	if (locale)
7984887Schin 	{
7994887Schin 		if (!(lc = lcmake(locale)) || !(lc->flags & LC_default))
8004887Schin 			return 0;
8014887Schin 		locales[0]->flags &= ~lc->flags;
8024887Schin 		locales[1]->flags &= ~lc->flags;
8034887Schin 		return lc->name;
8044887Schin 	}
8054887Schin 	return (locales[1]->flags & (1<<category)) ? locales[1]->name : locales[0]->name;
8064887Schin }
8074887Schin 
8084887Schin #endif
8094887Schin 
8104887Schin /*
8114887Schin  * set a single AST_LC_* locale category
8124887Schin  * the caller must validate category
8134887Schin  * lc==0 restores the previous state
8144887Schin  */
8154887Schin 
8164887Schin static char*
single(int category,Lc_t * lc,unsigned int flags)817*12068SRoger.Faulkner@Oracle.COM single(int category, Lc_t* lc, unsigned int flags)
8184887Schin {
8194887Schin 	const char*	sys;
8204887Schin 	int		i;
8214887Schin 
822*12068SRoger.Faulkner@Oracle.COM 	if (flags & (LC_setenv|LC_setlocale))
823*12068SRoger.Faulkner@Oracle.COM 	{
824*12068SRoger.Faulkner@Oracle.COM 		if (!(ast.locale.set & AST_LC_internal))
825*12068SRoger.Faulkner@Oracle.COM 			lc_categories[category].prev = lc;
826*12068SRoger.Faulkner@Oracle.COM 		if ((flags & LC_setenv) && lc_all && locales[category])
827*12068SRoger.Faulkner@Oracle.COM 			return (char*)locales[category]->name;
828*12068SRoger.Faulkner@Oracle.COM 	}
829*12068SRoger.Faulkner@Oracle.COM 	if (!lc && (!(lc_categories[category].flags & LC_setlocale) || !(lc = lc_categories[category].prev)) && !(lc = lc_all) && !(lc = lc_categories[category].prev) && !(lc = lang))
8304887Schin 		lc = lcmake(NiL);
831*12068SRoger.Faulkner@Oracle.COM 	sys = 0;
8324887Schin 	if (locales[category] != lc)
8334887Schin 	{
8348462SApril.Chin@Sun.COM 		if (lc_categories[category].external == -lc_categories[category].internal)
8354887Schin 		{
8364887Schin 			for (i = 1; i < AST_LC_COUNT; i++)
8374887Schin 				if (locales[i] == lc)
8384887Schin 				{
8394887Schin 					sys = (char*)lc->name;
8404887Schin 					break;
8414887Schin 				}
8424887Schin 		}
8434887Schin 		else if (lc->flags & (LC_debug|LC_local))
8448462SApril.Chin@Sun.COM 			sys = setlocale(lc_categories[category].external, lcmake(NiL)->name);
8458462SApril.Chin@Sun.COM 		else if (!(sys = setlocale(lc_categories[category].external, lc->name)) &&
8468462SApril.Chin@Sun.COM 			 (streq(lc->name, lc->code) || !(sys = setlocale(lc_categories[category].external, lc->code))) &&
8474887Schin 			 !streq(lc->code, lc->language->code))
8488462SApril.Chin@Sun.COM 				sys = setlocale(lc_categories[category].external, lc->language->code);
8494887Schin 		if (!sys)
8504887Schin 		{
8514887Schin 			/*
8524887Schin 			 * check for local override
8534887Schin 			 * currently this means an LC_MESSAGES dir exists
8544887Schin 			 */
8554887Schin 
8564887Schin 			if (!(lc->flags & LC_checked))
8574887Schin 			{
8584887Schin 				char	path[PATH_MAX];
8594887Schin 
8604887Schin 				if (mcfind(path, lc->code, NiL, LC_MESSAGES, 0))
8614887Schin 					lc->flags |= LC_local;
8624887Schin 				lc->flags |= LC_checked;
8634887Schin 			}
8644887Schin 			if (!(lc->flags & LC_local))
8654887Schin 				return 0;
8668462SApril.Chin@Sun.COM 			if (lc_categories[category].external != -lc_categories[category].internal)
8678462SApril.Chin@Sun.COM 				setlocale(lc_categories[category].external, lcmake(NiL)->name);
8684887Schin 		}
8694887Schin 		locales[category] = lc;
8708462SApril.Chin@Sun.COM 		if (lc_categories[category].setf && (*lc_categories[category].setf)(&lc_categories[category]))
8714887Schin 		{
8728462SApril.Chin@Sun.COM 			locales[category] = lc_categories[category].prev;
8734887Schin 			return 0;
8744887Schin 		}
87510898Sroland.mainz@nrubsig.org 		if ((lc->flags & LC_default) || category == AST_LC_MESSAGES && lc->name[0] == 'e' && lc->name[1] == 'n' && (lc->name[2] == 0 || lc->name[2] == '_' && lc->name[3] == 'U'))
8764887Schin 			ast.locale.set &= ~(1<<category);
8774887Schin 		else
8784887Schin 			ast.locale.set |= (1<<category);
8794887Schin 	}
880*12068SRoger.Faulkner@Oracle.COM 	else if (lc_categories[category].flags ^ flags)
881*12068SRoger.Faulkner@Oracle.COM 	{
882*12068SRoger.Faulkner@Oracle.COM 		lc_categories[category].flags &= ~(LC_setenv|LC_setlocale);
883*12068SRoger.Faulkner@Oracle.COM 		lc_categories[category].flags |= flags;
884*12068SRoger.Faulkner@Oracle.COM 	}
885*12068SRoger.Faulkner@Oracle.COM 	else
886*12068SRoger.Faulkner@Oracle.COM 		return (char*)lc->name;
887*12068SRoger.Faulkner@Oracle.COM 	if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
888*12068SRoger.Faulkner@Oracle.COM 		sfprintf(sfstderr, "locale set  %17s %16s %16s %16s %s%s\n", lc_categories[category].name, lc->name, sys, lc_categories[category].prev ? lc_categories[category].prev->name : NiL, (lc_categories[category].flags & LC_setlocale) ? "[setlocale]" : "", (lc_categories[category].flags & LC_setenv) ? "[setenv]" : "");
8894887Schin 	return (char*)lc->name;
8904887Schin }
8914887Schin 
8924887Schin /*
8934887Schin  * set composite AST_LC_ALL locale categories
8944887Schin  * return <0:composite-error 0:not-composite >0:composite-ok
8954887Schin  */
8964887Schin 
8974887Schin static int
composite(register const char * s,int initialize)8984887Schin composite(register const char* s, int initialize)
8994887Schin {
9004887Schin 	register const char*	t;
9014887Schin 	register int		i;
9024887Schin 	register int		j;
9034887Schin 	register int		k;
9044887Schin 	int			n;
90510898Sroland.mainz@nrubsig.org 	int			m;
9064887Schin 	const char*		w;
9074887Schin 	Lc_t*			p;
9084887Schin 	int			cat[AST_LC_COUNT];
9094887Schin 	int			stk[AST_LC_COUNT];
9104887Schin 	char			buf[PATH_MAX / 2];
9114887Schin 
9124887Schin 	k = n = 0;
9134887Schin 	while (s[0] == 'L' && s[1] == 'C' && s[2] == '_')
9144887Schin 	{
9154887Schin 		n++;
9164887Schin 		j = 0;
9174887Schin 		w = s;
9184887Schin 		for (i = 1; i < AST_LC_COUNT; i++)
9194887Schin 		{
9204887Schin 			s = w;
9218462SApril.Chin@Sun.COM 			t = lc_categories[i].name;
9224887Schin 			while (*t && *s++ == *t++);
9234887Schin 			if (!*t && *s++ == '=')
9244887Schin 			{
9254887Schin 				cat[j++] = i;
9264887Schin 				if (s[0] != 'L' || s[1] != 'C' || s[2] != '_')
9274887Schin 					break;
9284887Schin 				w = s;
9294887Schin 				i = -1;
9304887Schin 			}
9314887Schin 		}
9324887Schin 		for (s = w; *s && *s != '='; s++);
9334887Schin 		if (!*s)
9344887Schin 		{
9354887Schin 			for (i = 0; i < k; i++)
936*12068SRoger.Faulkner@Oracle.COM 				single(stk[i], NiL, 0);
9374887Schin 			return -1;
9384887Schin 		}
9394887Schin 		w = ++s;
9404887Schin 		for (;;)
9414887Schin 		{
9424887Schin 			if (!*s)
9434887Schin 			{
9444887Schin 				p = lcmake(w);
9454887Schin 				break;
9464887Schin 			}
9474887Schin 			else if (*s++ == ';')
9484887Schin 			{
94910898Sroland.mainz@nrubsig.org 				if ((m = s - w - 1) >= sizeof(buf))
95010898Sroland.mainz@nrubsig.org 					m = sizeof(buf) - 1;
95110898Sroland.mainz@nrubsig.org 				memcpy(buf, w, m);
95210898Sroland.mainz@nrubsig.org 				buf[m] = 0;
9534887Schin 				p = lcmake(buf);
9544887Schin 				break;
9554887Schin 			}
9564887Schin 		}
9574887Schin 		for (i = 0; i < j; i++)
9584887Schin 			if (!initialize)
9594887Schin 			{
960*12068SRoger.Faulkner@Oracle.COM 				if (!single(cat[i], p, 0))
9614887Schin 				{
9624887Schin 					for (i = 0; i < k; i++)
963*12068SRoger.Faulkner@Oracle.COM 						single(stk[i], NiL, 0);
9644887Schin 					return -1;
9654887Schin 				}
9664887Schin 				stk[k++] = cat[i];
9674887Schin 			}
968*12068SRoger.Faulkner@Oracle.COM 			else if (!lc_categories[cat[i]].prev && !(ast.locale.set & AST_LC_internal))
9698462SApril.Chin@Sun.COM 				lc_categories[cat[i]].prev = p;
9704887Schin 	}
97110898Sroland.mainz@nrubsig.org 	while (s[0] == '/' && s[1] && n < (AST_LC_COUNT - 1))
9724887Schin 	{
9734887Schin 		n++;
9744887Schin 		for (w = ++s; *s && *s != '/'; s++);
9754887Schin 		if (!*s)
9764887Schin 			p = lcmake(w);
9774887Schin 		else
9784887Schin 		{
9794887Schin 			if ((j = s - w - 1) >= sizeof(buf))
9804887Schin 				j = sizeof(buf) - 1;
9814887Schin 			memcpy(buf, w, j);
9824887Schin 			buf[j] = 0;
9834887Schin 			p = lcmake(buf);
9844887Schin 		}
9854887Schin 		if (!initialize)
9864887Schin 		{
987*12068SRoger.Faulkner@Oracle.COM 			if (!single(n, p, 0))
9884887Schin 			{
9894887Schin 				for (i = 1; i < n; i++)
990*12068SRoger.Faulkner@Oracle.COM 					single(i, NiL, 0);
9914887Schin 				return -1;
9924887Schin 			}
9934887Schin 		}
994*12068SRoger.Faulkner@Oracle.COM 		else if (!lc_categories[n].prev && !(ast.locale.set & AST_LC_internal))
9958462SApril.Chin@Sun.COM 			lc_categories[n].prev = p;
9964887Schin 	}
9974887Schin 	return n;
9984887Schin }
9994887Schin 
10004887Schin /*
10014887Schin  * setlocale() intercept
100210898Sroland.mainz@nrubsig.org  *
100310898Sroland.mainz@nrubsig.org  * locale:
100410898Sroland.mainz@nrubsig.org  *	0	query
1005*12068SRoger.Faulkner@Oracle.COM  *	""	initialize from environment (if LC_ALL)
1006*12068SRoger.Faulkner@Oracle.COM  *	""	AST_LC_setenv: value unset (defer to LANG)
1007*12068SRoger.Faulkner@Oracle.COM  *	"*"	AST_LC_setenv: value set (defer to LC_ALL)
1008*12068SRoger.Faulkner@Oracle.COM  *	*	set (override LC_ALL)
10094887Schin  */
10104887Schin 
10114887Schin char*
_ast_setlocale(int category,const char * locale)10124887Schin _ast_setlocale(int category, const char* locale)
10134887Schin {
10144887Schin 	register char*		s;
10154887Schin 	register int		i;
10164887Schin 	register int		j;
10174887Schin 	int			k;
1018*12068SRoger.Faulkner@Oracle.COM 	int			f;
10194887Schin 	Lc_t*			p;
10204887Schin 	int			cat[AST_LC_COUNT];
10214887Schin 
10224887Schin 	static Sfio_t*		sp;
10234887Schin 	static int		initialized;
1024*12068SRoger.Faulkner@Oracle.COM 	static const char	local[] = "local";
10254887Schin 
10264887Schin 	if ((category = lcindex(category, 0)) < 0)
10274887Schin 		return 0;
10284887Schin 	if (!locale)
10294887Schin 	{
10304887Schin 		/*
10314887Schin 		 * return the current state
10324887Schin 		 */
10334887Schin 
10344887Schin 	compose:
103510898Sroland.mainz@nrubsig.org 		if (category != AST_LC_ALL && category != AST_LC_LANG)
10364887Schin 			return (char*)locales[category]->name;
10374887Schin 		if (!sp && !(sp = sfstropen()))
10384887Schin 			return 0;
10394887Schin 		for (i = 1; i < AST_LC_COUNT; i++)
10404887Schin 			cat[i] = -1;
10414887Schin 		for (i = 1, k = 0; i < AST_LC_COUNT; i++)
10424887Schin 			if (cat[i] < 0)
10434887Schin 			{
10444887Schin 				k++;
10454887Schin 				cat[i] = i;
10464887Schin 				for (j = i + 1; j < AST_LC_COUNT; j++)
10474887Schin 					if (locales[j] == locales[i])
10484887Schin 						cat[j] = i;
10494887Schin 			}
10504887Schin 		if (k == 1)
10514887Schin 			return (char*)locales[1]->name;
10524887Schin 		for (i = 1; i < AST_LC_COUNT; i++)
10534887Schin 			if (cat[i] >= 0 && !(locales[i]->flags & LC_default))
10544887Schin 			{
10554887Schin 				if (sfstrtell(sp))
10564887Schin 					sfprintf(sp, ";");
10574887Schin 				for (j = i, k = cat[i]; j < AST_LC_COUNT; j++)
10584887Schin 					if (cat[j] == k)
10594887Schin 					{
10604887Schin 						cat[j] = -1;
10618462SApril.Chin@Sun.COM 						sfprintf(sp, "%s=", lc_categories[j].name);
10624887Schin 					}
10634887Schin 				sfprintf(sp, "%s", locales[i]->name);
10644887Schin 			}
10654887Schin 		if (!sfstrtell(sp))
10664887Schin 			return (char*)locales[0]->name;
10674887Schin 		return sfstruse(sp);
10684887Schin 	}
10694887Schin 	if (!ast.locale.serial++)
107010898Sroland.mainz@nrubsig.org 	{
10714887Schin 		stropt(getenv("LC_OPTIONS"), options, sizeof(*options), setopt, NiL);
107210898Sroland.mainz@nrubsig.org 		initialized = 0;
107310898Sroland.mainz@nrubsig.org 	}
1074*12068SRoger.Faulkner@Oracle.COM 	if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
1075*12068SRoger.Faulkner@Oracle.COM 		sfprintf(sfstderr, "locale user %17s %16s  %s%s\n", category == AST_LC_LANG ? "LANG" : lc_categories[category].name, locale && !*locale ? "''" : locale, initialized ? "" : "[initial]", (ast.locale.set & AST_LC_setenv) ? "[setenv]" : "");
1076*12068SRoger.Faulkner@Oracle.COM 	if (ast.locale.set & AST_LC_setenv)
10774887Schin 	{
1078*12068SRoger.Faulkner@Oracle.COM 		f = LC_setenv;
1079*12068SRoger.Faulkner@Oracle.COM 		p = *locale ? lcmake(locale) : (Lc_t*)0;
1080*12068SRoger.Faulkner@Oracle.COM 	}
1081*12068SRoger.Faulkner@Oracle.COM 	else if (*locale)
1082*12068SRoger.Faulkner@Oracle.COM 	{
1083*12068SRoger.Faulkner@Oracle.COM 		f = LC_setlocale;
1084*12068SRoger.Faulkner@Oracle.COM 		p = lcmake(locale);
1085*12068SRoger.Faulkner@Oracle.COM 	}
1086*12068SRoger.Faulkner@Oracle.COM 	else if (category == AST_LC_ALL)
1087*12068SRoger.Faulkner@Oracle.COM 	{
1088*12068SRoger.Faulkner@Oracle.COM 		if (!initialized)
10898462SApril.Chin@Sun.COM 		{
1090*12068SRoger.Faulkner@Oracle.COM 			char*	u;
1091*12068SRoger.Faulkner@Oracle.COM 			char	tmp[256];
1092*12068SRoger.Faulkner@Oracle.COM 
1093*12068SRoger.Faulkner@Oracle.COM 			/*
1094*12068SRoger.Faulkner@Oracle.COM 			 * initialize from the environment
1095*12068SRoger.Faulkner@Oracle.COM 			 * precedence determined by X/Open
1096*12068SRoger.Faulkner@Oracle.COM 			 */
1097*12068SRoger.Faulkner@Oracle.COM 
1098*12068SRoger.Faulkner@Oracle.COM 			u = 0;
1099*12068SRoger.Faulkner@Oracle.COM 			if ((s = getenv("LANG")) && *s)
1100*12068SRoger.Faulkner@Oracle.COM 			{
1101*12068SRoger.Faulkner@Oracle.COM 				if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
1102*12068SRoger.Faulkner@Oracle.COM 					s = u;
1103*12068SRoger.Faulkner@Oracle.COM 				lang = lcmake(s);
1104*12068SRoger.Faulkner@Oracle.COM 			}
1105*12068SRoger.Faulkner@Oracle.COM 			else
1106*12068SRoger.Faulkner@Oracle.COM 				lang = 0;
1107*12068SRoger.Faulkner@Oracle.COM 			if ((s = getenv("LC_ALL")) && *s)
11084887Schin 			{
110910898Sroland.mainz@nrubsig.org 				if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
111010898Sroland.mainz@nrubsig.org 					s = u;
1111*12068SRoger.Faulkner@Oracle.COM 				lc_all = lcmake(s);
11124887Schin 			}
111310898Sroland.mainz@nrubsig.org 			else
1114*12068SRoger.Faulkner@Oracle.COM 				lc_all = 0;
11158462SApril.Chin@Sun.COM 			for (i = 1; i < AST_LC_COUNT; i++)
1116*12068SRoger.Faulkner@Oracle.COM 				if (lc_categories[i].flags & LC_setlocale)
1117*12068SRoger.Faulkner@Oracle.COM 					/* explicitly set by setlocale() */;
1118*12068SRoger.Faulkner@Oracle.COM 				else if ((s = getenv(lc_categories[i].name)) && *s)
1119*12068SRoger.Faulkner@Oracle.COM 				{
1120*12068SRoger.Faulkner@Oracle.COM 					if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
1121*12068SRoger.Faulkner@Oracle.COM 						s = u;
1122*12068SRoger.Faulkner@Oracle.COM 					lc_categories[i].prev = lcmake(s);
1123*12068SRoger.Faulkner@Oracle.COM 				}
1124*12068SRoger.Faulkner@Oracle.COM 				else
1125*12068SRoger.Faulkner@Oracle.COM 					lc_categories[i].prev = 0;
1126*12068SRoger.Faulkner@Oracle.COM 			for (i = 1; i < AST_LC_COUNT; i++)
1127*12068SRoger.Faulkner@Oracle.COM 				if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
1128*12068SRoger.Faulkner@Oracle.COM 				{
1129*12068SRoger.Faulkner@Oracle.COM 					while (i--)
1130*12068SRoger.Faulkner@Oracle.COM 						single(i, NiL, 0);
1131*12068SRoger.Faulkner@Oracle.COM 					return 0;
1132*12068SRoger.Faulkner@Oracle.COM 				}
1133*12068SRoger.Faulkner@Oracle.COM 			if (ast.locale.set & AST_LC_debug)
1134*12068SRoger.Faulkner@Oracle.COM 				for (i = 1; i < AST_LC_COUNT; i++)
1135*12068SRoger.Faulkner@Oracle.COM 					sfprintf(sfstderr, "locale env  %17s %16s %16s %16s\n", lc_categories[i].name, locales[i]->name, "", lc_categories[i].prev ? lc_categories[i].prev->name : (char*)0);
1136*12068SRoger.Faulkner@Oracle.COM 			initialized = 1;
1137*12068SRoger.Faulkner@Oracle.COM 		}
11384887Schin 		goto compose;
11394887Schin 	}
114010898Sroland.mainz@nrubsig.org 	else if (category == AST_LC_LANG || !(p = lc_categories[category].prev))
1141*12068SRoger.Faulkner@Oracle.COM 	{
1142*12068SRoger.Faulkner@Oracle.COM 		f = 0;
11438462SApril.Chin@Sun.COM 		p = lcmake("C");
1144*12068SRoger.Faulkner@Oracle.COM 	}
1145*12068SRoger.Faulkner@Oracle.COM 	else
1146*12068SRoger.Faulkner@Oracle.COM 		f = 0;
114710898Sroland.mainz@nrubsig.org 	if (category == AST_LC_LANG)
114810898Sroland.mainz@nrubsig.org 	{
114910898Sroland.mainz@nrubsig.org 		if (lang != p)
115010898Sroland.mainz@nrubsig.org 		{
115110898Sroland.mainz@nrubsig.org 			lang = p;
115210898Sroland.mainz@nrubsig.org 			if (!lc_all)
115310898Sroland.mainz@nrubsig.org 				for (i = 1; i < AST_LC_COUNT; i++)
1154*12068SRoger.Faulkner@Oracle.COM 					if (!single(i, lc_categories[i].prev, 0))
115510898Sroland.mainz@nrubsig.org 					{
115610898Sroland.mainz@nrubsig.org 						while (i--)
1157*12068SRoger.Faulkner@Oracle.COM 							single(i, NiL, 0);
115810898Sroland.mainz@nrubsig.org 						return 0;
115910898Sroland.mainz@nrubsig.org 					}
116010898Sroland.mainz@nrubsig.org 		}
116110898Sroland.mainz@nrubsig.org 	}
116210898Sroland.mainz@nrubsig.org 	else if (category != AST_LC_ALL)
1163*12068SRoger.Faulkner@Oracle.COM 	{
1164*12068SRoger.Faulkner@Oracle.COM 		if (f || !lc_all)
1165*12068SRoger.Faulkner@Oracle.COM 			return single(category, p, f);
1166*12068SRoger.Faulkner@Oracle.COM 		if (p && !(ast.locale.set & AST_LC_internal))
1167*12068SRoger.Faulkner@Oracle.COM 			lc_categories[category].prev = p;
1168*12068SRoger.Faulkner@Oracle.COM 		return (char*)locales[category]->name;
1169*12068SRoger.Faulkner@Oracle.COM 	}
1170*12068SRoger.Faulkner@Oracle.COM 	else if (composite(locale, 0) < 0)
117110898Sroland.mainz@nrubsig.org 		return 0;
117210898Sroland.mainz@nrubsig.org 	else if (lc_all != p)
11734887Schin 	{
117410898Sroland.mainz@nrubsig.org 		lc_all = p;
11754887Schin 		for (i = 1; i < AST_LC_COUNT; i++)
1176*12068SRoger.Faulkner@Oracle.COM 			if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
11774887Schin 			{
11784887Schin 				while (i--)
1179*12068SRoger.Faulkner@Oracle.COM 					single(i, NiL, 0);
11804887Schin 				return 0;
11814887Schin 			}
11824887Schin 	}
11834887Schin 	goto compose;
11844887Schin }
1185