xref: /titanic_44/usr/src/lib/libast/common/port/lc.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  * locale state implementation
26da2e3ebdSchin  */
27da2e3ebdSchin 
28da2e3ebdSchin #include "lclib.h"
297c2fbfb3SApril Chin #include "lclang.h"
30da2e3ebdSchin 
31da2e3ebdSchin #include <ctype.h>
32da2e3ebdSchin 
33da2e3ebdSchin static Lc_numeric_t	default_numeric = { '.', -1 };
34da2e3ebdSchin 
35da2e3ebdSchin static Lc_t		default_lc =
36da2e3ebdSchin {
37da2e3ebdSchin 	"C",
38da2e3ebdSchin 	"POSIX",
397c2fbfb3SApril Chin 	&lc_languages[0],
407c2fbfb3SApril Chin 	&lc_territories[0],
417c2fbfb3SApril Chin 	&lc_charsets[0],
42da2e3ebdSchin 	0,
43da2e3ebdSchin 	LC_default|LC_checked|LC_local,
44da2e3ebdSchin 	0,
45da2e3ebdSchin 	{
46da2e3ebdSchin 		{ &default_lc, 0, 0 },
47da2e3ebdSchin 		{ &default_lc, 0, 0 },
48da2e3ebdSchin 		{ &default_lc, 0, 0 },
49da2e3ebdSchin 		{ &default_lc, 0, 0 },
50da2e3ebdSchin 		{ &default_lc, 0, 0 },
51da2e3ebdSchin 		{ &default_lc, 0, (void*)&default_numeric },
52da2e3ebdSchin 		{ &default_lc, 0, 0 },
53da2e3ebdSchin 		{ &default_lc, 0, 0 },
54da2e3ebdSchin 		{ &default_lc, 0, 0 },
55da2e3ebdSchin 		{ &default_lc, 0, 0 },
56da2e3ebdSchin 		{ &default_lc, 0, 0 },
57da2e3ebdSchin 		{ &default_lc, 0, 0 },
58da2e3ebdSchin 		{ &default_lc, 0, 0 },
59da2e3ebdSchin 		{ &default_lc, 0, 0 }
60da2e3ebdSchin 	}
61da2e3ebdSchin };
62da2e3ebdSchin 
63da2e3ebdSchin static Lc_numeric_t	debug_numeric = { ',', '.' };
64da2e3ebdSchin 
65da2e3ebdSchin static Lc_t		debug_lc =
66da2e3ebdSchin {
67da2e3ebdSchin 	"debug",
68da2e3ebdSchin 	"debug",
697c2fbfb3SApril Chin 	&lc_languages[1],
707c2fbfb3SApril Chin 	&lc_territories[1],
717c2fbfb3SApril Chin 	&lc_charsets[0],
72da2e3ebdSchin 	0,
73da2e3ebdSchin 	LC_debug|LC_checked|LC_local,
74da2e3ebdSchin 	0,
75da2e3ebdSchin 	{
76da2e3ebdSchin 		{ &debug_lc, 0, 0 },
77da2e3ebdSchin 		{ &debug_lc, 0, 0 },
78da2e3ebdSchin 		{ &debug_lc, 0, 0 },
79da2e3ebdSchin 		{ &debug_lc, 0, 0 },
80da2e3ebdSchin 		{ &debug_lc, 0, 0 },
81da2e3ebdSchin 		{ &debug_lc, 0, (void*)&debug_numeric },
82da2e3ebdSchin 		{ &debug_lc, 0, 0 },
83da2e3ebdSchin 		{ &debug_lc, 0, 0 },
84da2e3ebdSchin 		{ &debug_lc, 0, 0 },
85da2e3ebdSchin 		{ &debug_lc, 0, 0 },
86da2e3ebdSchin 		{ &debug_lc, 0, 0 },
87da2e3ebdSchin 		{ &debug_lc, 0, 0 },
88da2e3ebdSchin 		{ &debug_lc, 0, 0 },
89da2e3ebdSchin 		{ &debug_lc, 0, 0 }
90da2e3ebdSchin 	},
91da2e3ebdSchin 	&default_lc
92da2e3ebdSchin };
93da2e3ebdSchin 
94da2e3ebdSchin static Lc_t*		lcs = &debug_lc;
95da2e3ebdSchin 
96da2e3ebdSchin Lc_t*			locales[] =
97da2e3ebdSchin {
98da2e3ebdSchin 	&default_lc,
99da2e3ebdSchin 	&default_lc,
100da2e3ebdSchin 	&default_lc,
101da2e3ebdSchin 	&default_lc,
102da2e3ebdSchin 	&default_lc,
103da2e3ebdSchin 	&default_lc,
104da2e3ebdSchin 	&default_lc,
105da2e3ebdSchin 	&default_lc,
106da2e3ebdSchin 	&default_lc,
107da2e3ebdSchin 	&default_lc,
108da2e3ebdSchin 	&default_lc,
109da2e3ebdSchin 	&default_lc,
110da2e3ebdSchin 	&default_lc,
111da2e3ebdSchin 	&default_lc
112da2e3ebdSchin };
113da2e3ebdSchin 
114da2e3ebdSchin /*
115da2e3ebdSchin  * return the internal category index for category
116da2e3ebdSchin  */
117da2e3ebdSchin 
118da2e3ebdSchin int
lcindex(int category,int min)119da2e3ebdSchin lcindex(int category, int min)
120da2e3ebdSchin {
121da2e3ebdSchin 	switch (category)
122da2e3ebdSchin 	{
123da2e3ebdSchin 	case LC_ALL:		return min ? -1 : AST_LC_ALL;
124da2e3ebdSchin 	case LC_ADDRESS:	return AST_LC_ADDRESS;
125da2e3ebdSchin 	case LC_COLLATE:	return AST_LC_COLLATE;
126da2e3ebdSchin 	case LC_CTYPE:		return AST_LC_CTYPE;
127da2e3ebdSchin 	case LC_IDENTIFICATION:	return AST_LC_IDENTIFICATION;
12834f9b3eeSRoland Mainz 	case LC_LANG:		return AST_LC_LANG;
129da2e3ebdSchin 	case LC_MEASUREMENT:	return AST_LC_MEASUREMENT;
130da2e3ebdSchin 	case LC_MESSAGES:	return AST_LC_MESSAGES;
131da2e3ebdSchin 	case LC_MONETARY:	return AST_LC_MONETARY;
132da2e3ebdSchin 	case LC_NAME:		return AST_LC_NAME;
133da2e3ebdSchin 	case LC_NUMERIC:	return AST_LC_NUMERIC;
134da2e3ebdSchin 	case LC_PAPER:		return AST_LC_PAPER;
135da2e3ebdSchin 	case LC_TELEPHONE:	return AST_LC_TELEPHONE;
136da2e3ebdSchin 	case LC_TIME:		return AST_LC_TIME;
137da2e3ebdSchin 	case LC_XLITERATE:	return AST_LC_XLITERATE;
138da2e3ebdSchin 	}
139da2e3ebdSchin 	return -1;
140da2e3ebdSchin }
141da2e3ebdSchin 
142da2e3ebdSchin /*
143da2e3ebdSchin  * return the first category table entry
144da2e3ebdSchin  */
145da2e3ebdSchin 
146da2e3ebdSchin Lc_category_t*
lccategories(void)147da2e3ebdSchin lccategories(void)
148da2e3ebdSchin {
1497c2fbfb3SApril Chin 	return (Lc_category_t*)&lc_categories[0];
150da2e3ebdSchin }
151da2e3ebdSchin 
152da2e3ebdSchin /*
153da2e3ebdSchin  * return the current info for category
154da2e3ebdSchin  */
155da2e3ebdSchin 
156da2e3ebdSchin Lc_info_t*
lcinfo(register int category)157da2e3ebdSchin lcinfo(register int category)
158da2e3ebdSchin {
159da2e3ebdSchin 	if ((category = lcindex(category, 0)) < 0)
160da2e3ebdSchin 		return 0;
161da2e3ebdSchin 	return LCINFO(category);
162da2e3ebdSchin }
163da2e3ebdSchin 
164da2e3ebdSchin /*
165da2e3ebdSchin  * return 1 if s matches the alternation pattern p
166da2e3ebdSchin  * if minimum!=0 then at least that many chars must match
167da2e3ebdSchin  * if standard!=0 and s[0] is a digit leading non-digits are ignored in p
168da2e3ebdSchin  */
169da2e3ebdSchin 
170da2e3ebdSchin static int
match(const char * s,register const char * p,int minimum,int standard)171da2e3ebdSchin match(const char* s, register const char* p, int minimum, int standard)
172da2e3ebdSchin {
173da2e3ebdSchin 	register const char*	t;
174da2e3ebdSchin 	const char*		x;
175da2e3ebdSchin 	int			w;
176da2e3ebdSchin 	int			z;
177da2e3ebdSchin 
178da2e3ebdSchin 	z = 0;
179da2e3ebdSchin 	do
180da2e3ebdSchin 	{
181da2e3ebdSchin 		t = s;
182da2e3ebdSchin 		if (standard)
183da2e3ebdSchin 		{
184da2e3ebdSchin 			if (isdigit(*t))
185da2e3ebdSchin 				while (*p && !isdigit(*p))
186da2e3ebdSchin 					p++;
187da2e3ebdSchin 			else if (isdigit(*p))
188da2e3ebdSchin 				while (*t && !isdigit(*t))
189da2e3ebdSchin 					t++;
190da2e3ebdSchin 		}
191da2e3ebdSchin 		if (*p)
192da2e3ebdSchin 		{
193da2e3ebdSchin 			w = 0;
194da2e3ebdSchin 			x = p;
195da2e3ebdSchin 			while (*p && *p != '|')
196da2e3ebdSchin 			{
197da2e3ebdSchin 				if (!*t || *t == ',')
198da2e3ebdSchin 					break;
199da2e3ebdSchin 				else if (*t == *p)
200da2e3ebdSchin 					/*ok*/;
201da2e3ebdSchin 				else if (*t == '-')
202da2e3ebdSchin 				{
203da2e3ebdSchin 					if (standard && isdigit(*p))
204da2e3ebdSchin 					{
205da2e3ebdSchin 						t++;
206da2e3ebdSchin 						continue;
207da2e3ebdSchin 					}
208da2e3ebdSchin 					while (*p && *p != '-')
209da2e3ebdSchin 						p++;
210da2e3ebdSchin 					if (!*p)
211da2e3ebdSchin 						break;
212da2e3ebdSchin 				}
213da2e3ebdSchin 				else if (*p == '-')
214da2e3ebdSchin 				{
215da2e3ebdSchin 					if (standard && isdigit(*t))
216da2e3ebdSchin 					{
217da2e3ebdSchin 						p++;
218da2e3ebdSchin 						continue;
219da2e3ebdSchin 					}
220da2e3ebdSchin 					w = 1;
221da2e3ebdSchin 					while (*t && *t != '-')
222da2e3ebdSchin 						t++;
223da2e3ebdSchin 					if (!*t)
224da2e3ebdSchin 						break;
225da2e3ebdSchin 				}
226da2e3ebdSchin 				else
227da2e3ebdSchin 					break;
228da2e3ebdSchin 				t++;
229da2e3ebdSchin 				p++;
230da2e3ebdSchin 			}
231da2e3ebdSchin 			if ((!*t || *t == ',') && (!*p || *p == '|' || w))
232da2e3ebdSchin 				return p - x;
233da2e3ebdSchin 			if (minimum && z < (p - x) && (p - x) >= minimum)
234da2e3ebdSchin 				z = p - x;
235da2e3ebdSchin 		}
236da2e3ebdSchin 		while (*p && *p != '|')
237da2e3ebdSchin 			p++;
238da2e3ebdSchin 	} while (*p++);
239da2e3ebdSchin 	return z;
240da2e3ebdSchin }
241da2e3ebdSchin 
242da2e3ebdSchin /*
243da2e3ebdSchin  * return 1 if s matches the charset names in cp
244da2e3ebdSchin  */
245da2e3ebdSchin 
246da2e3ebdSchin static int
match_charset(register const char * s,register const Lc_charset_t * cp)247da2e3ebdSchin match_charset(register const char* s, register const Lc_charset_t* cp)
248da2e3ebdSchin {
249da2e3ebdSchin 	return match(s, cp->code, 0, 1) || match(s, cp->alternates, 3, 1) || cp->ms && match(s, cp->ms, 0, 1);
250da2e3ebdSchin }
251da2e3ebdSchin 
252da2e3ebdSchin /*
253da2e3ebdSchin  * low level for lccanon
254da2e3ebdSchin  */
255da2e3ebdSchin 
256da2e3ebdSchin static size_t
canonical(const Lc_language_t * lp,const Lc_territory_t * tp,const Lc_charset_t * cp,const Lc_attribute_list_t * ap,unsigned long flags,char * buf,size_t siz)257da2e3ebdSchin canonical(const Lc_language_t* lp, const Lc_territory_t* tp, const Lc_charset_t* cp, const Lc_attribute_list_t* ap, unsigned long flags, char* buf, size_t siz)
258da2e3ebdSchin {
259da2e3ebdSchin 	register int		c;
260da2e3ebdSchin 	register int		u;
261da2e3ebdSchin 	register char*		s;
262da2e3ebdSchin 	register char*		e;
263da2e3ebdSchin 	register const char*	t;
264da2e3ebdSchin 
265da2e3ebdSchin 	if (!(flags & (LC_abbreviated|LC_default|LC_local|LC_qualified|LC_verbose)))
266da2e3ebdSchin 		flags |= LC_abbreviated;
267da2e3ebdSchin 	s = buf;
268da2e3ebdSchin 	e = &buf[siz - 3];
269da2e3ebdSchin 	if (lp)
270da2e3ebdSchin 	{
271da2e3ebdSchin 		if (lp->flags & (LC_debug|LC_default))
272da2e3ebdSchin 		{
273da2e3ebdSchin 			for (t = lp->code; s < e && (*s = *t++); s++);
274da2e3ebdSchin 			*s++ = 0;
275da2e3ebdSchin 			return s - buf;
276da2e3ebdSchin 		}
277da2e3ebdSchin 		if (flags & LC_verbose)
278da2e3ebdSchin 		{
279da2e3ebdSchin 			u = 1;
280da2e3ebdSchin 			t = lp->name;
281da2e3ebdSchin 			while (s < e && (c = *t++))
282da2e3ebdSchin 			{
283da2e3ebdSchin 				if (u)
284da2e3ebdSchin 				{
285da2e3ebdSchin 					u = 0;
286da2e3ebdSchin 					c = toupper(c);
287da2e3ebdSchin 				}
288da2e3ebdSchin 				else if (!isalnum(c))
289da2e3ebdSchin 					u = 1;
290da2e3ebdSchin 				*s++ = c;
291da2e3ebdSchin 			}
292da2e3ebdSchin 		}
293da2e3ebdSchin 		else
294da2e3ebdSchin 			for (t = lp->code; s < e && (*s = *t++); s++);
295da2e3ebdSchin 	}
296da2e3ebdSchin 	if (s < e)
297da2e3ebdSchin 	{
2987c2fbfb3SApril Chin 		if (tp && tp != &lc_territories[0] && (!(flags & (LC_abbreviated|LC_default)) || !lp || !streq(lp->code, tp->code)))
299da2e3ebdSchin 		{
300da2e3ebdSchin 			if (lp)
301da2e3ebdSchin 				*s++ = '_';
302da2e3ebdSchin 			if (flags & LC_verbose)
303da2e3ebdSchin 			{
304da2e3ebdSchin 				u = 1;
305da2e3ebdSchin 				t = tp->name;
306da2e3ebdSchin 				while (s < e && (c = *t++) && c != '|')
307da2e3ebdSchin 				{
308da2e3ebdSchin 					if (u)
309da2e3ebdSchin 					{
310da2e3ebdSchin 						u = 0;
311da2e3ebdSchin 						c = toupper(c);
312da2e3ebdSchin 					}
313da2e3ebdSchin 					else if (!isalnum(c))
314da2e3ebdSchin 						u = 1;
315da2e3ebdSchin 					*s++ = c;
316da2e3ebdSchin 				}
317da2e3ebdSchin 			}
318da2e3ebdSchin 			else
319da2e3ebdSchin 				for (t = tp->code; s < e && (*s = toupper(*t++)); s++);
320da2e3ebdSchin 		}
321da2e3ebdSchin 		if (lp && (!(flags & (LC_abbreviated|LC_default)) || cp != lp->charset) && s < e)
322da2e3ebdSchin 		{
323da2e3ebdSchin 			*s++ = '.';
324da2e3ebdSchin 			for (t = cp->code; s < e && (c = *t++); s++)
325da2e3ebdSchin 			{
326da2e3ebdSchin 				if (islower(c))
327da2e3ebdSchin 					c = toupper(c);
328da2e3ebdSchin 				*s = c;
329da2e3ebdSchin 			}
330da2e3ebdSchin 		}
331da2e3ebdSchin 		for (c = '@'; ap && s < e; ap = ap->next)
332da2e3ebdSchin 			if (!(flags & (LC_abbreviated|LC_default|LC_verbose)) || !(ap->attribute->flags & LC_default))
333da2e3ebdSchin 			{
334da2e3ebdSchin 				*s++ = c;
335da2e3ebdSchin 				c = ',';
336da2e3ebdSchin 				for (t = ap->attribute->name; s < e && (*s = *t++); s++);
337da2e3ebdSchin 			}
338da2e3ebdSchin 	}
339da2e3ebdSchin 	*s++ = 0;
340da2e3ebdSchin 	return s - buf;
341da2e3ebdSchin }
342da2e3ebdSchin 
343da2e3ebdSchin /*
344da2e3ebdSchin  * generate a canonical locale name in buf
345da2e3ebdSchin  */
346da2e3ebdSchin 
347da2e3ebdSchin size_t
lccanon(Lc_t * lc,unsigned long flags,char * buf,size_t siz)348da2e3ebdSchin lccanon(Lc_t* lc, unsigned long flags, char* buf, size_t siz)
349da2e3ebdSchin {
350da2e3ebdSchin 	if ((flags & LC_local) && (!lc->language || !(lc->language->flags & (LC_debug|LC_default))))
351da2e3ebdSchin 	{
352da2e3ebdSchin #if _WINIX
353da2e3ebdSchin 		char	lang[64];
354da2e3ebdSchin 		char	code[64];
355da2e3ebdSchin 		char	ctry[64];
356da2e3ebdSchin 
357da2e3ebdSchin 		if (lc->index &&
358da2e3ebdSchin 		    GetLocaleInfo(lc->index, LOCALE_SENGLANGUAGE, lang, sizeof(lang)) &&
359da2e3ebdSchin 		    GetLocaleInfo(lc->index, LOCALE_SENGCOUNTRY, ctry, sizeof(ctry)))
360da2e3ebdSchin 		{
361da2e3ebdSchin 		    	if (!GetLocaleInfo(lc->index, LOCALE_IDEFAULTANSICODEPAGE, code, sizeof(code)))
362da2e3ebdSchin 				code[0] = 0;
363da2e3ebdSchin 			if (!lc->charset || !lc->charset->ms)
364da2e3ebdSchin 				return sfsprintf(buf, siz, "%s_%s", lang, ctry);
365da2e3ebdSchin 			else if (streq(lc->charset->ms, code))
366da2e3ebdSchin 				return sfsprintf(buf, siz, "%s_%s.%s", lang, ctry, code);
367da2e3ebdSchin 			else
368da2e3ebdSchin 				return sfsprintf(buf, siz, "%s_%s.%s,%s", lang, ctry, code, lc->charset->ms);
369da2e3ebdSchin 		}
370da2e3ebdSchin #endif
371da2e3ebdSchin 		buf[0] = '-';
372da2e3ebdSchin 		buf[1] = 0;
373da2e3ebdSchin 		return 0;
374da2e3ebdSchin 	}
375da2e3ebdSchin 	return canonical(lc->language, lc->territory, lc->charset, lc->attributes, flags, buf, siz);
376da2e3ebdSchin }
377da2e3ebdSchin 
378da2e3ebdSchin /*
379da2e3ebdSchin  * make an Lc_t from a locale name
380da2e3ebdSchin  */
381da2e3ebdSchin 
382da2e3ebdSchin Lc_t*
lcmake(const char * name)383da2e3ebdSchin lcmake(const char* name)
384da2e3ebdSchin {
385da2e3ebdSchin 	register int			c;
386da2e3ebdSchin 	register char*			s;
387da2e3ebdSchin 	register char*			e;
388da2e3ebdSchin 	register const char*		t;
389da2e3ebdSchin 	const char*			a;
390da2e3ebdSchin 	char*				w;
391da2e3ebdSchin 	char*				language_name;
392da2e3ebdSchin 	char*				territory_name;
393da2e3ebdSchin 	char*				charset_name;
394da2e3ebdSchin 	char*				attributes_name;
395da2e3ebdSchin 	Lc_t*				lc;
396da2e3ebdSchin 	const Lc_map_t*			mp;
397da2e3ebdSchin 	const Lc_language_t*		lp;
398da2e3ebdSchin 	const Lc_territory_t*		tp;
399da2e3ebdSchin 	const Lc_territory_t*		tpb;
400da2e3ebdSchin 	const Lc_territory_t*		primary;
401da2e3ebdSchin 	const Lc_charset_t*		cp;
402da2e3ebdSchin 	const Lc_charset_t*		ppa;
403da2e3ebdSchin 	const Lc_attribute_t*		ap;
404da2e3ebdSchin 	Lc_attribute_list_t*		ai;
405da2e3ebdSchin 	Lc_attribute_list_t*		al;
406da2e3ebdSchin 	int				i;
407da2e3ebdSchin 	int				n;
408da2e3ebdSchin 	int				z;
409da2e3ebdSchin 	char				buf[PATH_MAX / 2];
410da2e3ebdSchin 	char				tmp[PATH_MAX / 2];
411da2e3ebdSchin 
412da2e3ebdSchin 	if (!(t = name) || !*t)
413da2e3ebdSchin 		return &default_lc;
414da2e3ebdSchin 	for (lc = lcs; lc; lc = lc->next)
415da2e3ebdSchin 		if (!strcasecmp(t, lc->code) || !strcasecmp(t, lc->name))
416da2e3ebdSchin 			return lc;
4177c2fbfb3SApril Chin 	for (mp = lc_maps; mp->code; mp++)
418da2e3ebdSchin 		if (streq(t, mp->code))
419da2e3ebdSchin 		{
420da2e3ebdSchin 			lp = mp->language;
421da2e3ebdSchin 			tp = mp->territory;
422da2e3ebdSchin 			cp = mp->charset;
423da2e3ebdSchin 			if (!mp->attribute)
424da2e3ebdSchin 				al = 0;
425da2e3ebdSchin 			else if (al = newof(0, Lc_attribute_list_t, 1, 0))
426da2e3ebdSchin 				al->attribute = mp->attribute;
427da2e3ebdSchin 			goto mapped;
428da2e3ebdSchin 		}
429da2e3ebdSchin 	language_name = buf;
430da2e3ebdSchin 	territory_name = charset_name = attributes_name = 0;
431da2e3ebdSchin 	s = buf;
432da2e3ebdSchin 	e = &buf[sizeof(buf)-2];
433da2e3ebdSchin 	a = 0;
434da2e3ebdSchin 	n = 0;
435da2e3ebdSchin 	while (s < e && (c = *t++))
436da2e3ebdSchin 	{
437da2e3ebdSchin 		if (isspace(c) || (c == '(' || c == '-' && *t == '-') && ++n)
438da2e3ebdSchin 		{
439da2e3ebdSchin 			while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
440da2e3ebdSchin 			if (!c)
441da2e3ebdSchin 				break;
442da2e3ebdSchin 			if (isalnum(c) && !n)
443da2e3ebdSchin 				*s++ = '-';
444da2e3ebdSchin 			else
445da2e3ebdSchin 			{
446da2e3ebdSchin 				n = 0;
447da2e3ebdSchin 				if (!a)
448da2e3ebdSchin 				{
449da2e3ebdSchin 					a = t - 1;
450da2e3ebdSchin 					while (c && c != '_' && c != '.' && c != '@')
451da2e3ebdSchin 						c = *t++;
452da2e3ebdSchin 					if (!c)
453da2e3ebdSchin 						break;
454da2e3ebdSchin 				}
455da2e3ebdSchin 			}
456da2e3ebdSchin 		}
457da2e3ebdSchin 		if (c == '_' && !territory_name)
458da2e3ebdSchin 		{
459da2e3ebdSchin 			*s++ = 0;
460da2e3ebdSchin 			territory_name = s;
461da2e3ebdSchin 		}
462da2e3ebdSchin 		else if (c == '.' && !charset_name)
463da2e3ebdSchin 		{
464da2e3ebdSchin 			*s++ = 0;
465da2e3ebdSchin 			charset_name = s;
466da2e3ebdSchin 		}
467da2e3ebdSchin 		else if (c == '@' && !attributes_name)
468da2e3ebdSchin 		{
469da2e3ebdSchin 			*s++ = 0;
470da2e3ebdSchin 			attributes_name = s;
471da2e3ebdSchin 		}
472da2e3ebdSchin 		else
473da2e3ebdSchin 		{
474da2e3ebdSchin 			if (isupper(c))
475da2e3ebdSchin 				c = tolower(c);
476da2e3ebdSchin 			*s++ = c;
477da2e3ebdSchin 		}
478da2e3ebdSchin 	}
479da2e3ebdSchin 	if ((t = a) && s < e)
480da2e3ebdSchin 	{
481da2e3ebdSchin 		if (attributes_name)
482da2e3ebdSchin 			*s++ = ',';
483da2e3ebdSchin 		else
484da2e3ebdSchin 		{
485da2e3ebdSchin 			*s++ = 0;
486da2e3ebdSchin 			attributes_name = s;
487da2e3ebdSchin 		}
488da2e3ebdSchin 		while (s < e && (c = *t++))
489da2e3ebdSchin 		{
490da2e3ebdSchin 			if (isspace(c) || (c == '(' || c == ')' || c == '-' && *t == '-') && ++n)
491da2e3ebdSchin 			{
492da2e3ebdSchin 				while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
493da2e3ebdSchin 				if (!c)
494da2e3ebdSchin 					break;
495da2e3ebdSchin 				if (isalnum(c) && !n)
496da2e3ebdSchin 					*s++ = '-';
497da2e3ebdSchin 				else
498da2e3ebdSchin 					n = 0;
499da2e3ebdSchin 			}
500da2e3ebdSchin 			if (c == '_' || c == '.' || c == '@')
501da2e3ebdSchin 				break;
502da2e3ebdSchin 			if (isupper(c))
503da2e3ebdSchin 				c = tolower(c);
504da2e3ebdSchin 			*s++ = c;
505da2e3ebdSchin 		}
506da2e3ebdSchin 	}
507da2e3ebdSchin 	*s = 0;
508da2e3ebdSchin 	tp = 0;
509da2e3ebdSchin 	cp = ppa = 0;
510da2e3ebdSchin 	al = 0;
511da2e3ebdSchin 
512da2e3ebdSchin 	/*
513da2e3ebdSchin 	 * language
514da2e3ebdSchin 	 */
515da2e3ebdSchin 
516da2e3ebdSchin 	n = strlen(s = language_name);
517da2e3ebdSchin 	if (n == 2)
5187c2fbfb3SApril Chin 		for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
519da2e3ebdSchin 	else if (n == 3)
520da2e3ebdSchin 	{
5217c2fbfb3SApril Chin 		for (lp = lc_languages; lp->code && (!lp->alternates || !match(s, lp->alternates, n, 0)); lp++);
522da2e3ebdSchin 		if (!lp->code)
523da2e3ebdSchin 		{
524da2e3ebdSchin 			c = s[2];
525da2e3ebdSchin 			s[2] = 0;
5267c2fbfb3SApril Chin 			for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
527da2e3ebdSchin 			s[2] = c;
528da2e3ebdSchin 			if (lp->code)
529da2e3ebdSchin 				n = 1;
530da2e3ebdSchin 		}
531da2e3ebdSchin 	}
532da2e3ebdSchin 	else
533da2e3ebdSchin 		lp = 0;
534da2e3ebdSchin 	if (!lp || !lp->code)
535da2e3ebdSchin 	{
5367c2fbfb3SApril Chin 		for (lp = lc_languages; lp->code && !match(s, lp->name, 0, 0); lp++);
537da2e3ebdSchin 		if (!lp || !lp->code)
538da2e3ebdSchin 		{
539da2e3ebdSchin 			if (!territory_name)
540da2e3ebdSchin 			{
541da2e3ebdSchin 				if (n == 2)
5427c2fbfb3SApril Chin 					for (tp = lc_territories; tp->code && !streq(s, tp->code); tp++);
543da2e3ebdSchin 				else
544da2e3ebdSchin 				{
545da2e3ebdSchin 					z = 0;
546da2e3ebdSchin 					tpb = 0;
5477c2fbfb3SApril Chin 					for (tp = lc_territories; tp->name; tp++)
548da2e3ebdSchin 						if ((i = match(s, tp->name, 3, 0)) > z)
549da2e3ebdSchin 						{
550da2e3ebdSchin 							tpb = tp;
551da2e3ebdSchin 							if ((z = i) == n)
552da2e3ebdSchin 								break;
553da2e3ebdSchin 						}
554da2e3ebdSchin 					if (tpb)
555da2e3ebdSchin 						tp = tpb;
556da2e3ebdSchin 				}
557da2e3ebdSchin 				if (tp->code)
558da2e3ebdSchin 					lp = tp->languages[0];
559da2e3ebdSchin 			}
560da2e3ebdSchin 			if (!lp || !lp->code)
561da2e3ebdSchin 			{
562da2e3ebdSchin 				/*
563da2e3ebdSchin 				 * name not in the tables so let
564da2e3ebdSchin 				 * _ast_setlocale() and/or setlocale()
565da2e3ebdSchin 				 * handle the validity checks
566da2e3ebdSchin 				 */
567da2e3ebdSchin 
568da2e3ebdSchin 				s = (char*)name;
569da2e3ebdSchin 				z = strlen(s) + 1;
570da2e3ebdSchin 				if (!(lp = newof(0, Lc_language_t, 1, z)))
571da2e3ebdSchin 					return 0;
572da2e3ebdSchin 				name = ((Lc_language_t*)lp)->code = ((Lc_language_t*)lp)->name = (const char*)(lp + 1);
573da2e3ebdSchin 				memcpy((char*)lp->code, s, z - 1);
5747c2fbfb3SApril Chin 				tp = &lc_territories[0];
5757c2fbfb3SApril Chin 				cp = ((Lc_language_t*)lp)->charset = &lc_charsets[0];
576da2e3ebdSchin 				al = 0;
577da2e3ebdSchin 				goto override;
578da2e3ebdSchin 			}
579da2e3ebdSchin 		}
580da2e3ebdSchin 	}
581da2e3ebdSchin 
582da2e3ebdSchin 	/*
583da2e3ebdSchin 	 * territory
584da2e3ebdSchin 	 */
585da2e3ebdSchin 
586da2e3ebdSchin 	if (!tp || !tp->code)
587da2e3ebdSchin 	{
588da2e3ebdSchin 		if (!(s = territory_name))
589da2e3ebdSchin 		{
590da2e3ebdSchin 			n = 0;
591da2e3ebdSchin 			primary = 0;
5927c2fbfb3SApril Chin 			for (tp = lc_territories; tp->code; tp++)
593da2e3ebdSchin 				if (tp->languages[0] == lp)
594da2e3ebdSchin 				{
595da2e3ebdSchin 					if (tp->flags & LC_primary)
596da2e3ebdSchin 					{
597da2e3ebdSchin 						n = 1;
598da2e3ebdSchin 						primary = tp;
599da2e3ebdSchin 						break;
600da2e3ebdSchin 					}
601da2e3ebdSchin 					n++;
602da2e3ebdSchin 					primary = tp;
603da2e3ebdSchin 				}
604da2e3ebdSchin 			if (n == 1)
605da2e3ebdSchin 				tp = primary;
606da2e3ebdSchin 			s = (char*)lp->code;
607da2e3ebdSchin 		}
608da2e3ebdSchin 		if (!tp || !tp->code)
609da2e3ebdSchin 		{
610da2e3ebdSchin 			n = strlen(s);
611da2e3ebdSchin 			if (n == 2)
612da2e3ebdSchin 			{
6137c2fbfb3SApril Chin 				for (tp = lc_territories; tp->code; tp++)
614da2e3ebdSchin 					if (streq(s, tp->code))
615da2e3ebdSchin 					{
616da2e3ebdSchin 						for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
617da2e3ebdSchin 						if (i >= elementsof(tp->languages))
618da2e3ebdSchin 							tp = 0;
619da2e3ebdSchin 						break;
620da2e3ebdSchin 					}
621da2e3ebdSchin 			}
622da2e3ebdSchin 			else
623da2e3ebdSchin 			{
6247c2fbfb3SApril Chin 				for (tp = lc_territories; tp->code; tp++)
625da2e3ebdSchin 					if (match(s, tp->name, 3, 0))
626da2e3ebdSchin 					{
627da2e3ebdSchin 						for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
628da2e3ebdSchin 						if (i < elementsof(tp->languages))
629da2e3ebdSchin 							break;
630da2e3ebdSchin 					}
631da2e3ebdSchin 			}
632da2e3ebdSchin 			if (tp && !tp->code)
633da2e3ebdSchin 				tp = 0;
634da2e3ebdSchin 		}
635da2e3ebdSchin 	}
636da2e3ebdSchin 
637da2e3ebdSchin 	/*
638da2e3ebdSchin 	 * attributes -- done here to catch misplaced charset references
639da2e3ebdSchin 	 */
640da2e3ebdSchin 
641da2e3ebdSchin 	if (s = attributes_name)
642da2e3ebdSchin 	{
643da2e3ebdSchin 		do
644da2e3ebdSchin 		{
645da2e3ebdSchin 			for (w = s; *s && *s != ','; s++);
646da2e3ebdSchin 			c = *s;
647da2e3ebdSchin 			*s = 0;
648da2e3ebdSchin 			if (!(cp = lp->charset) || !match_charset(w, cp))
6497c2fbfb3SApril Chin 				for (cp = lc_charsets; cp->code; cp++)
650da2e3ebdSchin 					if (match_charset(w, cp))
651da2e3ebdSchin 					{
652da2e3ebdSchin 						ppa = cp;
653da2e3ebdSchin 						break;
654da2e3ebdSchin 					}
655da2e3ebdSchin 			if (!cp->code)
656da2e3ebdSchin 			{
657da2e3ebdSchin 				for (i = 0; i < elementsof(lp->attributes) && (ap = lp->attributes[i]); i++)
658da2e3ebdSchin 					if (match(w, ap->name, 5, 0))
659da2e3ebdSchin 					{
660da2e3ebdSchin 						if (ai = newof(0, Lc_attribute_list_t, 1, 0))
661da2e3ebdSchin 						{
662da2e3ebdSchin 							ai->attribute = ap;
663da2e3ebdSchin 							ai->next = al;
664da2e3ebdSchin 							al = ai;
665da2e3ebdSchin 						}
666da2e3ebdSchin 						break;
667da2e3ebdSchin 					}
668da2e3ebdSchin 				if (i >= elementsof(lp->attributes) && (ap = newof(0, Lc_attribute_t, 1, sizeof(Lc_attribute_list_t) + s - w + 1)))
669da2e3ebdSchin 				{
670da2e3ebdSchin 					ai = (Lc_attribute_list_t*)(ap + 1);
671da2e3ebdSchin 					strcpy((char*)(((Lc_attribute_t*)ap)->name = (const char*)(ai + 1)), w);
672da2e3ebdSchin 					ai->attribute = ap;
673da2e3ebdSchin 					ai->next = al;
674da2e3ebdSchin 					al = ai;
675da2e3ebdSchin 				}
676da2e3ebdSchin 			}
677da2e3ebdSchin 			*s = c;
678da2e3ebdSchin 		} while (*s++);
679da2e3ebdSchin 	}
680da2e3ebdSchin 
681da2e3ebdSchin 	/*
682da2e3ebdSchin 	 * charset
683da2e3ebdSchin 	 */
684da2e3ebdSchin 
685da2e3ebdSchin 	if (s = charset_name)
6867c2fbfb3SApril Chin 		for (cp = lc_charsets; cp->code; cp++)
687da2e3ebdSchin 			if (match_charset(s, cp))
688da2e3ebdSchin 				break;
689da2e3ebdSchin 	if (!cp || !cp->code)
690da2e3ebdSchin 		cp = ppa ? ppa : lp->charset;
691da2e3ebdSchin  mapped:
692da2e3ebdSchin 	z = canonical(lp, tp, cp, al, 0, s = tmp, sizeof(tmp));
693da2e3ebdSchin 
694da2e3ebdSchin 	/*
695da2e3ebdSchin 	 * add to the list of possibly active locales
696da2e3ebdSchin 	 */
697da2e3ebdSchin 
698da2e3ebdSchin  override:
699da2e3ebdSchin 	n = strlen(name) + 1;
700da2e3ebdSchin 	if (!(lc = newof(0, Lc_t, 1, n + z)))
701da2e3ebdSchin 		return 0;
702da2e3ebdSchin 	strcpy((char*)(lc->name = (const char*)(lc + 1)), name);
703da2e3ebdSchin 	strcpy((char*)(lc->code = lc->name + n), s);
7047c2fbfb3SApril Chin 	lc->language = lp ? lp : &lc_languages[0];
7057c2fbfb3SApril Chin 	lc->territory = tp ? tp : &lc_territories[0];
7067c2fbfb3SApril Chin 	lc->charset = cp ? cp : &lc_charsets[0];
70734f9b3eeSRoland Mainz 	if (!strcmp(lc->charset->code, "utf8"))
70834f9b3eeSRoland Mainz 		lc->flags |= LC_utf8;
709da2e3ebdSchin 	lc->attributes = al;
710da2e3ebdSchin 	for (i = 0; i < elementsof(lc->info); i++)
711da2e3ebdSchin 		lc->info[i].lc = lc;
712da2e3ebdSchin #if _WINIX
713da2e3ebdSchin 	n = SUBLANG_DEFAULT;
714da2e3ebdSchin 	if (tp)
715da2e3ebdSchin 		for (i = 0; i < elementsof(tp->languages); i++)
716da2e3ebdSchin 			if (lp == tp->languages[i])
717da2e3ebdSchin 			{
718da2e3ebdSchin 				n = tp->indices[i];
719da2e3ebdSchin 				break;
720da2e3ebdSchin 			}
721da2e3ebdSchin 	lc->index = MAKELCID(MAKELANGID(lp->index, n), SORT_DEFAULT);
722da2e3ebdSchin #endif
723da2e3ebdSchin 	lc->next = lcs;
724da2e3ebdSchin 	lcs = lc;
725da2e3ebdSchin 	return lc;
726da2e3ebdSchin }
727da2e3ebdSchin 
728da2e3ebdSchin /*
729da2e3ebdSchin  * return an Lc_t* for each locale in the tables
730da2e3ebdSchin  * one Lc_t is allocated on the first call with lc==0
731da2e3ebdSchin  * this is freed when 0 returned
732da2e3ebdSchin  * the return value is not part of the lcmake() cache
733da2e3ebdSchin  */
734da2e3ebdSchin 
735da2e3ebdSchin typedef struct Lc_scan_s
736da2e3ebdSchin {
737da2e3ebdSchin 	Lc_t			lc;
738da2e3ebdSchin 	Lc_attribute_list_t	list;
739da2e3ebdSchin 	int			territory;
740da2e3ebdSchin 	int			language;
741da2e3ebdSchin 	int			attribute;
742da2e3ebdSchin 	char			buf[256];
743da2e3ebdSchin } Lc_scan_t;
744da2e3ebdSchin 
745da2e3ebdSchin Lc_t*
lcscan(Lc_t * lc)746da2e3ebdSchin lcscan(Lc_t* lc)
747da2e3ebdSchin {
748da2e3ebdSchin 	register Lc_scan_t*	ls;
749da2e3ebdSchin 
750da2e3ebdSchin 	if (!(ls = (Lc_scan_t*)lc))
751da2e3ebdSchin 	{
752da2e3ebdSchin 		if (!(ls = newof(0, Lc_scan_t, 1, 0)))
753da2e3ebdSchin 			return 0;
754da2e3ebdSchin 		ls->lc.code = ls->lc.name = ls->buf;
755da2e3ebdSchin 		ls->territory = -1;
756da2e3ebdSchin 		ls->language = elementsof(ls->lc.territory->languages);
757da2e3ebdSchin 		ls->attribute = elementsof(ls->lc.language->attributes);
758da2e3ebdSchin 	}
759da2e3ebdSchin 	if (++ls->attribute >= elementsof(ls->lc.language->attributes) || !(ls->list.attribute = ls->lc.language->attributes[ls->attribute]))
760da2e3ebdSchin 	{
761da2e3ebdSchin 		if (++ls->language >= elementsof(ls->lc.territory->languages) || !(ls->lc.language = ls->lc.territory->languages[ls->language]))
762da2e3ebdSchin 		{
7637c2fbfb3SApril Chin 			if (!lc_territories[++ls->territory].code)
764da2e3ebdSchin 			{
765da2e3ebdSchin 				free(ls);
766da2e3ebdSchin 				return 0;
767da2e3ebdSchin 			}
7687c2fbfb3SApril Chin 			ls->lc.territory = &lc_territories[ls->territory];
769da2e3ebdSchin 			ls->lc.language = ls->lc.territory->languages[ls->language = 0];
770da2e3ebdSchin 		}
771da2e3ebdSchin 		if (ls->lc.language)
772da2e3ebdSchin 		{
7737c2fbfb3SApril Chin 			ls->lc.charset = ls->lc.language->charset ? ls->lc.language->charset : &lc_charsets[0];
774da2e3ebdSchin 			ls->list.attribute = ls->lc.language->attributes[ls->attribute = 0];
775da2e3ebdSchin 		}
776da2e3ebdSchin 		else
777da2e3ebdSchin 		{
7787c2fbfb3SApril Chin 			ls->lc.charset = &lc_charsets[0];
779da2e3ebdSchin 			ls->list.attribute = 0;
780da2e3ebdSchin 		}
781da2e3ebdSchin 	}
782da2e3ebdSchin 	ls->lc.attributes = ls->list.attribute ? &ls->list : (Lc_attribute_list_t*)0;
783da2e3ebdSchin #if _WINIX
784da2e3ebdSchin 	if (!ls->lc.language || !ls->lc.language->index)
785da2e3ebdSchin 		ls->lc.index = 0;
786da2e3ebdSchin 	else
787da2e3ebdSchin 	{
788da2e3ebdSchin 		if ((!ls->list.attribute || !(ls->lc.index = ls->list.attribute->index)) &&
789da2e3ebdSchin 		    (!ls->lc.territory || !(ls->lc.index = ls->lc.territory->indices[ls->language])))
790da2e3ebdSchin 			ls->lc.index = SUBLANG_DEFAULT;
791da2e3ebdSchin 		ls->lc.index = MAKELCID(MAKELANGID(ls->lc.language->index, ls->lc.index), SORT_DEFAULT);
792da2e3ebdSchin 	}
793da2e3ebdSchin #endif
794da2e3ebdSchin 	canonical(ls->lc.language, ls->lc.territory, ls->lc.charset, ls->lc.attributes, 0, ls->buf, sizeof(ls->buf));
795da2e3ebdSchin 	return (Lc_t*)ls;
796da2e3ebdSchin }
797