xref: /titanic_50/usr/src/lib/libast/common/comp/setlocale.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin 
24da2e3ebdSchin /*
25da2e3ebdSchin  * setlocale() intercept
26da2e3ebdSchin  * maintains a bitmask of non-default categories
27da2e3ebdSchin  * and a permanent locale namespace for pointer comparison
28da2e3ebdSchin  * and persistent private data for locale related functions
29da2e3ebdSchin  */
30da2e3ebdSchin 
31da2e3ebdSchin #include <ast_standards.h>
32da2e3ebdSchin 
33da2e3ebdSchin #include "lclib.h"
34da2e3ebdSchin 
35da2e3ebdSchin #include <ast_wchar.h>
36da2e3ebdSchin #include <ctype.h>
37da2e3ebdSchin #include <mc.h>
38da2e3ebdSchin #include <namval.h>
39da2e3ebdSchin 
40da2e3ebdSchin #if ( _lib_wcwidth || _lib_wctomb ) && _hdr_wctype
41da2e3ebdSchin #include <wctype.h>
42da2e3ebdSchin #endif
43da2e3ebdSchin 
44da2e3ebdSchin #if _lib_wcwidth
45da2e3ebdSchin #undef	wcwidth
46da2e3ebdSchin #else
47da2e3ebdSchin #define wcwidth			0
48da2e3ebdSchin #endif
49da2e3ebdSchin 
50da2e3ebdSchin #if _lib_wctomb
51da2e3ebdSchin #undef	wctomb
52da2e3ebdSchin #else
53da2e3ebdSchin #define wctomb			0
54da2e3ebdSchin #endif
55da2e3ebdSchin 
56da2e3ebdSchin #ifdef mblen
57da2e3ebdSchin #undef	mblen
58da2e3ebdSchin extern int		mblen(const char*, size_t);
59da2e3ebdSchin #endif
60da2e3ebdSchin 
61da2e3ebdSchin #undef	mbtowc
62da2e3ebdSchin #undef	setlocale
63da2e3ebdSchin #undef	strcmp
64da2e3ebdSchin #undef	strcoll
65da2e3ebdSchin #undef	strxfrm
66da2e3ebdSchin #undef	valid
67da2e3ebdSchin 
68da2e3ebdSchin #ifndef AST_LC_CANONICAL
69da2e3ebdSchin #define AST_LC_CANONICAL	LC_abbreviated
70da2e3ebdSchin #endif
71da2e3ebdSchin 
7234f9b3eeSRoland Mainz #ifndef AST_LC_test
7334f9b3eeSRoland Mainz #define AST_LC_test		(1L<<27)
7434f9b3eeSRoland Mainz #endif
7534f9b3eeSRoland Mainz 
76da2e3ebdSchin #if _UWIN
77da2e3ebdSchin 
78da2e3ebdSchin #include <ast_windows.h>
79da2e3ebdSchin 
80da2e3ebdSchin #undef	_lib_setlocale
81da2e3ebdSchin #define _lib_setlocale		1
82da2e3ebdSchin 
83da2e3ebdSchin #define setlocale(c,l)		native_setlocale(c,l)
84da2e3ebdSchin 
85da2e3ebdSchin extern char*			uwin_setlocale(int, const char*);
86da2e3ebdSchin 
87da2e3ebdSchin /*
88da2e3ebdSchin  * convert locale to native locale name in buf
89da2e3ebdSchin  */
90da2e3ebdSchin 
91da2e3ebdSchin static char*
native_locale(const char * locale,char * buf,size_t siz)92da2e3ebdSchin native_locale(const char* locale, char* buf, size_t siz)
93da2e3ebdSchin {
94da2e3ebdSchin 	Lc_t*				lc;
95da2e3ebdSchin 	const Lc_attribute_list_t*	ap;
96da2e3ebdSchin 	int				i;
97da2e3ebdSchin 	unsigned long			lcid;
98da2e3ebdSchin 	unsigned long			lang;
99da2e3ebdSchin 	unsigned long			ctry;
100da2e3ebdSchin 	char				lbuf[128];
101da2e3ebdSchin 	char				cbuf[128];
102da2e3ebdSchin 
103da2e3ebdSchin 	if (locale && *locale)
104da2e3ebdSchin 	{
105da2e3ebdSchin 		if (!(lc = lcmake(locale)))
106da2e3ebdSchin 			return 0;
107da2e3ebdSchin 		lang = lc->language->index;
108da2e3ebdSchin 		ctry = 0;
109da2e3ebdSchin 		for (ap = lc->attributes; ap; ap = ap->next)
110da2e3ebdSchin 			if (ctry = ap->attribute->index)
111da2e3ebdSchin 				break;
112da2e3ebdSchin 		if (!ctry)
113da2e3ebdSchin 		{
114da2e3ebdSchin 			for (i = 0; i < elementsof(lc->territory->languages); i++)
115da2e3ebdSchin 				if (lc->territory->languages[i] == lc->language)
116da2e3ebdSchin 				{
117da2e3ebdSchin 					ctry = lc->territory->indices[i];
118da2e3ebdSchin 					break;
119da2e3ebdSchin 				}
120da2e3ebdSchin 			if (!ctry)
12134f9b3eeSRoland Mainz 			{
12234f9b3eeSRoland Mainz 				if (!lang)
12334f9b3eeSRoland Mainz 					return 0;
124da2e3ebdSchin 				ctry = SUBLANG_DEFAULT;
125da2e3ebdSchin 			}
12634f9b3eeSRoland Mainz 		}
127da2e3ebdSchin 		lcid = MAKELCID(MAKELANGID(lang, ctry), SORT_DEFAULT);
128da2e3ebdSchin 	}
129da2e3ebdSchin 	else
130da2e3ebdSchin 		lcid = GetUserDefaultLCID();
131da2e3ebdSchin 	if (GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, lbuf, sizeof(lbuf)) <= 0 ||
132da2e3ebdSchin 	    GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, cbuf, sizeof(cbuf)) <= 0)
133da2e3ebdSchin 		return 0;
134da2e3ebdSchin 	if (lc->charset->ms)
135da2e3ebdSchin 		sfsprintf(buf, siz, "%s_%s.%s", lbuf, cbuf, lc->charset->ms);
136da2e3ebdSchin 	else
137da2e3ebdSchin 		sfsprintf(buf, siz, "%s_%s", lbuf, cbuf);
138da2e3ebdSchin 	return buf;
139da2e3ebdSchin }
140da2e3ebdSchin 
141da2e3ebdSchin /*
142da2e3ebdSchin  * locale!=0 here
143da2e3ebdSchin  */
144da2e3ebdSchin 
145da2e3ebdSchin static char*
native_setlocale(int category,const char * locale)146da2e3ebdSchin native_setlocale(int category, const char* locale)
147da2e3ebdSchin {
148da2e3ebdSchin 	char*		usr;
149da2e3ebdSchin 	char*		sys;
150da2e3ebdSchin 	char		buf[256];
151da2e3ebdSchin 
15234f9b3eeSRoland Mainz 	if (!(usr = native_locale(locale, buf, sizeof(buf))))
15334f9b3eeSRoland Mainz 		return 0;
15434f9b3eeSRoland Mainz 
155da2e3ebdSchin 	/*
156da2e3ebdSchin 	 * win32 doesn't have LC_MESSAGES
157da2e3ebdSchin 	 */
158da2e3ebdSchin 
159da2e3ebdSchin 	if (category == LC_MESSAGES)
160da2e3ebdSchin 		return (char*)locale;
161da2e3ebdSchin 	sys = uwin_setlocale(category, usr);
162da2e3ebdSchin 	if (ast.locale.set & AST_LC_debug)
1637c2fbfb3SApril Chin 		sfprintf(sfstderr, "locale uwin %17s %-24s %-24s\n", lc_categories[lcindex(category, 0)].name, usr, sys);
164da2e3ebdSchin 	return sys;
165da2e3ebdSchin }
166da2e3ebdSchin 
167da2e3ebdSchin #else
168da2e3ebdSchin 
169da2e3ebdSchin #define native_locale(a,b,c)	((char*)0)
170da2e3ebdSchin 
171da2e3ebdSchin #endif
172da2e3ebdSchin 
173da2e3ebdSchin /*
174da2e3ebdSchin  * LC_COLLATE and LC_CTYPE native support
175da2e3ebdSchin  */
176da2e3ebdSchin 
177da2e3ebdSchin #if !_lib_mbtowc || MB_LEN_MAX <= 1
178da2e3ebdSchin #define mblen		0
179da2e3ebdSchin #define mbtowc		0
180da2e3ebdSchin #endif
181da2e3ebdSchin 
182da2e3ebdSchin #if !_lib_strcoll
183da2e3ebdSchin #define	strcoll		0
184da2e3ebdSchin #endif
185da2e3ebdSchin 
186da2e3ebdSchin #if !_lib_strxfrm
187da2e3ebdSchin #define	strxfrm		0
188da2e3ebdSchin #endif
189da2e3ebdSchin 
190da2e3ebdSchin /*
191da2e3ebdSchin  * LC_COLLATE and LC_CTYPE debug support
192da2e3ebdSchin  *
193da2e3ebdSchin  * mutibyte debug encoding
194da2e3ebdSchin  *
195da2e3ebdSchin  *	DL0 [ '0' .. '4' ] c1 ... c4 DR0
196da2e3ebdSchin  *	DL1 [ '0' .. '4' ] c1 ... c4 DR1
197da2e3ebdSchin  *
198da2e3ebdSchin  * with these ligatures
199da2e3ebdSchin  *
200da2e3ebdSchin  *	ch CH sst SST
201da2e3ebdSchin  *
202da2e3ebdSchin  * and private collation order
203da2e3ebdSchin  *
204da2e3ebdSchin  * wide character display width is the low order 3 bits
205da2e3ebdSchin  * wctomb() uses DL1...DR1
206da2e3ebdSchin  */
207da2e3ebdSchin 
208da2e3ebdSchin #define DEBUG_MB_CUR_MAX	7
209da2e3ebdSchin 
210da2e3ebdSchin #if DEBUG_MB_CUR_MAX < MB_LEN_MAX
211da2e3ebdSchin #undef	DEBUG_MB_CUR_MAX
212da2e3ebdSchin #define DEBUG_MB_CUR_MAX	MB_LEN_MAX
213da2e3ebdSchin #endif
214da2e3ebdSchin 
215da2e3ebdSchin #define DL0	'<'
216da2e3ebdSchin #define DL1	0xab		/* 8-bit mini << on xterm	*/
217da2e3ebdSchin #define DR0	'>'
218da2e3ebdSchin #define DR1	0xbb		/* 8-bit mini >> on xterm	*/
219da2e3ebdSchin 
220da2e3ebdSchin #define DB	((int)sizeof(wchar_t)*8-1)
221da2e3ebdSchin #define DC	7		/* wchar_t embedded char bits	*/
222da2e3ebdSchin #define DX	(DB/DC)		/* wchar_t max embedded chars	*/
223da2e3ebdSchin #define DZ	(DB-DX*DC+1)	/* wchar_t embedded size bits	*/
224da2e3ebdSchin #define DD	3		/* # mb delimiter chars <n...>	*/
225da2e3ebdSchin 
226da2e3ebdSchin static unsigned char debug_order[] =
227da2e3ebdSchin {
228da2e3ebdSchin 	  0,   1,   2,   3,   4,   5,   6,   7,
229da2e3ebdSchin 	  8,   9,  10,  11,  12,  13,  14,  15,
230da2e3ebdSchin 	 16,  17,  18,  19,  20,  21,  22,  23,
231da2e3ebdSchin 	 24,  25,  26,  27,  28,  29,  30,  31,
232da2e3ebdSchin 	 99, 100, 101, 102,  98, 103, 104, 105,
233da2e3ebdSchin 	106, 107, 108,  43, 109,  44,  42, 110,
234da2e3ebdSchin 	 32,  33,  34,  35,  36,  37,  38,  39,
235da2e3ebdSchin 	 40,  41, 111, 112, 113, 114, 115, 116,
236da2e3ebdSchin 	117,  71,  72,  73,  74,  75,  76,  77,
237da2e3ebdSchin 	 78,  79,  80,  81,  82,  83,  84,  85,
238da2e3ebdSchin 	 86,  87,  88,  89,  90,  91,  92,  93,
239da2e3ebdSchin 	 94,  95,  96, 118, 119, 120, 121,  97,
240da2e3ebdSchin 	122,  45,  46,  47,  48,  49,  50,  51,
241da2e3ebdSchin 	 52,  53,  54,  55,  56,  57,  58,  59,
242da2e3ebdSchin 	 60,  61,  62,  63,  64,  65,  66,  67,
243da2e3ebdSchin 	 68,  69,  70, 123, 124, 125, 126, 127,
244da2e3ebdSchin 	128, 129, 130, 131, 132, 133, 134, 135,
245da2e3ebdSchin 	136, 137, 138, 139, 140, 141, 142, 143,
246da2e3ebdSchin 	144, 145, 146, 147, 148, 149, 150, 151,
247da2e3ebdSchin 	152, 153, 154, 155, 156, 157, 158, 159,
248da2e3ebdSchin 	160, 161, 162, 163, 164, 165, 166, 167,
249da2e3ebdSchin 	168, 169, 170, 171, 172, 173, 174, 175,
250da2e3ebdSchin 	176, 177, 178, 179, 180, 181, 182, 183,
251da2e3ebdSchin 	184, 185, 186, 187, 188, 189, 190, 191,
252da2e3ebdSchin 	192, 193, 194, 195, 196, 197, 198, 199,
253da2e3ebdSchin 	200, 201, 202, 203, 204, 205, 206, 207,
254da2e3ebdSchin 	208, 209, 210, 211, 212, 213, 214, 215,
255da2e3ebdSchin 	216, 217, 218, 219, 220, 221, 222, 223,
256da2e3ebdSchin 	224, 225, 226, 227, 228, 229, 230, 231,
257da2e3ebdSchin 	232, 233, 234, 235, 236, 237, 238, 239,
258da2e3ebdSchin 	240, 241, 242, 243, 244, 245, 246, 247,
259da2e3ebdSchin 	248, 249, 250, 251, 252, 253, 254, 255,
260da2e3ebdSchin };
261da2e3ebdSchin 
262da2e3ebdSchin static int
debug_mbtowc(register wchar_t * p,register const char * s,size_t n)263da2e3ebdSchin debug_mbtowc(register wchar_t* p, register const char* s, size_t n)
264da2e3ebdSchin {
265da2e3ebdSchin 	register const char*	q;
266da2e3ebdSchin 	register const char*	r;
267da2e3ebdSchin 	register int		w;
268da2e3ebdSchin 	register int		dr;
269da2e3ebdSchin 	wchar_t			c;
270da2e3ebdSchin 
271da2e3ebdSchin 	if (n < 1)
272da2e3ebdSchin 		return -1;
273da2e3ebdSchin 	if (!s || !*s)
274da2e3ebdSchin 		return 0;
275da2e3ebdSchin 	switch (((unsigned char*)s)[0])
276da2e3ebdSchin 	{
277da2e3ebdSchin 	case DL0:
278da2e3ebdSchin 		dr = DR0;
279da2e3ebdSchin 		break;
280da2e3ebdSchin 	case DL1:
281da2e3ebdSchin 		dr = DR1;
282da2e3ebdSchin 		break;
283da2e3ebdSchin 	default:
284da2e3ebdSchin 		if (p)
285da2e3ebdSchin 			*p = ((unsigned char*)s)[0] & ((1<<DC)-1);
286da2e3ebdSchin 		return 1;
287da2e3ebdSchin 	}
288da2e3ebdSchin 	if (n < 2)
289da2e3ebdSchin 		return -1;
290da2e3ebdSchin 	if ((w = ((unsigned char*)s)[1]) == ((unsigned char*)s)[0])
291da2e3ebdSchin 	{
292da2e3ebdSchin 		if (p)
293da2e3ebdSchin 			*p = w;
294da2e3ebdSchin 		return 2;
295da2e3ebdSchin 	}
296da2e3ebdSchin 	if (w < '0' || w > ('0' + DX))
297da2e3ebdSchin 		return -1;
298da2e3ebdSchin 	if ((w -= '0' - DD) > n)
299da2e3ebdSchin 		return -1;
300da2e3ebdSchin 	r = s + w - 1;
301da2e3ebdSchin 	q = s += 2;
302da2e3ebdSchin 	while (q < r && *q)
303da2e3ebdSchin 		q++;
304da2e3ebdSchin 	if (q != r || *((unsigned char*)q) != dr)
305da2e3ebdSchin 		return -1;
306da2e3ebdSchin 	if (p)
307da2e3ebdSchin 	{
308da2e3ebdSchin 		c = 0;
309da2e3ebdSchin 		while (--q >= s)
310da2e3ebdSchin 		{
311da2e3ebdSchin 			c <<= DC;
312da2e3ebdSchin 			c |= *((unsigned char*)q);
313da2e3ebdSchin 		}
314da2e3ebdSchin 		c <<= DZ;
315da2e3ebdSchin 		c |= w - DD;
316da2e3ebdSchin 		*p = c;
317da2e3ebdSchin 	}
318da2e3ebdSchin 	return w;
319da2e3ebdSchin }
320da2e3ebdSchin 
321da2e3ebdSchin static int
debug_wctomb(char * s,wchar_t c)322da2e3ebdSchin debug_wctomb(char* s, wchar_t c)
323da2e3ebdSchin {
324da2e3ebdSchin 	int	w;
325da2e3ebdSchin 	int	i;
326da2e3ebdSchin 	int	k;
327da2e3ebdSchin 
328da2e3ebdSchin 	w = 0;
329da2e3ebdSchin 	if (c >= 0 && c <= UCHAR_MAX)
330da2e3ebdSchin 	{
331da2e3ebdSchin 		w++;
332da2e3ebdSchin 		if (s)
333da2e3ebdSchin 			*s = c;
334da2e3ebdSchin 	}
335da2e3ebdSchin 	else if ((i = c & ((1<<DZ)-1)) > DX)
336da2e3ebdSchin 		return -1;
337da2e3ebdSchin 	else
338da2e3ebdSchin 	{
339da2e3ebdSchin 		w++;
340da2e3ebdSchin 		if (s)
341da2e3ebdSchin 			*s++ = DL1;
342da2e3ebdSchin 		c >>= DZ;
343da2e3ebdSchin 		w++;
344da2e3ebdSchin 		if (s)
345da2e3ebdSchin 			*s++ = i + '0';
346da2e3ebdSchin 		while (i--)
347da2e3ebdSchin 		{
348da2e3ebdSchin 			w++;
349da2e3ebdSchin 			if (s)
350da2e3ebdSchin 				*s++ = (k = c & ((1<<DC)-1)) ? k : '?';
351da2e3ebdSchin 			c >>= DC;
352da2e3ebdSchin 		}
353da2e3ebdSchin 		w++;
354da2e3ebdSchin 		if (s)
355da2e3ebdSchin 			*s++ = DR1;
356da2e3ebdSchin 	}
357da2e3ebdSchin 	return w;
358da2e3ebdSchin }
359da2e3ebdSchin 
360da2e3ebdSchin static int
debug_mblen(const char * s,size_t n)361da2e3ebdSchin debug_mblen(const char* s, size_t n)
362da2e3ebdSchin {
363da2e3ebdSchin 	return debug_mbtowc(NiL, s, n);
364da2e3ebdSchin }
365da2e3ebdSchin 
366da2e3ebdSchin static int
debug_wcwidth(wchar_t c)367da2e3ebdSchin debug_wcwidth(wchar_t c)
368da2e3ebdSchin {
369da2e3ebdSchin 	if (c >= 0 && c <= UCHAR_MAX)
370da2e3ebdSchin 		return 1;
371da2e3ebdSchin 	if ((c &= ((1<<DZ)-1)) > DX)
372da2e3ebdSchin 		return -1;
373da2e3ebdSchin 	return c + DD;
374da2e3ebdSchin }
375da2e3ebdSchin 
376da2e3ebdSchin static size_t
debug_strxfrm(register char * t,register const char * s,size_t n)377da2e3ebdSchin debug_strxfrm(register char* t, register const char* s, size_t n)
378da2e3ebdSchin {
379da2e3ebdSchin 	register const char*	q;
380da2e3ebdSchin 	register const char*	r;
381da2e3ebdSchin 	register char*		e;
3827c2fbfb3SApril Chin 	char*			o;
383da2e3ebdSchin 	register size_t		z;
384da2e3ebdSchin 	register int		w;
385da2e3ebdSchin 
3867c2fbfb3SApril Chin 	o = t;
387da2e3ebdSchin 	z = 0;
388da2e3ebdSchin 	if (e = t)
389da2e3ebdSchin 		e += n;
390da2e3ebdSchin 	while (s[0])
391da2e3ebdSchin 	{
392da2e3ebdSchin 		if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC))
393da2e3ebdSchin 		{
394da2e3ebdSchin 			w -= '0';
395da2e3ebdSchin 			q = s + 2;
396da2e3ebdSchin 			r = q + w;
397da2e3ebdSchin 			while (q < r && *q)
398da2e3ebdSchin 				q++;
399da2e3ebdSchin 			if (*((unsigned char*)q) == DR0 || *((unsigned char*)q) == DR1)
400da2e3ebdSchin 			{
401da2e3ebdSchin 				if (t)
402da2e3ebdSchin 				{
403da2e3ebdSchin 					for (q = s + 2; q < r; q++)
404da2e3ebdSchin 						if (t < e)
405da2e3ebdSchin 							*t++ = debug_order[*q];
406da2e3ebdSchin 					while (w++ < DX)
407da2e3ebdSchin 						if (t < e)
408da2e3ebdSchin 							*t++ = 1;
409da2e3ebdSchin 				}
410da2e3ebdSchin 				s = r + 1;
411da2e3ebdSchin 				z += DX;
412da2e3ebdSchin 				continue;
413da2e3ebdSchin 			}
414da2e3ebdSchin 		}
415da2e3ebdSchin 		if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H'))
416da2e3ebdSchin 		{
417da2e3ebdSchin 			if (t)
418da2e3ebdSchin 			{
419da2e3ebdSchin 				if (t < e)
420da2e3ebdSchin 					*t++ = debug_order[s[0]];
421da2e3ebdSchin 				if (t < e)
422da2e3ebdSchin 					*t++ = debug_order[s[1]];
423da2e3ebdSchin 				if (t < e)
424da2e3ebdSchin 					*t++ = 1;
425da2e3ebdSchin 				if (t < e)
426da2e3ebdSchin 					*t++ = 1;
427da2e3ebdSchin 			}
428da2e3ebdSchin 			s += 2;
429da2e3ebdSchin 			z += DX;
430da2e3ebdSchin 			continue;
431da2e3ebdSchin 		}
432da2e3ebdSchin 		if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T'))
433da2e3ebdSchin 		{
434da2e3ebdSchin 			if (t)
435da2e3ebdSchin 			{
436da2e3ebdSchin 				if (t < e)
437da2e3ebdSchin 					*t++ = debug_order[s[0]];
438da2e3ebdSchin 				if (t < e)
439da2e3ebdSchin 					*t++ = debug_order[s[1]];
440da2e3ebdSchin 				if (t < e)
441da2e3ebdSchin 					*t++ = debug_order[s[2]];
442da2e3ebdSchin 				if (t < e)
443da2e3ebdSchin 					*t++ = 1;
444da2e3ebdSchin 			}
445da2e3ebdSchin 			s += 3;
446da2e3ebdSchin 			z += DX;
447da2e3ebdSchin 			continue;
448da2e3ebdSchin 		}
449da2e3ebdSchin 		if (t)
450da2e3ebdSchin 		{
451da2e3ebdSchin 			if (t < e)
452da2e3ebdSchin 				*t++ = debug_order[s[0]];
453da2e3ebdSchin 			if (t < e)
454da2e3ebdSchin 				*t++ = 1;
455da2e3ebdSchin 			if (t < e)
456da2e3ebdSchin 				*t++ = 1;
457da2e3ebdSchin 			if (t < e)
458da2e3ebdSchin 				*t++ = 1;
459da2e3ebdSchin 		}
460da2e3ebdSchin 		s++;
461da2e3ebdSchin 		z += DX;
462da2e3ebdSchin 	}
4637c2fbfb3SApril Chin 	if (!t)
4647c2fbfb3SApril Chin 		return z;
465da2e3ebdSchin 	if (t < e)
466da2e3ebdSchin 		*t = 0;
4677c2fbfb3SApril Chin 	return t - o;
468da2e3ebdSchin }
469da2e3ebdSchin 
470da2e3ebdSchin static int
debug_strcoll(const char * a,const char * b)471da2e3ebdSchin debug_strcoll(const char* a, const char* b)
472da2e3ebdSchin {
473da2e3ebdSchin 	char	ab[1024];
474da2e3ebdSchin 	char	bb[1024];
475da2e3ebdSchin 
476da2e3ebdSchin 	debug_strxfrm(ab, a, sizeof(ab) - 1);
477da2e3ebdSchin 	ab[sizeof(ab)-1] = 0;
478da2e3ebdSchin 	debug_strxfrm(bb, b, sizeof(bb) - 1);
479da2e3ebdSchin 	bb[sizeof(bb)-1] = 0;
480da2e3ebdSchin 	return strcmp(ab, bb);
481da2e3ebdSchin }
482da2e3ebdSchin 
483da2e3ebdSchin /*
484da2e3ebdSchin  * default locale
485da2e3ebdSchin  */
486da2e3ebdSchin 
487da2e3ebdSchin static int
default_wcwidth(wchar_t w)488da2e3ebdSchin default_wcwidth(wchar_t w)
489da2e3ebdSchin {
490da2e3ebdSchin 	return w >= 0 && w <= 255 && !iscntrl(w) ? 1 : -1;
491da2e3ebdSchin }
492da2e3ebdSchin 
493da2e3ebdSchin /*
494da2e3ebdSchin  * called when LC_COLLATE initialized or changes
495da2e3ebdSchin  */
496da2e3ebdSchin 
497da2e3ebdSchin static int
set_collate(Lc_category_t * cp)498da2e3ebdSchin set_collate(Lc_category_t* cp)
499da2e3ebdSchin {
500da2e3ebdSchin 	if (locales[cp->internal]->flags & LC_debug)
501da2e3ebdSchin 	{
502da2e3ebdSchin 		ast.collate = debug_strcoll;
503da2e3ebdSchin 		ast.mb_xfrm = debug_strxfrm;
504da2e3ebdSchin 	}
505da2e3ebdSchin 	else if (locales[cp->internal]->flags & LC_default)
506da2e3ebdSchin 	{
507da2e3ebdSchin 		ast.collate = strcmp;
508da2e3ebdSchin 		ast.mb_xfrm = 0;
509da2e3ebdSchin 	}
510da2e3ebdSchin 	else
511da2e3ebdSchin 	{
512da2e3ebdSchin 		ast.collate = strcoll;
513da2e3ebdSchin 		ast.mb_xfrm = strxfrm;
514da2e3ebdSchin 	}
515da2e3ebdSchin 	return 0;
516da2e3ebdSchin }
517da2e3ebdSchin 
518da2e3ebdSchin /*
5197c2fbfb3SApril Chin  * workaround the interesting sjis that translates unshifted 7 bit ascii!
5207c2fbfb3SApril Chin  */
5217c2fbfb3SApril Chin 
5227c2fbfb3SApril Chin #if _hdr_wchar && _typ_mbstate_t && _lib_mbrtowc
5237c2fbfb3SApril Chin 
5247c2fbfb3SApril Chin #define mb_state_zero	((mbstate_t*)&ast.pad[sizeof(ast.pad)-2*sizeof(mbstate_t)])
5257c2fbfb3SApril Chin #define mb_state	((mbstate_t*)&ast.pad[sizeof(ast.pad)-sizeof(mbstate_t)])
5267c2fbfb3SApril Chin 
5277c2fbfb3SApril Chin static int
sjis_mbtowc(register wchar_t * p,register const char * s,size_t n)5287c2fbfb3SApril Chin sjis_mbtowc(register wchar_t* p, register const char* s, size_t n)
5297c2fbfb3SApril Chin {
5307c2fbfb3SApril Chin 	if (n && p && s && (*s == '\\' || *s == '~') && !memcmp(mb_state, mb_state_zero, sizeof(mbstate_t)))
5317c2fbfb3SApril Chin 	{
5327c2fbfb3SApril Chin 		*p = *s;
5337c2fbfb3SApril Chin 		return 1;
5347c2fbfb3SApril Chin 	}
5357c2fbfb3SApril Chin 	return mbrtowc(p, s, n, mb_state);
5367c2fbfb3SApril Chin }
5377c2fbfb3SApril Chin 
5387c2fbfb3SApril Chin #endif
5397c2fbfb3SApril Chin 
54034f9b3eeSRoland Mainz #define utf8_wctomb	wctomb
54134f9b3eeSRoland Mainz 
54234f9b3eeSRoland Mainz static const uint32_t		utf8mask[] =
54334f9b3eeSRoland Mainz {
54434f9b3eeSRoland Mainz 	0x00000000,
54534f9b3eeSRoland Mainz 	0x00000000,
54634f9b3eeSRoland Mainz 	0xffffff80,
54734f9b3eeSRoland Mainz 	0xfffff800,
54834f9b3eeSRoland Mainz 	0xffff0000,
54934f9b3eeSRoland Mainz 	0xffe00000,
55034f9b3eeSRoland Mainz 	0xfc000000,
55134f9b3eeSRoland Mainz };
55234f9b3eeSRoland Mainz 
55334f9b3eeSRoland Mainz static const signed char	utf8tab[256] =
55434f9b3eeSRoland Mainz {
55534f9b3eeSRoland Mainz 	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55634f9b3eeSRoland Mainz 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55734f9b3eeSRoland Mainz 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55834f9b3eeSRoland Mainz 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55934f9b3eeSRoland Mainz 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56034f9b3eeSRoland Mainz 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56134f9b3eeSRoland Mainz 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56234f9b3eeSRoland Mainz 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56334f9b3eeSRoland Mainz 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56434f9b3eeSRoland Mainz 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56534f9b3eeSRoland Mainz 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56634f9b3eeSRoland Mainz 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56734f9b3eeSRoland Mainz 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56834f9b3eeSRoland Mainz 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56934f9b3eeSRoland Mainz 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
57034f9b3eeSRoland Mainz 	4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,-1,-1,
57134f9b3eeSRoland Mainz };
57234f9b3eeSRoland Mainz 
57334f9b3eeSRoland Mainz static int
utf8_mbtowc(wchar_t * wp,const char * str,size_t n)57434f9b3eeSRoland Mainz utf8_mbtowc(wchar_t* wp, const char* str, size_t n)
57534f9b3eeSRoland Mainz {
57634f9b3eeSRoland Mainz 	register unsigned char*	sp = (unsigned char*)str;
57734f9b3eeSRoland Mainz 	register int		m;
57834f9b3eeSRoland Mainz 	register int		i;
57934f9b3eeSRoland Mainz 	register int		c;
58034f9b3eeSRoland Mainz 	register wchar_t	w = 0;
58134f9b3eeSRoland Mainz 
58234f9b3eeSRoland Mainz 	if (!sp || !n)
58334f9b3eeSRoland Mainz 		return 0;
58434f9b3eeSRoland Mainz 	if ((m = utf8tab[*sp]) > 0)
58534f9b3eeSRoland Mainz 	{
58634f9b3eeSRoland Mainz 		if (m > n)
58734f9b3eeSRoland Mainz 			return -1;
58834f9b3eeSRoland Mainz 		if (wp)
58934f9b3eeSRoland Mainz 		{
59034f9b3eeSRoland Mainz 			if (m == 1)
59134f9b3eeSRoland Mainz 			{
59234f9b3eeSRoland Mainz 				*wp = *sp;
59334f9b3eeSRoland Mainz 				return 1;
59434f9b3eeSRoland Mainz 			}
59534f9b3eeSRoland Mainz 			w = *sp & ((1<<(8-m))-1);
59634f9b3eeSRoland Mainz 			for (i = m - 1; i > 0; i--)
59734f9b3eeSRoland Mainz 			{
59834f9b3eeSRoland Mainz 				c = *++sp;
59934f9b3eeSRoland Mainz 				if ((c&0xc0) != 0x80)
60034f9b3eeSRoland Mainz 					goto invalid;
60134f9b3eeSRoland Mainz 				w = (w<<6) | (c&0x3f);
60234f9b3eeSRoland Mainz 			}
60334f9b3eeSRoland Mainz 			if (!(utf8mask[m] & w) || w >= 0xd800 && (w <= 0xdfff || w >= 0xfffe && w <= 0xffff))
60434f9b3eeSRoland Mainz 				goto invalid;
60534f9b3eeSRoland Mainz 			*wp = w;
60634f9b3eeSRoland Mainz 		}
60734f9b3eeSRoland Mainz 		return m;
60834f9b3eeSRoland Mainz 	}
60934f9b3eeSRoland Mainz 	if (!*sp)
61034f9b3eeSRoland Mainz 		return 0;
61134f9b3eeSRoland Mainz  invalid:
61234f9b3eeSRoland Mainz #ifdef EILSEQ
61334f9b3eeSRoland Mainz 	errno = EILSEQ;
61434f9b3eeSRoland Mainz #endif
61534f9b3eeSRoland Mainz 	ast.mb_sync = (const char*)sp - str;
61634f9b3eeSRoland Mainz 	return -1;
61734f9b3eeSRoland Mainz }
61834f9b3eeSRoland Mainz 
61934f9b3eeSRoland Mainz static int
utf8_mblen(const char * str,size_t n)62034f9b3eeSRoland Mainz utf8_mblen(const char* str, size_t n)
62134f9b3eeSRoland Mainz {
62234f9b3eeSRoland Mainz 	wchar_t		w;
62334f9b3eeSRoland Mainz 
62434f9b3eeSRoland Mainz 	return utf8_mbtowc(&w, str, n);
62534f9b3eeSRoland Mainz }
62634f9b3eeSRoland Mainz 
6277c2fbfb3SApril Chin /*
628da2e3ebdSchin  * called when LC_CTYPE initialized or changes
629da2e3ebdSchin  */
630da2e3ebdSchin 
631da2e3ebdSchin static int
set_ctype(Lc_category_t * cp)632da2e3ebdSchin set_ctype(Lc_category_t* cp)
633da2e3ebdSchin {
63434f9b3eeSRoland Mainz 	ast.mb_sync = 0;
635da2e3ebdSchin 	if (locales[cp->internal]->flags & LC_debug)
636da2e3ebdSchin 	{
637da2e3ebdSchin 		ast.mb_cur_max = DEBUG_MB_CUR_MAX;
638da2e3ebdSchin 		ast.mb_len = debug_mblen;
639da2e3ebdSchin 		ast.mb_towc = debug_mbtowc;
640da2e3ebdSchin 		ast.mb_width = debug_wcwidth;
641da2e3ebdSchin 		ast.mb_conv = debug_wctomb;
642da2e3ebdSchin 	}
643da2e3ebdSchin 	else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc))
644da2e3ebdSchin 	{
645da2e3ebdSchin 		ast.mb_cur_max = 1;
646da2e3ebdSchin 		ast.mb_len = 0;
647da2e3ebdSchin 		ast.mb_towc = 0;
648da2e3ebdSchin 		ast.mb_width = default_wcwidth;
649da2e3ebdSchin 		ast.mb_conv = 0;
650da2e3ebdSchin 	}
65134f9b3eeSRoland Mainz 	else if ((locales[cp->internal]->flags & LC_utf8) && !(ast.locale.set & AST_LC_test))
65234f9b3eeSRoland Mainz 	{
65334f9b3eeSRoland Mainz 		ast.mb_cur_max = 6;
65434f9b3eeSRoland Mainz 		ast.mb_len = utf8_mblen;
65534f9b3eeSRoland Mainz 		ast.mb_towc = utf8_mbtowc;
65634f9b3eeSRoland Mainz 		if (!(ast.mb_width = wcwidth))
65734f9b3eeSRoland Mainz 			ast.mb_width = default_wcwidth;
65834f9b3eeSRoland Mainz 		ast.mb_conv = utf8_wctomb;
65934f9b3eeSRoland Mainz 	}
660da2e3ebdSchin 	else
661da2e3ebdSchin 	{
662da2e3ebdSchin 		if (!(ast.mb_width = wcwidth))
663da2e3ebdSchin 			ast.mb_width = default_wcwidth;
664da2e3ebdSchin 		ast.mb_conv = wctomb;
6657c2fbfb3SApril Chin #ifdef mb_state
6667c2fbfb3SApril Chin 		{
6677c2fbfb3SApril Chin 			/*
6687c2fbfb3SApril Chin 			 * check for sjis that translates unshifted 7 bit ascii!
6697c2fbfb3SApril Chin 			 */
6707c2fbfb3SApril Chin 
6717c2fbfb3SApril Chin 			char*	s;
6727c2fbfb3SApril Chin 			char	buf[2];
6737c2fbfb3SApril Chin 
6747c2fbfb3SApril Chin 			mbinit();
6757c2fbfb3SApril Chin 			buf[1] = 0;
6767c2fbfb3SApril Chin 			*(s = buf) = '\\';
6777c2fbfb3SApril Chin 			if (mbchar(s) != buf[0])
6787c2fbfb3SApril Chin 			{
6797c2fbfb3SApril Chin 				memcpy(mb_state, mb_state_zero, sizeof(mbstate_t));
6807c2fbfb3SApril Chin 				ast.mb_towc = sjis_mbtowc;
6817c2fbfb3SApril Chin 			}
6827c2fbfb3SApril Chin 		}
6837c2fbfb3SApril Chin #endif
684da2e3ebdSchin 	}
68534f9b3eeSRoland Mainz 	if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
68634f9b3eeSRoland Mainz 		sfprintf(sfstderr, "locale info %17s MB_CUR_MAX=%d%s%s%s%s\n"
68734f9b3eeSRoland Mainz 			, cp->name
68834f9b3eeSRoland Mainz 			, ast.mb_cur_max
68934f9b3eeSRoland Mainz 			, ast.mb_len == debug_mblen ? " debug_mblen" : ast.mb_len == mblen ? " mblen" : ""
69034f9b3eeSRoland Mainz 			, ast.mb_towc == debug_mbtowc ? " debug_mbtowc" : ast.mb_towc == mbtowc ? " mbtowc"
69134f9b3eeSRoland Mainz #ifdef mb_state
69234f9b3eeSRoland Mainz 				: ast.mb_towc == sjis_mbtowc ? " sjis_mbtowc"
69334f9b3eeSRoland Mainz #endif
69434f9b3eeSRoland Mainz 				: ""
69534f9b3eeSRoland Mainz 			, ast.mb_width == debug_wcwidth ? " debug_wcwidth" : ast.mb_width == wcwidth ? " wcwidth" : ast.mb_width == default_wcwidth ? " default_wcwidth" : ""
69634f9b3eeSRoland Mainz 			, ast.mb_conv == debug_wctomb ? " debug_wctomb" : ast.mb_conv == wctomb ? " wctomb" : ""
69734f9b3eeSRoland Mainz 			);
698da2e3ebdSchin 	return 0;
699da2e3ebdSchin }
700da2e3ebdSchin 
701da2e3ebdSchin /*
702da2e3ebdSchin  * called when LC_NUMERIC initialized or changes
703da2e3ebdSchin  */
704da2e3ebdSchin 
705da2e3ebdSchin static int
set_numeric(Lc_category_t * cp)706da2e3ebdSchin set_numeric(Lc_category_t* cp)
707da2e3ebdSchin {
708da2e3ebdSchin 	register int		category = cp->internal;
709da2e3ebdSchin 	struct lconv*		lp;
710da2e3ebdSchin 	Lc_numeric_t*		dp;
711da2e3ebdSchin 
712da2e3ebdSchin 	static Lc_numeric_t	default_numeric = { '.', -1 };
713da2e3ebdSchin 
714da2e3ebdSchin 	if (!LCINFO(category)->data)
715da2e3ebdSchin 	{
716da2e3ebdSchin 		if ((lp = localeconv()) && (dp = newof(0, Lc_numeric_t, 1, 0)))
717da2e3ebdSchin 		{
718da2e3ebdSchin 			dp->decimal = lp->decimal_point && *lp->decimal_point ? *(unsigned char*)lp->decimal_point : '.';
719da2e3ebdSchin 			dp->thousand = lp->thousands_sep && *lp->thousands_sep ? *(unsigned char*)lp->thousands_sep : -1;
720da2e3ebdSchin 		}
721da2e3ebdSchin 		else
722da2e3ebdSchin 			dp = &default_numeric;
723da2e3ebdSchin 		LCINFO(category)->data = (void*)dp;
724da2e3ebdSchin 		if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
7257c2fbfb3SApril Chin 			sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", lc_categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X');
726da2e3ebdSchin 	}
727da2e3ebdSchin 	return 0;
728da2e3ebdSchin }
729da2e3ebdSchin 
730da2e3ebdSchin /*
731da2e3ebdSchin  * this table is indexed by AST_LC_[A-Z]*
732da2e3ebdSchin  */
733da2e3ebdSchin 
7347c2fbfb3SApril Chin Lc_category_t		lc_categories[] =
735da2e3ebdSchin {
736da2e3ebdSchin { "LC_ALL",           LC_ALL,           AST_LC_ALL,           0               },
737da2e3ebdSchin { "LC_COLLATE",       LC_COLLATE,       AST_LC_COLLATE,       set_collate     },
738da2e3ebdSchin { "LC_CTYPE",         LC_CTYPE,         AST_LC_CTYPE,         set_ctype       },
739da2e3ebdSchin { "LC_MESSAGES",      LC_MESSAGES,      AST_LC_MESSAGES,      0               },
740da2e3ebdSchin { "LC_MONETARY",      LC_MONETARY,      AST_LC_MONETARY,      0               },
741da2e3ebdSchin { "LC_NUMERIC",       LC_NUMERIC,       AST_LC_NUMERIC,       set_numeric     },
742da2e3ebdSchin { "LC_TIME",          LC_TIME,          AST_LC_TIME,          0               },
743da2e3ebdSchin { "LC_IDENTIFICATION",LC_IDENTIFICATION,AST_LC_IDENTIFICATION,0               },
744da2e3ebdSchin { "LC_ADDRESS",       LC_ADDRESS,       AST_LC_ADDRESS,       0               },
745da2e3ebdSchin { "LC_NAME",          LC_NAME,          AST_LC_NAME,          0               },
746da2e3ebdSchin { "LC_TELEPHONE",     LC_TELEPHONE,     AST_LC_TELEPHONE,     0               },
747da2e3ebdSchin { "LC_XLITERATE",     LC_XLITERATE,     AST_LC_XLITERATE,     0               },
748da2e3ebdSchin { "LC_MEASUREMENT",   LC_MEASUREMENT,   AST_LC_MEASUREMENT,   0               },
749da2e3ebdSchin { "LC_PAPER",         LC_PAPER,         AST_LC_PAPER,         0               },
750da2e3ebdSchin };
751da2e3ebdSchin 
75234f9b3eeSRoland Mainz static Lc_t*		lang;
75334f9b3eeSRoland Mainz static Lc_t*		lc_all;
75434f9b3eeSRoland Mainz 
75534f9b3eeSRoland Mainz typedef struct Unamval_s
75634f9b3eeSRoland Mainz {
75734f9b3eeSRoland Mainz 	char*		name;
75834f9b3eeSRoland Mainz 	unsigned int	value;
75934f9b3eeSRoland Mainz } Unamval_t;
76034f9b3eeSRoland Mainz 
76134f9b3eeSRoland Mainz static const Unamval_t	options[] =
762da2e3ebdSchin {
763da2e3ebdSchin 	"debug",		AST_LC_debug,
764da2e3ebdSchin 	"find",			AST_LC_find,
765da2e3ebdSchin 	"setlocale",		AST_LC_setlocale,
76634f9b3eeSRoland Mainz 	"test",			AST_LC_test,
767da2e3ebdSchin 	"translate",		AST_LC_translate,
768da2e3ebdSchin 	0,			0
769da2e3ebdSchin };
770da2e3ebdSchin 
771da2e3ebdSchin /*
772da2e3ebdSchin  * called by stropt() to set options
773da2e3ebdSchin  */
774da2e3ebdSchin 
775da2e3ebdSchin static int
setopt(void * a,const void * p,int n,const char * v)776da2e3ebdSchin setopt(void* a, const void* p, int n, const char* v)
777da2e3ebdSchin {
778da2e3ebdSchin 	if (p)
779da2e3ebdSchin 	{
780da2e3ebdSchin 		if (n)
78134f9b3eeSRoland Mainz 			ast.locale.set |= ((Unamval_t*)p)->value;
782da2e3ebdSchin 		else
78334f9b3eeSRoland Mainz 			ast.locale.set &= ~((Unamval_t*)p)->value;
784da2e3ebdSchin 	}
785da2e3ebdSchin 	return 0;
786da2e3ebdSchin }
787da2e3ebdSchin 
788da2e3ebdSchin #if !_lib_setlocale
789da2e3ebdSchin 
790da2e3ebdSchin #define setlocale(c,l)		default_setlocale(c,l)
791da2e3ebdSchin 
792da2e3ebdSchin static char*
default_setlocale(int category,const char * locale)793da2e3ebdSchin default_setlocale(int category, const char* locale)
794da2e3ebdSchin {
795da2e3ebdSchin 	Lc_t*		lc;
796da2e3ebdSchin 
797da2e3ebdSchin 	if (locale)
798da2e3ebdSchin 	{
799da2e3ebdSchin 		if (!(lc = lcmake(locale)) || !(lc->flags & LC_default))
800da2e3ebdSchin 			return 0;
801da2e3ebdSchin 		locales[0]->flags &= ~lc->flags;
802da2e3ebdSchin 		locales[1]->flags &= ~lc->flags;
803da2e3ebdSchin 		return lc->name;
804da2e3ebdSchin 	}
805da2e3ebdSchin 	return (locales[1]->flags & (1<<category)) ? locales[1]->name : locales[0]->name;
806da2e3ebdSchin }
807da2e3ebdSchin 
808da2e3ebdSchin #endif
809da2e3ebdSchin 
810da2e3ebdSchin /*
811da2e3ebdSchin  * set a single AST_LC_* locale category
812da2e3ebdSchin  * the caller must validate category
813da2e3ebdSchin  * lc==0 restores the previous state
814da2e3ebdSchin  */
815da2e3ebdSchin 
816da2e3ebdSchin static char*
single(int category,Lc_t * lc,unsigned int flags)817*3e14f97fSRoger A. Faulkner single(int category, Lc_t* lc, unsigned int flags)
818da2e3ebdSchin {
819da2e3ebdSchin 	const char*	sys;
820da2e3ebdSchin 	int		i;
821da2e3ebdSchin 
822*3e14f97fSRoger A. Faulkner 	if (flags & (LC_setenv|LC_setlocale))
823*3e14f97fSRoger A. Faulkner 	{
824*3e14f97fSRoger A. Faulkner 		if (!(ast.locale.set & AST_LC_internal))
825*3e14f97fSRoger A. Faulkner 			lc_categories[category].prev = lc;
826*3e14f97fSRoger A. Faulkner 		if ((flags & LC_setenv) && lc_all && locales[category])
827*3e14f97fSRoger A. Faulkner 			return (char*)locales[category]->name;
828*3e14f97fSRoger A. Faulkner 	}
829*3e14f97fSRoger A. Faulkner 	if (!lc && (!(lc_categories[category].flags & LC_setlocale) || !(lc = lc_categories[category].prev)) && !(lc = lc_all) && !(lc = lc_categories[category].prev) && !(lc = lang))
830da2e3ebdSchin 		lc = lcmake(NiL);
831*3e14f97fSRoger A. Faulkner 	sys = 0;
832da2e3ebdSchin 	if (locales[category] != lc)
833da2e3ebdSchin 	{
8347c2fbfb3SApril Chin 		if (lc_categories[category].external == -lc_categories[category].internal)
835da2e3ebdSchin 		{
836da2e3ebdSchin 			for (i = 1; i < AST_LC_COUNT; i++)
837da2e3ebdSchin 				if (locales[i] == lc)
838da2e3ebdSchin 				{
839da2e3ebdSchin 					sys = (char*)lc->name;
840da2e3ebdSchin 					break;
841da2e3ebdSchin 				}
842da2e3ebdSchin 		}
843da2e3ebdSchin 		else if (lc->flags & (LC_debug|LC_local))
8447c2fbfb3SApril Chin 			sys = setlocale(lc_categories[category].external, lcmake(NiL)->name);
8457c2fbfb3SApril Chin 		else if (!(sys = setlocale(lc_categories[category].external, lc->name)) &&
8467c2fbfb3SApril Chin 			 (streq(lc->name, lc->code) || !(sys = setlocale(lc_categories[category].external, lc->code))) &&
847da2e3ebdSchin 			 !streq(lc->code, lc->language->code))
8487c2fbfb3SApril Chin 				sys = setlocale(lc_categories[category].external, lc->language->code);
849da2e3ebdSchin 		if (!sys)
850da2e3ebdSchin 		{
851da2e3ebdSchin 			/*
852da2e3ebdSchin 			 * check for local override
853da2e3ebdSchin 			 * currently this means an LC_MESSAGES dir exists
854da2e3ebdSchin 			 */
855da2e3ebdSchin 
856da2e3ebdSchin 			if (!(lc->flags & LC_checked))
857da2e3ebdSchin 			{
858da2e3ebdSchin 				char	path[PATH_MAX];
859da2e3ebdSchin 
860da2e3ebdSchin 				if (mcfind(path, lc->code, NiL, LC_MESSAGES, 0))
861da2e3ebdSchin 					lc->flags |= LC_local;
862da2e3ebdSchin 				lc->flags |= LC_checked;
863da2e3ebdSchin 			}
864da2e3ebdSchin 			if (!(lc->flags & LC_local))
865da2e3ebdSchin 				return 0;
8667c2fbfb3SApril Chin 			if (lc_categories[category].external != -lc_categories[category].internal)
8677c2fbfb3SApril Chin 				setlocale(lc_categories[category].external, lcmake(NiL)->name);
868da2e3ebdSchin 		}
869da2e3ebdSchin 		locales[category] = lc;
8707c2fbfb3SApril Chin 		if (lc_categories[category].setf && (*lc_categories[category].setf)(&lc_categories[category]))
871da2e3ebdSchin 		{
8727c2fbfb3SApril Chin 			locales[category] = lc_categories[category].prev;
873da2e3ebdSchin 			return 0;
874da2e3ebdSchin 		}
87534f9b3eeSRoland Mainz 		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'))
876da2e3ebdSchin 			ast.locale.set &= ~(1<<category);
877da2e3ebdSchin 		else
878da2e3ebdSchin 			ast.locale.set |= (1<<category);
879da2e3ebdSchin 	}
880*3e14f97fSRoger A. Faulkner 	else if (lc_categories[category].flags ^ flags)
881*3e14f97fSRoger A. Faulkner 	{
882*3e14f97fSRoger A. Faulkner 		lc_categories[category].flags &= ~(LC_setenv|LC_setlocale);
883*3e14f97fSRoger A. Faulkner 		lc_categories[category].flags |= flags;
884*3e14f97fSRoger A. Faulkner 	}
885*3e14f97fSRoger A. Faulkner 	else
886*3e14f97fSRoger A. Faulkner 		return (char*)lc->name;
887*3e14f97fSRoger A. Faulkner 	if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
888*3e14f97fSRoger A. Faulkner 		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]" : "");
889da2e3ebdSchin 	return (char*)lc->name;
890da2e3ebdSchin }
891da2e3ebdSchin 
892da2e3ebdSchin /*
893da2e3ebdSchin  * set composite AST_LC_ALL locale categories
894da2e3ebdSchin  * return <0:composite-error 0:not-composite >0:composite-ok
895da2e3ebdSchin  */
896da2e3ebdSchin 
897da2e3ebdSchin static int
composite(register const char * s,int initialize)898da2e3ebdSchin composite(register const char* s, int initialize)
899da2e3ebdSchin {
900da2e3ebdSchin 	register const char*	t;
901da2e3ebdSchin 	register int		i;
902da2e3ebdSchin 	register int		j;
903da2e3ebdSchin 	register int		k;
904da2e3ebdSchin 	int			n;
90534f9b3eeSRoland Mainz 	int			m;
906da2e3ebdSchin 	const char*		w;
907da2e3ebdSchin 	Lc_t*			p;
908da2e3ebdSchin 	int			cat[AST_LC_COUNT];
909da2e3ebdSchin 	int			stk[AST_LC_COUNT];
910da2e3ebdSchin 	char			buf[PATH_MAX / 2];
911da2e3ebdSchin 
912da2e3ebdSchin 	k = n = 0;
913da2e3ebdSchin 	while (s[0] == 'L' && s[1] == 'C' && s[2] == '_')
914da2e3ebdSchin 	{
915da2e3ebdSchin 		n++;
916da2e3ebdSchin 		j = 0;
917da2e3ebdSchin 		w = s;
918da2e3ebdSchin 		for (i = 1; i < AST_LC_COUNT; i++)
919da2e3ebdSchin 		{
920da2e3ebdSchin 			s = w;
9217c2fbfb3SApril Chin 			t = lc_categories[i].name;
922da2e3ebdSchin 			while (*t && *s++ == *t++);
923da2e3ebdSchin 			if (!*t && *s++ == '=')
924da2e3ebdSchin 			{
925da2e3ebdSchin 				cat[j++] = i;
926da2e3ebdSchin 				if (s[0] != 'L' || s[1] != 'C' || s[2] != '_')
927da2e3ebdSchin 					break;
928da2e3ebdSchin 				w = s;
929da2e3ebdSchin 				i = -1;
930da2e3ebdSchin 			}
931da2e3ebdSchin 		}
932da2e3ebdSchin 		for (s = w; *s && *s != '='; s++);
933da2e3ebdSchin 		if (!*s)
934da2e3ebdSchin 		{
935da2e3ebdSchin 			for (i = 0; i < k; i++)
936*3e14f97fSRoger A. Faulkner 				single(stk[i], NiL, 0);
937da2e3ebdSchin 			return -1;
938da2e3ebdSchin 		}
939da2e3ebdSchin 		w = ++s;
940da2e3ebdSchin 		for (;;)
941da2e3ebdSchin 		{
942da2e3ebdSchin 			if (!*s)
943da2e3ebdSchin 			{
944da2e3ebdSchin 				p = lcmake(w);
945da2e3ebdSchin 				break;
946da2e3ebdSchin 			}
947da2e3ebdSchin 			else if (*s++ == ';')
948da2e3ebdSchin 			{
94934f9b3eeSRoland Mainz 				if ((m = s - w - 1) >= sizeof(buf))
95034f9b3eeSRoland Mainz 					m = sizeof(buf) - 1;
95134f9b3eeSRoland Mainz 				memcpy(buf, w, m);
95234f9b3eeSRoland Mainz 				buf[m] = 0;
953da2e3ebdSchin 				p = lcmake(buf);
954da2e3ebdSchin 				break;
955da2e3ebdSchin 			}
956da2e3ebdSchin 		}
957da2e3ebdSchin 		for (i = 0; i < j; i++)
958da2e3ebdSchin 			if (!initialize)
959da2e3ebdSchin 			{
960*3e14f97fSRoger A. Faulkner 				if (!single(cat[i], p, 0))
961da2e3ebdSchin 				{
962da2e3ebdSchin 					for (i = 0; i < k; i++)
963*3e14f97fSRoger A. Faulkner 						single(stk[i], NiL, 0);
964da2e3ebdSchin 					return -1;
965da2e3ebdSchin 				}
966da2e3ebdSchin 				stk[k++] = cat[i];
967da2e3ebdSchin 			}
968*3e14f97fSRoger A. Faulkner 			else if (!lc_categories[cat[i]].prev && !(ast.locale.set & AST_LC_internal))
9697c2fbfb3SApril Chin 				lc_categories[cat[i]].prev = p;
970da2e3ebdSchin 	}
97134f9b3eeSRoland Mainz 	while (s[0] == '/' && s[1] && n < (AST_LC_COUNT - 1))
972da2e3ebdSchin 	{
973da2e3ebdSchin 		n++;
974da2e3ebdSchin 		for (w = ++s; *s && *s != '/'; s++);
975da2e3ebdSchin 		if (!*s)
976da2e3ebdSchin 			p = lcmake(w);
977da2e3ebdSchin 		else
978da2e3ebdSchin 		{
979da2e3ebdSchin 			if ((j = s - w - 1) >= sizeof(buf))
980da2e3ebdSchin 				j = sizeof(buf) - 1;
981da2e3ebdSchin 			memcpy(buf, w, j);
982da2e3ebdSchin 			buf[j] = 0;
983da2e3ebdSchin 			p = lcmake(buf);
984da2e3ebdSchin 		}
985da2e3ebdSchin 		if (!initialize)
986da2e3ebdSchin 		{
987*3e14f97fSRoger A. Faulkner 			if (!single(n, p, 0))
988da2e3ebdSchin 			{
989da2e3ebdSchin 				for (i = 1; i < n; i++)
990*3e14f97fSRoger A. Faulkner 					single(i, NiL, 0);
991da2e3ebdSchin 				return -1;
992da2e3ebdSchin 			}
993da2e3ebdSchin 		}
994*3e14f97fSRoger A. Faulkner 		else if (!lc_categories[n].prev && !(ast.locale.set & AST_LC_internal))
9957c2fbfb3SApril Chin 			lc_categories[n].prev = p;
996da2e3ebdSchin 	}
997da2e3ebdSchin 	return n;
998da2e3ebdSchin }
999da2e3ebdSchin 
1000da2e3ebdSchin /*
1001da2e3ebdSchin  * setlocale() intercept
100234f9b3eeSRoland Mainz  *
100334f9b3eeSRoland Mainz  * locale:
100434f9b3eeSRoland Mainz  *	0	query
1005*3e14f97fSRoger A. Faulkner  *	""	initialize from environment (if LC_ALL)
1006*3e14f97fSRoger A. Faulkner  *	""	AST_LC_setenv: value unset (defer to LANG)
1007*3e14f97fSRoger A. Faulkner  *	"*"	AST_LC_setenv: value set (defer to LC_ALL)
1008*3e14f97fSRoger A. Faulkner  *	*	set (override LC_ALL)
1009da2e3ebdSchin  */
1010da2e3ebdSchin 
1011da2e3ebdSchin char*
_ast_setlocale(int category,const char * locale)1012da2e3ebdSchin _ast_setlocale(int category, const char* locale)
1013da2e3ebdSchin {
1014da2e3ebdSchin 	register char*		s;
1015da2e3ebdSchin 	register int		i;
1016da2e3ebdSchin 	register int		j;
1017da2e3ebdSchin 	int			k;
1018*3e14f97fSRoger A. Faulkner 	int			f;
1019da2e3ebdSchin 	Lc_t*			p;
1020da2e3ebdSchin 	int			cat[AST_LC_COUNT];
1021da2e3ebdSchin 
1022da2e3ebdSchin 	static Sfio_t*		sp;
1023da2e3ebdSchin 	static int		initialized;
1024*3e14f97fSRoger A. Faulkner 	static const char	local[] = "local";
1025da2e3ebdSchin 
1026da2e3ebdSchin 	if ((category = lcindex(category, 0)) < 0)
1027da2e3ebdSchin 		return 0;
1028da2e3ebdSchin 	if (!locale)
1029da2e3ebdSchin 	{
1030da2e3ebdSchin 		/*
1031da2e3ebdSchin 		 * return the current state
1032da2e3ebdSchin 		 */
1033da2e3ebdSchin 
1034da2e3ebdSchin 	compose:
103534f9b3eeSRoland Mainz 		if (category != AST_LC_ALL && category != AST_LC_LANG)
1036da2e3ebdSchin 			return (char*)locales[category]->name;
1037da2e3ebdSchin 		if (!sp && !(sp = sfstropen()))
1038da2e3ebdSchin 			return 0;
1039da2e3ebdSchin 		for (i = 1; i < AST_LC_COUNT; i++)
1040da2e3ebdSchin 			cat[i] = -1;
1041da2e3ebdSchin 		for (i = 1, k = 0; i < AST_LC_COUNT; i++)
1042da2e3ebdSchin 			if (cat[i] < 0)
1043da2e3ebdSchin 			{
1044da2e3ebdSchin 				k++;
1045da2e3ebdSchin 				cat[i] = i;
1046da2e3ebdSchin 				for (j = i + 1; j < AST_LC_COUNT; j++)
1047da2e3ebdSchin 					if (locales[j] == locales[i])
1048da2e3ebdSchin 						cat[j] = i;
1049da2e3ebdSchin 			}
1050da2e3ebdSchin 		if (k == 1)
1051da2e3ebdSchin 			return (char*)locales[1]->name;
1052da2e3ebdSchin 		for (i = 1; i < AST_LC_COUNT; i++)
1053da2e3ebdSchin 			if (cat[i] >= 0 && !(locales[i]->flags & LC_default))
1054da2e3ebdSchin 			{
1055da2e3ebdSchin 				if (sfstrtell(sp))
1056da2e3ebdSchin 					sfprintf(sp, ";");
1057da2e3ebdSchin 				for (j = i, k = cat[i]; j < AST_LC_COUNT; j++)
1058da2e3ebdSchin 					if (cat[j] == k)
1059da2e3ebdSchin 					{
1060da2e3ebdSchin 						cat[j] = -1;
10617c2fbfb3SApril Chin 						sfprintf(sp, "%s=", lc_categories[j].name);
1062da2e3ebdSchin 					}
1063da2e3ebdSchin 				sfprintf(sp, "%s", locales[i]->name);
1064da2e3ebdSchin 			}
1065da2e3ebdSchin 		if (!sfstrtell(sp))
1066da2e3ebdSchin 			return (char*)locales[0]->name;
1067da2e3ebdSchin 		return sfstruse(sp);
1068da2e3ebdSchin 	}
1069da2e3ebdSchin 	if (!ast.locale.serial++)
107034f9b3eeSRoland Mainz 	{
1071da2e3ebdSchin 		stropt(getenv("LC_OPTIONS"), options, sizeof(*options), setopt, NiL);
107234f9b3eeSRoland Mainz 		initialized = 0;
107334f9b3eeSRoland Mainz 	}
1074*3e14f97fSRoger A. Faulkner 	if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
1075*3e14f97fSRoger A. Faulkner 		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*3e14f97fSRoger A. Faulkner 	if (ast.locale.set & AST_LC_setenv)
1077*3e14f97fSRoger A. Faulkner 	{
1078*3e14f97fSRoger A. Faulkner 		f = LC_setenv;
1079*3e14f97fSRoger A. Faulkner 		p = *locale ? lcmake(locale) : (Lc_t*)0;
1080*3e14f97fSRoger A. Faulkner 	}
1081*3e14f97fSRoger A. Faulkner 	else if (*locale)
1082*3e14f97fSRoger A. Faulkner 	{
1083*3e14f97fSRoger A. Faulkner 		f = LC_setlocale;
1084*3e14f97fSRoger A. Faulkner 		p = lcmake(locale);
1085*3e14f97fSRoger A. Faulkner 	}
1086*3e14f97fSRoger A. Faulkner 	else if (category == AST_LC_ALL)
1087*3e14f97fSRoger A. Faulkner 	{
1088*3e14f97fSRoger A. Faulkner 		if (!initialized)
1089da2e3ebdSchin 		{
1090da2e3ebdSchin 			char*	u;
1091da2e3ebdSchin 			char	tmp[256];
1092da2e3ebdSchin 
1093da2e3ebdSchin 			/*
1094da2e3ebdSchin 			 * initialize from the environment
1095da2e3ebdSchin 			 * precedence determined by X/Open
1096da2e3ebdSchin 			 */
1097da2e3ebdSchin 
1098da2e3ebdSchin 			u = 0;
109934f9b3eeSRoland Mainz 			if ((s = getenv("LANG")) && *s)
1100da2e3ebdSchin 			{
110134f9b3eeSRoland Mainz 				if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
110234f9b3eeSRoland Mainz 					s = u;
110334f9b3eeSRoland Mainz 				lang = lcmake(s);
110434f9b3eeSRoland Mainz 			}
110534f9b3eeSRoland Mainz 			else
110634f9b3eeSRoland Mainz 				lang = 0;
110734f9b3eeSRoland Mainz 			if ((s = getenv("LC_ALL")) && *s)
110834f9b3eeSRoland Mainz 			{
110934f9b3eeSRoland Mainz 				if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
111034f9b3eeSRoland Mainz 					s = u;
111134f9b3eeSRoland Mainz 				lc_all = lcmake(s);
111234f9b3eeSRoland Mainz 			}
111334f9b3eeSRoland Mainz 			else
111434f9b3eeSRoland Mainz 				lc_all = 0;
1115da2e3ebdSchin 			for (i = 1; i < AST_LC_COUNT; i++)
1116*3e14f97fSRoger A. Faulkner 				if (lc_categories[i].flags & LC_setlocale)
1117*3e14f97fSRoger A. Faulkner 					/* explicitly set by setlocale() */;
1118*3e14f97fSRoger A. Faulkner 				else if ((s = getenv(lc_categories[i].name)) && *s)
1119da2e3ebdSchin 				{
1120da2e3ebdSchin 					if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
1121da2e3ebdSchin 						s = u;
11227c2fbfb3SApril Chin 					lc_categories[i].prev = lcmake(s);
1123da2e3ebdSchin 				}
112434f9b3eeSRoland Mainz 				else
112534f9b3eeSRoland Mainz 					lc_categories[i].prev = 0;
1126da2e3ebdSchin 			for (i = 1; i < AST_LC_COUNT; i++)
1127*3e14f97fSRoger A. Faulkner 				if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
1128da2e3ebdSchin 				{
112934f9b3eeSRoland Mainz 					while (i--)
1130*3e14f97fSRoger A. Faulkner 						single(i, NiL, 0);
113134f9b3eeSRoland Mainz 					return 0;
1132da2e3ebdSchin 				}
113334f9b3eeSRoland Mainz 			if (ast.locale.set & AST_LC_debug)
113434f9b3eeSRoland Mainz 				for (i = 1; i < AST_LC_COUNT; i++)
1135*3e14f97fSRoger A. Faulkner 					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);
113634f9b3eeSRoland Mainz 			initialized = 1;
1137*3e14f97fSRoger A. Faulkner 		}
113834f9b3eeSRoland Mainz 		goto compose;
113934f9b3eeSRoland Mainz 	}
114034f9b3eeSRoland Mainz 	else if (category == AST_LC_LANG || !(p = lc_categories[category].prev))
1141*3e14f97fSRoger A. Faulkner 	{
1142*3e14f97fSRoger A. Faulkner 		f = 0;
114334f9b3eeSRoland Mainz 		p = lcmake("C");
1144*3e14f97fSRoger A. Faulkner 	}
1145*3e14f97fSRoger A. Faulkner 	else
1146*3e14f97fSRoger A. Faulkner 		f = 0;
114734f9b3eeSRoland Mainz 	if (category == AST_LC_LANG)
114834f9b3eeSRoland Mainz 	{
114934f9b3eeSRoland Mainz 		if (lang != p)
115034f9b3eeSRoland Mainz 		{
115134f9b3eeSRoland Mainz 			lang = p;
115234f9b3eeSRoland Mainz 			if (!lc_all)
115334f9b3eeSRoland Mainz 				for (i = 1; i < AST_LC_COUNT; i++)
1154*3e14f97fSRoger A. Faulkner 					if (!single(i, lc_categories[i].prev, 0))
1155da2e3ebdSchin 					{
1156da2e3ebdSchin 						while (i--)
1157*3e14f97fSRoger A. Faulkner 							single(i, NiL, 0);
1158da2e3ebdSchin 						return 0;
1159da2e3ebdSchin 					}
1160da2e3ebdSchin 		}
1161da2e3ebdSchin 	}
116234f9b3eeSRoland Mainz 	else if (category != AST_LC_ALL)
1163*3e14f97fSRoger A. Faulkner 	{
1164*3e14f97fSRoger A. Faulkner 		if (f || !lc_all)
1165*3e14f97fSRoger A. Faulkner 			return single(category, p, f);
1166*3e14f97fSRoger A. Faulkner 		if (p && !(ast.locale.set & AST_LC_internal))
1167*3e14f97fSRoger A. Faulkner 			lc_categories[category].prev = p;
1168*3e14f97fSRoger A. Faulkner 		return (char*)locales[category]->name;
1169*3e14f97fSRoger A. Faulkner 	}
1170*3e14f97fSRoger A. Faulkner 	else if (composite(locale, 0) < 0)
1171da2e3ebdSchin 		return 0;
117234f9b3eeSRoland Mainz 	else if (lc_all != p)
117334f9b3eeSRoland Mainz 	{
117434f9b3eeSRoland Mainz 		lc_all = p;
1175da2e3ebdSchin 		for (i = 1; i < AST_LC_COUNT; i++)
1176*3e14f97fSRoger A. Faulkner 			if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
1177da2e3ebdSchin 			{
1178da2e3ebdSchin 				while (i--)
1179*3e14f97fSRoger A. Faulkner 					single(i, NiL, 0);
1180da2e3ebdSchin 				return 0;
1181da2e3ebdSchin 			}
1182da2e3ebdSchin 	}
1183da2e3ebdSchin 	goto compose;
1184da2e3ebdSchin }
1185