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