xref: /onnv-gate/usr/src/lib/libast/common/port/lc.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin 
244887Schin /*
254887Schin  * locale state implementation
264887Schin  */
274887Schin 
284887Schin #include "lclib.h"
298462SApril.Chin@Sun.COM #include "lclang.h"
304887Schin 
314887Schin #include <ctype.h>
324887Schin 
334887Schin static Lc_numeric_t	default_numeric = { '.', -1 };
344887Schin 
354887Schin static Lc_t		default_lc =
364887Schin {
374887Schin 	"C",
384887Schin 	"POSIX",
398462SApril.Chin@Sun.COM 	&lc_languages[0],
408462SApril.Chin@Sun.COM 	&lc_territories[0],
418462SApril.Chin@Sun.COM 	&lc_charsets[0],
424887Schin 	0,
434887Schin 	LC_default|LC_checked|LC_local,
444887Schin 	0,
454887Schin 	{
464887Schin 		{ &default_lc, 0, 0 },
474887Schin 		{ &default_lc, 0, 0 },
484887Schin 		{ &default_lc, 0, 0 },
494887Schin 		{ &default_lc, 0, 0 },
504887Schin 		{ &default_lc, 0, 0 },
514887Schin 		{ &default_lc, 0, (void*)&default_numeric },
524887Schin 		{ &default_lc, 0, 0 },
534887Schin 		{ &default_lc, 0, 0 },
544887Schin 		{ &default_lc, 0, 0 },
554887Schin 		{ &default_lc, 0, 0 },
564887Schin 		{ &default_lc, 0, 0 },
574887Schin 		{ &default_lc, 0, 0 },
584887Schin 		{ &default_lc, 0, 0 },
594887Schin 		{ &default_lc, 0, 0 }
604887Schin 	}
614887Schin };
624887Schin 
634887Schin static Lc_numeric_t	debug_numeric = { ',', '.' };
644887Schin 
654887Schin static Lc_t		debug_lc =
664887Schin {
674887Schin 	"debug",
684887Schin 	"debug",
698462SApril.Chin@Sun.COM 	&lc_languages[1],
708462SApril.Chin@Sun.COM 	&lc_territories[1],
718462SApril.Chin@Sun.COM 	&lc_charsets[0],
724887Schin 	0,
734887Schin 	LC_debug|LC_checked|LC_local,
744887Schin 	0,
754887Schin 	{
764887Schin 		{ &debug_lc, 0, 0 },
774887Schin 		{ &debug_lc, 0, 0 },
784887Schin 		{ &debug_lc, 0, 0 },
794887Schin 		{ &debug_lc, 0, 0 },
804887Schin 		{ &debug_lc, 0, 0 },
814887Schin 		{ &debug_lc, 0, (void*)&debug_numeric },
824887Schin 		{ &debug_lc, 0, 0 },
834887Schin 		{ &debug_lc, 0, 0 },
844887Schin 		{ &debug_lc, 0, 0 },
854887Schin 		{ &debug_lc, 0, 0 },
864887Schin 		{ &debug_lc, 0, 0 },
874887Schin 		{ &debug_lc, 0, 0 },
884887Schin 		{ &debug_lc, 0, 0 },
894887Schin 		{ &debug_lc, 0, 0 }
904887Schin 	},
914887Schin 	&default_lc
924887Schin };
934887Schin 
944887Schin static Lc_t*		lcs = &debug_lc;
954887Schin 
964887Schin Lc_t*			locales[] =
974887Schin {
984887Schin 	&default_lc,
994887Schin 	&default_lc,
1004887Schin 	&default_lc,
1014887Schin 	&default_lc,
1024887Schin 	&default_lc,
1034887Schin 	&default_lc,
1044887Schin 	&default_lc,
1054887Schin 	&default_lc,
1064887Schin 	&default_lc,
1074887Schin 	&default_lc,
1084887Schin 	&default_lc,
1094887Schin 	&default_lc,
1104887Schin 	&default_lc,
1114887Schin 	&default_lc
1124887Schin };
1134887Schin 
1144887Schin /*
1154887Schin  * return the internal category index for category
1164887Schin  */
1174887Schin 
1184887Schin int
lcindex(int category,int min)1194887Schin lcindex(int category, int min)
1204887Schin {
1214887Schin 	switch (category)
1224887Schin 	{
1234887Schin 	case LC_ALL:		return min ? -1 : AST_LC_ALL;
1244887Schin 	case LC_ADDRESS:	return AST_LC_ADDRESS;
1254887Schin 	case LC_COLLATE:	return AST_LC_COLLATE;
1264887Schin 	case LC_CTYPE:		return AST_LC_CTYPE;
1274887Schin 	case LC_IDENTIFICATION:	return AST_LC_IDENTIFICATION;
12810898Sroland.mainz@nrubsig.org 	case LC_LANG:		return AST_LC_LANG;
1294887Schin 	case LC_MEASUREMENT:	return AST_LC_MEASUREMENT;
1304887Schin 	case LC_MESSAGES:	return AST_LC_MESSAGES;
1314887Schin 	case LC_MONETARY:	return AST_LC_MONETARY;
1324887Schin 	case LC_NAME:		return AST_LC_NAME;
1334887Schin 	case LC_NUMERIC:	return AST_LC_NUMERIC;
1344887Schin 	case LC_PAPER:		return AST_LC_PAPER;
1354887Schin 	case LC_TELEPHONE:	return AST_LC_TELEPHONE;
1364887Schin 	case LC_TIME:		return AST_LC_TIME;
1374887Schin 	case LC_XLITERATE:	return AST_LC_XLITERATE;
1384887Schin 	}
1394887Schin 	return -1;
1404887Schin }
1414887Schin 
1424887Schin /*
1434887Schin  * return the first category table entry
1444887Schin  */
1454887Schin 
1464887Schin Lc_category_t*
lccategories(void)1474887Schin lccategories(void)
1484887Schin {
1498462SApril.Chin@Sun.COM 	return (Lc_category_t*)&lc_categories[0];
1504887Schin }
1514887Schin 
1524887Schin /*
1534887Schin  * return the current info for category
1544887Schin  */
1554887Schin 
1564887Schin Lc_info_t*
lcinfo(register int category)1574887Schin lcinfo(register int category)
1584887Schin {
1594887Schin 	if ((category = lcindex(category, 0)) < 0)
1604887Schin 		return 0;
1614887Schin 	return LCINFO(category);
1624887Schin }
1634887Schin 
1644887Schin /*
1654887Schin  * return 1 if s matches the alternation pattern p
1664887Schin  * if minimum!=0 then at least that many chars must match
1674887Schin  * if standard!=0 and s[0] is a digit leading non-digits are ignored in p
1684887Schin  */
1694887Schin 
1704887Schin static int
match(const char * s,register const char * p,int minimum,int standard)1714887Schin match(const char* s, register const char* p, int minimum, int standard)
1724887Schin {
1734887Schin 	register const char*	t;
1744887Schin 	const char*		x;
1754887Schin 	int			w;
1764887Schin 	int			z;
1774887Schin 
1784887Schin 	z = 0;
1794887Schin 	do
1804887Schin 	{
1814887Schin 		t = s;
1824887Schin 		if (standard)
1834887Schin 		{
1844887Schin 			if (isdigit(*t))
1854887Schin 				while (*p && !isdigit(*p))
1864887Schin 					p++;
1874887Schin 			else if (isdigit(*p))
1884887Schin 				while (*t && !isdigit(*t))
1894887Schin 					t++;
1904887Schin 		}
1914887Schin 		if (*p)
1924887Schin 		{
1934887Schin 			w = 0;
1944887Schin 			x = p;
1954887Schin 			while (*p && *p != '|')
1964887Schin 			{
1974887Schin 				if (!*t || *t == ',')
1984887Schin 					break;
1994887Schin 				else if (*t == *p)
2004887Schin 					/*ok*/;
2014887Schin 				else if (*t == '-')
2024887Schin 				{
2034887Schin 					if (standard && isdigit(*p))
2044887Schin 					{
2054887Schin 						t++;
2064887Schin 						continue;
2074887Schin 					}
2084887Schin 					while (*p && *p != '-')
2094887Schin 						p++;
2104887Schin 					if (!*p)
2114887Schin 						break;
2124887Schin 				}
2134887Schin 				else if (*p == '-')
2144887Schin 				{
2154887Schin 					if (standard && isdigit(*t))
2164887Schin 					{
2174887Schin 						p++;
2184887Schin 						continue;
2194887Schin 					}
2204887Schin 					w = 1;
2214887Schin 					while (*t && *t != '-')
2224887Schin 						t++;
2234887Schin 					if (!*t)
2244887Schin 						break;
2254887Schin 				}
2264887Schin 				else
2274887Schin 					break;
2284887Schin 				t++;
2294887Schin 				p++;
2304887Schin 			}
2314887Schin 			if ((!*t || *t == ',') && (!*p || *p == '|' || w))
2324887Schin 				return p - x;
2334887Schin 			if (minimum && z < (p - x) && (p - x) >= minimum)
2344887Schin 				z = p - x;
2354887Schin 		}
2364887Schin 		while (*p && *p != '|')
2374887Schin 			p++;
2384887Schin 	} while (*p++);
2394887Schin 	return z;
2404887Schin }
2414887Schin 
2424887Schin /*
2434887Schin  * return 1 if s matches the charset names in cp
2444887Schin  */
2454887Schin 
2464887Schin static int
match_charset(register const char * s,register const Lc_charset_t * cp)2474887Schin match_charset(register const char* s, register const Lc_charset_t* cp)
2484887Schin {
2494887Schin 	return match(s, cp->code, 0, 1) || match(s, cp->alternates, 3, 1) || cp->ms && match(s, cp->ms, 0, 1);
2504887Schin }
2514887Schin 
2524887Schin /*
2534887Schin  * low level for lccanon
2544887Schin  */
2554887Schin 
2564887Schin 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)2574887Schin 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)
2584887Schin {
2594887Schin 	register int		c;
2604887Schin 	register int		u;
2614887Schin 	register char*		s;
2624887Schin 	register char*		e;
2634887Schin 	register const char*	t;
2644887Schin 
2654887Schin 	if (!(flags & (LC_abbreviated|LC_default|LC_local|LC_qualified|LC_verbose)))
2664887Schin 		flags |= LC_abbreviated;
2674887Schin 	s = buf;
2684887Schin 	e = &buf[siz - 3];
2694887Schin 	if (lp)
2704887Schin 	{
2714887Schin 		if (lp->flags & (LC_debug|LC_default))
2724887Schin 		{
2734887Schin 			for (t = lp->code; s < e && (*s = *t++); s++);
2744887Schin 			*s++ = 0;
2754887Schin 			return s - buf;
2764887Schin 		}
2774887Schin 		if (flags & LC_verbose)
2784887Schin 		{
2794887Schin 			u = 1;
2804887Schin 			t = lp->name;
2814887Schin 			while (s < e && (c = *t++))
2824887Schin 			{
2834887Schin 				if (u)
2844887Schin 				{
2854887Schin 					u = 0;
2864887Schin 					c = toupper(c);
2874887Schin 				}
2884887Schin 				else if (!isalnum(c))
2894887Schin 					u = 1;
2904887Schin 				*s++ = c;
2914887Schin 			}
2924887Schin 		}
2934887Schin 		else
2944887Schin 			for (t = lp->code; s < e && (*s = *t++); s++);
2954887Schin 	}
2964887Schin 	if (s < e)
2974887Schin 	{
2988462SApril.Chin@Sun.COM 		if (tp && tp != &lc_territories[0] && (!(flags & (LC_abbreviated|LC_default)) || !lp || !streq(lp->code, tp->code)))
2994887Schin 		{
3004887Schin 			if (lp)
3014887Schin 				*s++ = '_';
3024887Schin 			if (flags & LC_verbose)
3034887Schin 			{
3044887Schin 				u = 1;
3054887Schin 				t = tp->name;
3064887Schin 				while (s < e && (c = *t++) && c != '|')
3074887Schin 				{
3084887Schin 					if (u)
3094887Schin 					{
3104887Schin 						u = 0;
3114887Schin 						c = toupper(c);
3124887Schin 					}
3134887Schin 					else if (!isalnum(c))
3144887Schin 						u = 1;
3154887Schin 					*s++ = c;
3164887Schin 				}
3174887Schin 			}
3184887Schin 			else
3194887Schin 				for (t = tp->code; s < e && (*s = toupper(*t++)); s++);
3204887Schin 		}
3214887Schin 		if (lp && (!(flags & (LC_abbreviated|LC_default)) || cp != lp->charset) && s < e)
3224887Schin 		{
3234887Schin 			*s++ = '.';
3244887Schin 			for (t = cp->code; s < e && (c = *t++); s++)
3254887Schin 			{
3264887Schin 				if (islower(c))
3274887Schin 					c = toupper(c);
3284887Schin 				*s = c;
3294887Schin 			}
3304887Schin 		}
3314887Schin 		for (c = '@'; ap && s < e; ap = ap->next)
3324887Schin 			if (!(flags & (LC_abbreviated|LC_default|LC_verbose)) || !(ap->attribute->flags & LC_default))
3334887Schin 			{
3344887Schin 				*s++ = c;
3354887Schin 				c = ',';
3364887Schin 				for (t = ap->attribute->name; s < e && (*s = *t++); s++);
3374887Schin 			}
3384887Schin 	}
3394887Schin 	*s++ = 0;
3404887Schin 	return s - buf;
3414887Schin }
3424887Schin 
3434887Schin /*
3444887Schin  * generate a canonical locale name in buf
3454887Schin  */
3464887Schin 
3474887Schin size_t
lccanon(Lc_t * lc,unsigned long flags,char * buf,size_t siz)3484887Schin lccanon(Lc_t* lc, unsigned long flags, char* buf, size_t siz)
3494887Schin {
3504887Schin 	if ((flags & LC_local) && (!lc->language || !(lc->language->flags & (LC_debug|LC_default))))
3514887Schin 	{
3524887Schin #if _WINIX
3534887Schin 		char	lang[64];
3544887Schin 		char	code[64];
3554887Schin 		char	ctry[64];
3564887Schin 
3574887Schin 		if (lc->index &&
3584887Schin 		    GetLocaleInfo(lc->index, LOCALE_SENGLANGUAGE, lang, sizeof(lang)) &&
3594887Schin 		    GetLocaleInfo(lc->index, LOCALE_SENGCOUNTRY, ctry, sizeof(ctry)))
3604887Schin 		{
3614887Schin 		    	if (!GetLocaleInfo(lc->index, LOCALE_IDEFAULTANSICODEPAGE, code, sizeof(code)))
3624887Schin 				code[0] = 0;
3634887Schin 			if (!lc->charset || !lc->charset->ms)
3644887Schin 				return sfsprintf(buf, siz, "%s_%s", lang, ctry);
3654887Schin 			else if (streq(lc->charset->ms, code))
3664887Schin 				return sfsprintf(buf, siz, "%s_%s.%s", lang, ctry, code);
3674887Schin 			else
3684887Schin 				return sfsprintf(buf, siz, "%s_%s.%s,%s", lang, ctry, code, lc->charset->ms);
3694887Schin 		}
3704887Schin #endif
3714887Schin 		buf[0] = '-';
3724887Schin 		buf[1] = 0;
3734887Schin 		return 0;
3744887Schin 	}
3754887Schin 	return canonical(lc->language, lc->territory, lc->charset, lc->attributes, flags, buf, siz);
3764887Schin }
3774887Schin 
3784887Schin /*
3794887Schin  * make an Lc_t from a locale name
3804887Schin  */
3814887Schin 
3824887Schin Lc_t*
lcmake(const char * name)3834887Schin lcmake(const char* name)
3844887Schin {
3854887Schin 	register int			c;
3864887Schin 	register char*			s;
3874887Schin 	register char*			e;
3884887Schin 	register const char*		t;
3894887Schin 	const char*			a;
3904887Schin 	char*				w;
3914887Schin 	char*				language_name;
3924887Schin 	char*				territory_name;
3934887Schin 	char*				charset_name;
3944887Schin 	char*				attributes_name;
3954887Schin 	Lc_t*				lc;
3964887Schin 	const Lc_map_t*			mp;
3974887Schin 	const Lc_language_t*		lp;
3984887Schin 	const Lc_territory_t*		tp;
3994887Schin 	const Lc_territory_t*		tpb;
4004887Schin 	const Lc_territory_t*		primary;
4014887Schin 	const Lc_charset_t*		cp;
4024887Schin 	const Lc_charset_t*		ppa;
4034887Schin 	const Lc_attribute_t*		ap;
4044887Schin 	Lc_attribute_list_t*		ai;
4054887Schin 	Lc_attribute_list_t*		al;
4064887Schin 	int				i;
4074887Schin 	int				n;
4084887Schin 	int				z;
4094887Schin 	char				buf[PATH_MAX / 2];
4104887Schin 	char				tmp[PATH_MAX / 2];
4114887Schin 
4124887Schin 	if (!(t = name) || !*t)
4134887Schin 		return &default_lc;
4144887Schin 	for (lc = lcs; lc; lc = lc->next)
4154887Schin 		if (!strcasecmp(t, lc->code) || !strcasecmp(t, lc->name))
4164887Schin 			return lc;
4178462SApril.Chin@Sun.COM 	for (mp = lc_maps; mp->code; mp++)
4184887Schin 		if (streq(t, mp->code))
4194887Schin 		{
4204887Schin 			lp = mp->language;
4214887Schin 			tp = mp->territory;
4224887Schin 			cp = mp->charset;
4234887Schin 			if (!mp->attribute)
4244887Schin 				al = 0;
4254887Schin 			else if (al = newof(0, Lc_attribute_list_t, 1, 0))
4264887Schin 				al->attribute = mp->attribute;
4274887Schin 			goto mapped;
4284887Schin 		}
4294887Schin 	language_name = buf;
4304887Schin 	territory_name = charset_name = attributes_name = 0;
4314887Schin 	s = buf;
4324887Schin 	e = &buf[sizeof(buf)-2];
4334887Schin 	a = 0;
4344887Schin 	n = 0;
4354887Schin 	while (s < e && (c = *t++))
4364887Schin 	{
4374887Schin 		if (isspace(c) || (c == '(' || c == '-' && *t == '-') && ++n)
4384887Schin 		{
4394887Schin 			while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
4404887Schin 			if (!c)
4414887Schin 				break;
4424887Schin 			if (isalnum(c) && !n)
4434887Schin 				*s++ = '-';
4444887Schin 			else
4454887Schin 			{
4464887Schin 				n = 0;
4474887Schin 				if (!a)
4484887Schin 				{
4494887Schin 					a = t - 1;
4504887Schin 					while (c && c != '_' && c != '.' && c != '@')
4514887Schin 						c = *t++;
4524887Schin 					if (!c)
4534887Schin 						break;
4544887Schin 				}
4554887Schin 			}
4564887Schin 		}
4574887Schin 		if (c == '_' && !territory_name)
4584887Schin 		{
4594887Schin 			*s++ = 0;
4604887Schin 			territory_name = s;
4614887Schin 		}
4624887Schin 		else if (c == '.' && !charset_name)
4634887Schin 		{
4644887Schin 			*s++ = 0;
4654887Schin 			charset_name = s;
4664887Schin 		}
4674887Schin 		else if (c == '@' && !attributes_name)
4684887Schin 		{
4694887Schin 			*s++ = 0;
4704887Schin 			attributes_name = s;
4714887Schin 		}
4724887Schin 		else
4734887Schin 		{
4744887Schin 			if (isupper(c))
4754887Schin 				c = tolower(c);
4764887Schin 			*s++ = c;
4774887Schin 		}
4784887Schin 	}
4794887Schin 	if ((t = a) && s < e)
4804887Schin 	{
4814887Schin 		if (attributes_name)
4824887Schin 			*s++ = ',';
4834887Schin 		else
4844887Schin 		{
4854887Schin 			*s++ = 0;
4864887Schin 			attributes_name = s;
4874887Schin 		}
4884887Schin 		while (s < e && (c = *t++))
4894887Schin 		{
4904887Schin 			if (isspace(c) || (c == '(' || c == ')' || c == '-' && *t == '-') && ++n)
4914887Schin 			{
4924887Schin 				while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
4934887Schin 				if (!c)
4944887Schin 					break;
4954887Schin 				if (isalnum(c) && !n)
4964887Schin 					*s++ = '-';
4974887Schin 				else
4984887Schin 					n = 0;
4994887Schin 			}
5004887Schin 			if (c == '_' || c == '.' || c == '@')
5014887Schin 				break;
5024887Schin 			if (isupper(c))
5034887Schin 				c = tolower(c);
5044887Schin 			*s++ = c;
5054887Schin 		}
5064887Schin 	}
5074887Schin 	*s = 0;
5084887Schin 	tp = 0;
5094887Schin 	cp = ppa = 0;
5104887Schin 	al = 0;
5114887Schin 
5124887Schin 	/*
5134887Schin 	 * language
5144887Schin 	 */
5154887Schin 
5164887Schin 	n = strlen(s = language_name);
5174887Schin 	if (n == 2)
5188462SApril.Chin@Sun.COM 		for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
5194887Schin 	else if (n == 3)
5204887Schin 	{
5218462SApril.Chin@Sun.COM 		for (lp = lc_languages; lp->code && (!lp->alternates || !match(s, lp->alternates, n, 0)); lp++);
5224887Schin 		if (!lp->code)
5234887Schin 		{
5244887Schin 			c = s[2];
5254887Schin 			s[2] = 0;
5268462SApril.Chin@Sun.COM 			for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
5274887Schin 			s[2] = c;
5284887Schin 			if (lp->code)
5294887Schin 				n = 1;
5304887Schin 		}
5314887Schin 	}
5324887Schin 	else
5334887Schin 		lp = 0;
5344887Schin 	if (!lp || !lp->code)
5354887Schin 	{
5368462SApril.Chin@Sun.COM 		for (lp = lc_languages; lp->code && !match(s, lp->name, 0, 0); lp++);
5374887Schin 		if (!lp || !lp->code)
5384887Schin 		{
5394887Schin 			if (!territory_name)
5404887Schin 			{
5414887Schin 				if (n == 2)
5428462SApril.Chin@Sun.COM 					for (tp = lc_territories; tp->code && !streq(s, tp->code); tp++);
5434887Schin 				else
5444887Schin 				{
5454887Schin 					z = 0;
5464887Schin 					tpb = 0;
5478462SApril.Chin@Sun.COM 					for (tp = lc_territories; tp->name; tp++)
5484887Schin 						if ((i = match(s, tp->name, 3, 0)) > z)
5494887Schin 						{
5504887Schin 							tpb = tp;
5514887Schin 							if ((z = i) == n)
5524887Schin 								break;
5534887Schin 						}
5544887Schin 					if (tpb)
5554887Schin 						tp = tpb;
5564887Schin 				}
5574887Schin 				if (tp->code)
5584887Schin 					lp = tp->languages[0];
5594887Schin 			}
5604887Schin 			if (!lp || !lp->code)
5614887Schin 			{
5624887Schin 				/*
5634887Schin 				 * name not in the tables so let
5644887Schin 				 * _ast_setlocale() and/or setlocale()
5654887Schin 				 * handle the validity checks
5664887Schin 				 */
5674887Schin 
5684887Schin 				s = (char*)name;
5694887Schin 				z = strlen(s) + 1;
5704887Schin 				if (!(lp = newof(0, Lc_language_t, 1, z)))
5714887Schin 					return 0;
5724887Schin 				name = ((Lc_language_t*)lp)->code = ((Lc_language_t*)lp)->name = (const char*)(lp + 1);
5734887Schin 				memcpy((char*)lp->code, s, z - 1);
5748462SApril.Chin@Sun.COM 				tp = &lc_territories[0];
5758462SApril.Chin@Sun.COM 				cp = ((Lc_language_t*)lp)->charset = &lc_charsets[0];
5764887Schin 				al = 0;
5774887Schin 				goto override;
5784887Schin 			}
5794887Schin 		}
5804887Schin 	}
5814887Schin 
5824887Schin 	/*
5834887Schin 	 * territory
5844887Schin 	 */
5854887Schin 
5864887Schin 	if (!tp || !tp->code)
5874887Schin 	{
5884887Schin 		if (!(s = territory_name))
5894887Schin 		{
5904887Schin 			n = 0;
5914887Schin 			primary = 0;
5928462SApril.Chin@Sun.COM 			for (tp = lc_territories; tp->code; tp++)
5934887Schin 				if (tp->languages[0] == lp)
5944887Schin 				{
5954887Schin 					if (tp->flags & LC_primary)
5964887Schin 					{
5974887Schin 						n = 1;
5984887Schin 						primary = tp;
5994887Schin 						break;
6004887Schin 					}
6014887Schin 					n++;
6024887Schin 					primary = tp;
6034887Schin 				}
6044887Schin 			if (n == 1)
6054887Schin 				tp = primary;
6064887Schin 			s = (char*)lp->code;
6074887Schin 		}
6084887Schin 		if (!tp || !tp->code)
6094887Schin 		{
6104887Schin 			n = strlen(s);
6114887Schin 			if (n == 2)
6124887Schin 			{
6138462SApril.Chin@Sun.COM 				for (tp = lc_territories; tp->code; tp++)
6144887Schin 					if (streq(s, tp->code))
6154887Schin 					{
6164887Schin 						for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
6174887Schin 						if (i >= elementsof(tp->languages))
6184887Schin 							tp = 0;
6194887Schin 						break;
6204887Schin 					}
6214887Schin 			}
6224887Schin 			else
6234887Schin 			{
6248462SApril.Chin@Sun.COM 				for (tp = lc_territories; tp->code; tp++)
6254887Schin 					if (match(s, tp->name, 3, 0))
6264887Schin 					{
6274887Schin 						for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
6284887Schin 						if (i < elementsof(tp->languages))
6294887Schin 							break;
6304887Schin 					}
6314887Schin 			}
6324887Schin 			if (tp && !tp->code)
6334887Schin 				tp = 0;
6344887Schin 		}
6354887Schin 	}
6364887Schin 
6374887Schin 	/*
6384887Schin 	 * attributes -- done here to catch misplaced charset references
6394887Schin 	 */
6404887Schin 
6414887Schin 	if (s = attributes_name)
6424887Schin 	{
6434887Schin 		do
6444887Schin 		{
6454887Schin 			for (w = s; *s && *s != ','; s++);
6464887Schin 			c = *s;
6474887Schin 			*s = 0;
6484887Schin 			if (!(cp = lp->charset) || !match_charset(w, cp))
6498462SApril.Chin@Sun.COM 				for (cp = lc_charsets; cp->code; cp++)
6504887Schin 					if (match_charset(w, cp))
6514887Schin 					{
6524887Schin 						ppa = cp;
6534887Schin 						break;
6544887Schin 					}
6554887Schin 			if (!cp->code)
6564887Schin 			{
6574887Schin 				for (i = 0; i < elementsof(lp->attributes) && (ap = lp->attributes[i]); i++)
6584887Schin 					if (match(w, ap->name, 5, 0))
6594887Schin 					{
6604887Schin 						if (ai = newof(0, Lc_attribute_list_t, 1, 0))
6614887Schin 						{
6624887Schin 							ai->attribute = ap;
6634887Schin 							ai->next = al;
6644887Schin 							al = ai;
6654887Schin 						}
6664887Schin 						break;
6674887Schin 					}
6684887Schin 				if (i >= elementsof(lp->attributes) && (ap = newof(0, Lc_attribute_t, 1, sizeof(Lc_attribute_list_t) + s - w + 1)))
6694887Schin 				{
6704887Schin 					ai = (Lc_attribute_list_t*)(ap + 1);
6714887Schin 					strcpy((char*)(((Lc_attribute_t*)ap)->name = (const char*)(ai + 1)), w);
6724887Schin 					ai->attribute = ap;
6734887Schin 					ai->next = al;
6744887Schin 					al = ai;
6754887Schin 				}
6764887Schin 			}
6774887Schin 			*s = c;
6784887Schin 		} while (*s++);
6794887Schin 	}
6804887Schin 
6814887Schin 	/*
6824887Schin 	 * charset
6834887Schin 	 */
6844887Schin 
6854887Schin 	if (s = charset_name)
6868462SApril.Chin@Sun.COM 		for (cp = lc_charsets; cp->code; cp++)
6874887Schin 			if (match_charset(s, cp))
6884887Schin 				break;
6894887Schin 	if (!cp || !cp->code)
6904887Schin 		cp = ppa ? ppa : lp->charset;
6914887Schin  mapped:
6924887Schin 	z = canonical(lp, tp, cp, al, 0, s = tmp, sizeof(tmp));
6934887Schin 
6944887Schin 	/*
6954887Schin 	 * add to the list of possibly active locales
6964887Schin 	 */
6974887Schin 
6984887Schin  override:
6994887Schin 	n = strlen(name) + 1;
7004887Schin 	if (!(lc = newof(0, Lc_t, 1, n + z)))
7014887Schin 		return 0;
7024887Schin 	strcpy((char*)(lc->name = (const char*)(lc + 1)), name);
7034887Schin 	strcpy((char*)(lc->code = lc->name + n), s);
7048462SApril.Chin@Sun.COM 	lc->language = lp ? lp : &lc_languages[0];
7058462SApril.Chin@Sun.COM 	lc->territory = tp ? tp : &lc_territories[0];
7068462SApril.Chin@Sun.COM 	lc->charset = cp ? cp : &lc_charsets[0];
70710898Sroland.mainz@nrubsig.org 	if (!strcmp(lc->charset->code, "utf8"))
70810898Sroland.mainz@nrubsig.org 		lc->flags |= LC_utf8;
7094887Schin 	lc->attributes = al;
7104887Schin 	for (i = 0; i < elementsof(lc->info); i++)
7114887Schin 		lc->info[i].lc = lc;
7124887Schin #if _WINIX
7134887Schin 	n = SUBLANG_DEFAULT;
7144887Schin 	if (tp)
7154887Schin 		for (i = 0; i < elementsof(tp->languages); i++)
7164887Schin 			if (lp == tp->languages[i])
7174887Schin 			{
7184887Schin 				n = tp->indices[i];
7194887Schin 				break;
7204887Schin 			}
7214887Schin 	lc->index = MAKELCID(MAKELANGID(lp->index, n), SORT_DEFAULT);
7224887Schin #endif
7234887Schin 	lc->next = lcs;
7244887Schin 	lcs = lc;
7254887Schin 	return lc;
7264887Schin }
7274887Schin 
7284887Schin /*
7294887Schin  * return an Lc_t* for each locale in the tables
7304887Schin  * one Lc_t is allocated on the first call with lc==0
7314887Schin  * this is freed when 0 returned
7324887Schin  * the return value is not part of the lcmake() cache
7334887Schin  */
7344887Schin 
7354887Schin typedef struct Lc_scan_s
7364887Schin {
7374887Schin 	Lc_t			lc;
7384887Schin 	Lc_attribute_list_t	list;
7394887Schin 	int			territory;
7404887Schin 	int			language;
7414887Schin 	int			attribute;
7424887Schin 	char			buf[256];
7434887Schin } Lc_scan_t;
7444887Schin 
7454887Schin Lc_t*
lcscan(Lc_t * lc)7464887Schin lcscan(Lc_t* lc)
7474887Schin {
7484887Schin 	register Lc_scan_t*	ls;
7494887Schin 
7504887Schin 	if (!(ls = (Lc_scan_t*)lc))
7514887Schin 	{
7524887Schin 		if (!(ls = newof(0, Lc_scan_t, 1, 0)))
7534887Schin 			return 0;
7544887Schin 		ls->lc.code = ls->lc.name = ls->buf;
7554887Schin 		ls->territory = -1;
7564887Schin 		ls->language = elementsof(ls->lc.territory->languages);
7574887Schin 		ls->attribute = elementsof(ls->lc.language->attributes);
7584887Schin 	}
7594887Schin 	if (++ls->attribute >= elementsof(ls->lc.language->attributes) || !(ls->list.attribute = ls->lc.language->attributes[ls->attribute]))
7604887Schin 	{
7614887Schin 		if (++ls->language >= elementsof(ls->lc.territory->languages) || !(ls->lc.language = ls->lc.territory->languages[ls->language]))
7624887Schin 		{
7638462SApril.Chin@Sun.COM 			if (!lc_territories[++ls->territory].code)
7644887Schin 			{
7654887Schin 				free(ls);
7664887Schin 				return 0;
7674887Schin 			}
7688462SApril.Chin@Sun.COM 			ls->lc.territory = &lc_territories[ls->territory];
7694887Schin 			ls->lc.language = ls->lc.territory->languages[ls->language = 0];
7704887Schin 		}
7714887Schin 		if (ls->lc.language)
7724887Schin 		{
7738462SApril.Chin@Sun.COM 			ls->lc.charset = ls->lc.language->charset ? ls->lc.language->charset : &lc_charsets[0];
7744887Schin 			ls->list.attribute = ls->lc.language->attributes[ls->attribute = 0];
7754887Schin 		}
7764887Schin 		else
7774887Schin 		{
7788462SApril.Chin@Sun.COM 			ls->lc.charset = &lc_charsets[0];
7794887Schin 			ls->list.attribute = 0;
7804887Schin 		}
7814887Schin 	}
7824887Schin 	ls->lc.attributes = ls->list.attribute ? &ls->list : (Lc_attribute_list_t*)0;
7834887Schin #if _WINIX
7844887Schin 	if (!ls->lc.language || !ls->lc.language->index)
7854887Schin 		ls->lc.index = 0;
7864887Schin 	else
7874887Schin 	{
7884887Schin 		if ((!ls->list.attribute || !(ls->lc.index = ls->list.attribute->index)) &&
7894887Schin 		    (!ls->lc.territory || !(ls->lc.index = ls->lc.territory->indices[ls->language])))
7904887Schin 			ls->lc.index = SUBLANG_DEFAULT;
7914887Schin 		ls->lc.index = MAKELCID(MAKELANGID(ls->lc.language->index, ls->lc.index), SORT_DEFAULT);
7924887Schin 	}
7934887Schin #endif
7944887Schin 	canonical(ls->lc.language, ls->lc.territory, ls->lc.charset, ls->lc.attributes, 0, ls->buf, sizeof(ls->buf));
7954887Schin 	return (Lc_t*)ls;
7964887Schin }
797