xref: /onnv-gate/usr/src/lib/libast/common/port/lc.c (revision 8462:6e341f5569ba)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.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"
29*8462SApril.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",
39*8462SApril.Chin@Sun.COM 	&lc_languages[0],
40*8462SApril.Chin@Sun.COM 	&lc_territories[0],
41*8462SApril.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",
69*8462SApril.Chin@Sun.COM 	&lc_languages[1],
70*8462SApril.Chin@Sun.COM 	&lc_territories[1],
71*8462SApril.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
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;
1284887Schin 	case LC_MEASUREMENT:	return AST_LC_MEASUREMENT;
1294887Schin 	case LC_MESSAGES:	return AST_LC_MESSAGES;
1304887Schin 	case LC_MONETARY:	return AST_LC_MONETARY;
1314887Schin 	case LC_NAME:		return AST_LC_NAME;
1324887Schin 	case LC_NUMERIC:	return AST_LC_NUMERIC;
1334887Schin 	case LC_PAPER:		return AST_LC_PAPER;
1344887Schin 	case LC_TELEPHONE:	return AST_LC_TELEPHONE;
1354887Schin 	case LC_TIME:		return AST_LC_TIME;
1364887Schin 	case LC_XLITERATE:	return AST_LC_XLITERATE;
1374887Schin 	}
1384887Schin 	return -1;
1394887Schin }
1404887Schin 
1414887Schin /*
1424887Schin  * return the first category table entry
1434887Schin  */
1444887Schin 
1454887Schin Lc_category_t*
1464887Schin lccategories(void)
1474887Schin {
148*8462SApril.Chin@Sun.COM 	return (Lc_category_t*)&lc_categories[0];
1494887Schin }
1504887Schin 
1514887Schin /*
1524887Schin  * return the current info for category
1534887Schin  */
1544887Schin 
1554887Schin Lc_info_t*
1564887Schin lcinfo(register int category)
1574887Schin {
1584887Schin 	if ((category = lcindex(category, 0)) < 0)
1594887Schin 		return 0;
1604887Schin 	return LCINFO(category);
1614887Schin }
1624887Schin 
1634887Schin /*
1644887Schin  * return 1 if s matches the alternation pattern p
1654887Schin  * if minimum!=0 then at least that many chars must match
1664887Schin  * if standard!=0 and s[0] is a digit leading non-digits are ignored in p
1674887Schin  */
1684887Schin 
1694887Schin static int
1704887Schin match(const char* s, register const char* p, int minimum, int standard)
1714887Schin {
1724887Schin 	register const char*	t;
1734887Schin 	const char*		x;
1744887Schin 	int			w;
1754887Schin 	int			z;
1764887Schin 
1774887Schin 	z = 0;
1784887Schin 	do
1794887Schin 	{
1804887Schin 		t = s;
1814887Schin 		if (standard)
1824887Schin 		{
1834887Schin 			if (isdigit(*t))
1844887Schin 				while (*p && !isdigit(*p))
1854887Schin 					p++;
1864887Schin 			else if (isdigit(*p))
1874887Schin 				while (*t && !isdigit(*t))
1884887Schin 					t++;
1894887Schin 		}
1904887Schin 		if (*p)
1914887Schin 		{
1924887Schin 			w = 0;
1934887Schin 			x = p;
1944887Schin 			while (*p && *p != '|')
1954887Schin 			{
1964887Schin 				if (!*t || *t == ',')
1974887Schin 					break;
1984887Schin 				else if (*t == *p)
1994887Schin 					/*ok*/;
2004887Schin 				else if (*t == '-')
2014887Schin 				{
2024887Schin 					if (standard && isdigit(*p))
2034887Schin 					{
2044887Schin 						t++;
2054887Schin 						continue;
2064887Schin 					}
2074887Schin 					while (*p && *p != '-')
2084887Schin 						p++;
2094887Schin 					if (!*p)
2104887Schin 						break;
2114887Schin 				}
2124887Schin 				else if (*p == '-')
2134887Schin 				{
2144887Schin 					if (standard && isdigit(*t))
2154887Schin 					{
2164887Schin 						p++;
2174887Schin 						continue;
2184887Schin 					}
2194887Schin 					w = 1;
2204887Schin 					while (*t && *t != '-')
2214887Schin 						t++;
2224887Schin 					if (!*t)
2234887Schin 						break;
2244887Schin 				}
2254887Schin 				else
2264887Schin 					break;
2274887Schin 				t++;
2284887Schin 				p++;
2294887Schin 			}
2304887Schin 			if ((!*t || *t == ',') && (!*p || *p == '|' || w))
2314887Schin 				return p - x;
2324887Schin 			if (minimum && z < (p - x) && (p - x) >= minimum)
2334887Schin 				z = p - x;
2344887Schin 		}
2354887Schin 		while (*p && *p != '|')
2364887Schin 			p++;
2374887Schin 	} while (*p++);
2384887Schin 	return z;
2394887Schin }
2404887Schin 
2414887Schin /*
2424887Schin  * return 1 if s matches the charset names in cp
2434887Schin  */
2444887Schin 
2454887Schin static int
2464887Schin match_charset(register const char* s, register const Lc_charset_t* cp)
2474887Schin {
2484887Schin 	return match(s, cp->code, 0, 1) || match(s, cp->alternates, 3, 1) || cp->ms && match(s, cp->ms, 0, 1);
2494887Schin }
2504887Schin 
2514887Schin /*
2524887Schin  * low level for lccanon
2534887Schin  */
2544887Schin 
2554887Schin static size_t
2564887Schin 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 {
2584887Schin 	register int		c;
2594887Schin 	register int		u;
2604887Schin 	register char*		s;
2614887Schin 	register char*		e;
2624887Schin 	register const char*	t;
2634887Schin 
2644887Schin 	if (!(flags & (LC_abbreviated|LC_default|LC_local|LC_qualified|LC_verbose)))
2654887Schin 		flags |= LC_abbreviated;
2664887Schin 	s = buf;
2674887Schin 	e = &buf[siz - 3];
2684887Schin 	if (lp)
2694887Schin 	{
2704887Schin 		if (lp->flags & (LC_debug|LC_default))
2714887Schin 		{
2724887Schin 			for (t = lp->code; s < e && (*s = *t++); s++);
2734887Schin 			*s++ = 0;
2744887Schin 			return s - buf;
2754887Schin 		}
2764887Schin 		if (flags & LC_verbose)
2774887Schin 		{
2784887Schin 			u = 1;
2794887Schin 			t = lp->name;
2804887Schin 			while (s < e && (c = *t++))
2814887Schin 			{
2824887Schin 				if (u)
2834887Schin 				{
2844887Schin 					u = 0;
2854887Schin 					c = toupper(c);
2864887Schin 				}
2874887Schin 				else if (!isalnum(c))
2884887Schin 					u = 1;
2894887Schin 				*s++ = c;
2904887Schin 			}
2914887Schin 		}
2924887Schin 		else
2934887Schin 			for (t = lp->code; s < e && (*s = *t++); s++);
2944887Schin 	}
2954887Schin 	if (s < e)
2964887Schin 	{
297*8462SApril.Chin@Sun.COM 		if (tp && tp != &lc_territories[0] && (!(flags & (LC_abbreviated|LC_default)) || !lp || !streq(lp->code, tp->code)))
2984887Schin 		{
2994887Schin 			if (lp)
3004887Schin 				*s++ = '_';
3014887Schin 			if (flags & LC_verbose)
3024887Schin 			{
3034887Schin 				u = 1;
3044887Schin 				t = tp->name;
3054887Schin 				while (s < e && (c = *t++) && c != '|')
3064887Schin 				{
3074887Schin 					if (u)
3084887Schin 					{
3094887Schin 						u = 0;
3104887Schin 						c = toupper(c);
3114887Schin 					}
3124887Schin 					else if (!isalnum(c))
3134887Schin 						u = 1;
3144887Schin 					*s++ = c;
3154887Schin 				}
3164887Schin 			}
3174887Schin 			else
3184887Schin 				for (t = tp->code; s < e && (*s = toupper(*t++)); s++);
3194887Schin 		}
3204887Schin 		if (lp && (!(flags & (LC_abbreviated|LC_default)) || cp != lp->charset) && s < e)
3214887Schin 		{
3224887Schin 			*s++ = '.';
3234887Schin 			for (t = cp->code; s < e && (c = *t++); s++)
3244887Schin 			{
3254887Schin 				if (islower(c))
3264887Schin 					c = toupper(c);
3274887Schin 				*s = c;
3284887Schin 			}
3294887Schin 		}
3304887Schin 		for (c = '@'; ap && s < e; ap = ap->next)
3314887Schin 			if (!(flags & (LC_abbreviated|LC_default|LC_verbose)) || !(ap->attribute->flags & LC_default))
3324887Schin 			{
3334887Schin 				*s++ = c;
3344887Schin 				c = ',';
3354887Schin 				for (t = ap->attribute->name; s < e && (*s = *t++); s++);
3364887Schin 			}
3374887Schin 	}
3384887Schin 	*s++ = 0;
3394887Schin 	return s - buf;
3404887Schin }
3414887Schin 
3424887Schin /*
3434887Schin  * generate a canonical locale name in buf
3444887Schin  */
3454887Schin 
3464887Schin size_t
3474887Schin lccanon(Lc_t* lc, unsigned long flags, char* buf, size_t siz)
3484887Schin {
3494887Schin 	if ((flags & LC_local) && (!lc->language || !(lc->language->flags & (LC_debug|LC_default))))
3504887Schin 	{
3514887Schin #if _WINIX
3524887Schin 		char	lang[64];
3534887Schin 		char	code[64];
3544887Schin 		char	ctry[64];
3554887Schin 
3564887Schin 		if (lc->index &&
3574887Schin 		    GetLocaleInfo(lc->index, LOCALE_SENGLANGUAGE, lang, sizeof(lang)) &&
3584887Schin 		    GetLocaleInfo(lc->index, LOCALE_SENGCOUNTRY, ctry, sizeof(ctry)))
3594887Schin 		{
3604887Schin 		    	if (!GetLocaleInfo(lc->index, LOCALE_IDEFAULTANSICODEPAGE, code, sizeof(code)))
3614887Schin 				code[0] = 0;
3624887Schin 			if (!lc->charset || !lc->charset->ms)
3634887Schin 				return sfsprintf(buf, siz, "%s_%s", lang, ctry);
3644887Schin 			else if (streq(lc->charset->ms, code))
3654887Schin 				return sfsprintf(buf, siz, "%s_%s.%s", lang, ctry, code);
3664887Schin 			else
3674887Schin 				return sfsprintf(buf, siz, "%s_%s.%s,%s", lang, ctry, code, lc->charset->ms);
3684887Schin 		}
3694887Schin #endif
3704887Schin 		buf[0] = '-';
3714887Schin 		buf[1] = 0;
3724887Schin 		return 0;
3734887Schin 	}
3744887Schin 	return canonical(lc->language, lc->territory, lc->charset, lc->attributes, flags, buf, siz);
3754887Schin }
3764887Schin 
3774887Schin /*
3784887Schin  * make an Lc_t from a locale name
3794887Schin  */
3804887Schin 
3814887Schin Lc_t*
3824887Schin lcmake(const char* name)
3834887Schin {
3844887Schin 	register int			c;
3854887Schin 	register char*			s;
3864887Schin 	register char*			e;
3874887Schin 	register const char*		t;
3884887Schin 	const char*			a;
3894887Schin 	char*				w;
3904887Schin 	char*				language_name;
3914887Schin 	char*				territory_name;
3924887Schin 	char*				charset_name;
3934887Schin 	char*				attributes_name;
3944887Schin 	Lc_t*				lc;
3954887Schin 	const Lc_map_t*			mp;
3964887Schin 	const Lc_language_t*		lp;
3974887Schin 	const Lc_territory_t*		tp;
3984887Schin 	const Lc_territory_t*		tpb;
3994887Schin 	const Lc_territory_t*		primary;
4004887Schin 	const Lc_charset_t*		cp;
4014887Schin 	const Lc_charset_t*		ppa;
4024887Schin 	const Lc_attribute_t*		ap;
4034887Schin 	Lc_attribute_list_t*		ai;
4044887Schin 	Lc_attribute_list_t*		al;
4054887Schin 	int				i;
4064887Schin 	int				n;
4074887Schin 	int				z;
4084887Schin 	char				buf[PATH_MAX / 2];
4094887Schin 	char				tmp[PATH_MAX / 2];
4104887Schin 
4114887Schin 	if (!(t = name) || !*t)
4124887Schin 		return &default_lc;
4134887Schin 	for (lc = lcs; lc; lc = lc->next)
4144887Schin 		if (!strcasecmp(t, lc->code) || !strcasecmp(t, lc->name))
4154887Schin 			return lc;
416*8462SApril.Chin@Sun.COM 	for (mp = lc_maps; mp->code; mp++)
4174887Schin 		if (streq(t, mp->code))
4184887Schin 		{
4194887Schin 			lp = mp->language;
4204887Schin 			tp = mp->territory;
4214887Schin 			cp = mp->charset;
4224887Schin 			if (!mp->attribute)
4234887Schin 				al = 0;
4244887Schin 			else if (al = newof(0, Lc_attribute_list_t, 1, 0))
4254887Schin 				al->attribute = mp->attribute;
4264887Schin 			goto mapped;
4274887Schin 		}
4284887Schin 	language_name = buf;
4294887Schin 	territory_name = charset_name = attributes_name = 0;
4304887Schin 	s = buf;
4314887Schin 	e = &buf[sizeof(buf)-2];
4324887Schin 	a = 0;
4334887Schin 	n = 0;
4344887Schin 	while (s < e && (c = *t++))
4354887Schin 	{
4364887Schin 		if (isspace(c) || (c == '(' || c == '-' && *t == '-') && ++n)
4374887Schin 		{
4384887Schin 			while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
4394887Schin 			if (!c)
4404887Schin 				break;
4414887Schin 			if (isalnum(c) && !n)
4424887Schin 				*s++ = '-';
4434887Schin 			else
4444887Schin 			{
4454887Schin 				n = 0;
4464887Schin 				if (!a)
4474887Schin 				{
4484887Schin 					a = t - 1;
4494887Schin 					while (c && c != '_' && c != '.' && c != '@')
4504887Schin 						c = *t++;
4514887Schin 					if (!c)
4524887Schin 						break;
4534887Schin 				}
4544887Schin 			}
4554887Schin 		}
4564887Schin 		if (c == '_' && !territory_name)
4574887Schin 		{
4584887Schin 			*s++ = 0;
4594887Schin 			territory_name = s;
4604887Schin 		}
4614887Schin 		else if (c == '.' && !charset_name)
4624887Schin 		{
4634887Schin 			*s++ = 0;
4644887Schin 			charset_name = s;
4654887Schin 		}
4664887Schin 		else if (c == '@' && !attributes_name)
4674887Schin 		{
4684887Schin 			*s++ = 0;
4694887Schin 			attributes_name = s;
4704887Schin 		}
4714887Schin 		else
4724887Schin 		{
4734887Schin 			if (isupper(c))
4744887Schin 				c = tolower(c);
4754887Schin 			*s++ = c;
4764887Schin 		}
4774887Schin 	}
4784887Schin 	if ((t = a) && s < e)
4794887Schin 	{
4804887Schin 		if (attributes_name)
4814887Schin 			*s++ = ',';
4824887Schin 		else
4834887Schin 		{
4844887Schin 			*s++ = 0;
4854887Schin 			attributes_name = s;
4864887Schin 		}
4874887Schin 		while (s < e && (c = *t++))
4884887Schin 		{
4894887Schin 			if (isspace(c) || (c == '(' || c == ')' || c == '-' && *t == '-') && ++n)
4904887Schin 			{
4914887Schin 				while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
4924887Schin 				if (!c)
4934887Schin 					break;
4944887Schin 				if (isalnum(c) && !n)
4954887Schin 					*s++ = '-';
4964887Schin 				else
4974887Schin 					n = 0;
4984887Schin 			}
4994887Schin 			if (c == '_' || c == '.' || c == '@')
5004887Schin 				break;
5014887Schin 			if (isupper(c))
5024887Schin 				c = tolower(c);
5034887Schin 			*s++ = c;
5044887Schin 		}
5054887Schin 	}
5064887Schin 	*s = 0;
5074887Schin 	tp = 0;
5084887Schin 	cp = ppa = 0;
5094887Schin 	al = 0;
5104887Schin 
5114887Schin 	/*
5124887Schin 	 * language
5134887Schin 	 */
5144887Schin 
5154887Schin 	n = strlen(s = language_name);
5164887Schin 	if (n == 2)
517*8462SApril.Chin@Sun.COM 		for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
5184887Schin 	else if (n == 3)
5194887Schin 	{
520*8462SApril.Chin@Sun.COM 		for (lp = lc_languages; lp->code && (!lp->alternates || !match(s, lp->alternates, n, 0)); lp++);
5214887Schin 		if (!lp->code)
5224887Schin 		{
5234887Schin 			c = s[2];
5244887Schin 			s[2] = 0;
525*8462SApril.Chin@Sun.COM 			for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
5264887Schin 			s[2] = c;
5274887Schin 			if (lp->code)
5284887Schin 				n = 1;
5294887Schin 		}
5304887Schin 	}
5314887Schin 	else
5324887Schin 		lp = 0;
5334887Schin 	if (!lp || !lp->code)
5344887Schin 	{
535*8462SApril.Chin@Sun.COM 		for (lp = lc_languages; lp->code && !match(s, lp->name, 0, 0); lp++);
5364887Schin 		if (!lp || !lp->code)
5374887Schin 		{
5384887Schin 			if (!territory_name)
5394887Schin 			{
5404887Schin 				if (n == 2)
541*8462SApril.Chin@Sun.COM 					for (tp = lc_territories; tp->code && !streq(s, tp->code); tp++);
5424887Schin 				else
5434887Schin 				{
5444887Schin 					z = 0;
5454887Schin 					tpb = 0;
546*8462SApril.Chin@Sun.COM 					for (tp = lc_territories; tp->name; tp++)
5474887Schin 						if ((i = match(s, tp->name, 3, 0)) > z)
5484887Schin 						{
5494887Schin 							tpb = tp;
5504887Schin 							if ((z = i) == n)
5514887Schin 								break;
5524887Schin 						}
5534887Schin 					if (tpb)
5544887Schin 						tp = tpb;
5554887Schin 				}
5564887Schin 				if (tp->code)
5574887Schin 					lp = tp->languages[0];
5584887Schin 			}
5594887Schin 			if (!lp || !lp->code)
5604887Schin 			{
5614887Schin 				/*
5624887Schin 				 * name not in the tables so let
5634887Schin 				 * _ast_setlocale() and/or setlocale()
5644887Schin 				 * handle the validity checks
5654887Schin 				 */
5664887Schin 
5674887Schin 				s = (char*)name;
5684887Schin 				z = strlen(s) + 1;
5694887Schin 				if (!(lp = newof(0, Lc_language_t, 1, z)))
5704887Schin 					return 0;
5714887Schin 				name = ((Lc_language_t*)lp)->code = ((Lc_language_t*)lp)->name = (const char*)(lp + 1);
5724887Schin 				memcpy((char*)lp->code, s, z - 1);
573*8462SApril.Chin@Sun.COM 				tp = &lc_territories[0];
574*8462SApril.Chin@Sun.COM 				cp = ((Lc_language_t*)lp)->charset = &lc_charsets[0];
5754887Schin 				al = 0;
5764887Schin 				goto override;
5774887Schin 			}
5784887Schin 		}
5794887Schin 	}
5804887Schin 
5814887Schin 	/*
5824887Schin 	 * territory
5834887Schin 	 */
5844887Schin 
5854887Schin 	if (!tp || !tp->code)
5864887Schin 	{
5874887Schin 		if (!(s = territory_name))
5884887Schin 		{
5894887Schin 			n = 0;
5904887Schin 			primary = 0;
591*8462SApril.Chin@Sun.COM 			for (tp = lc_territories; tp->code; tp++)
5924887Schin 				if (tp->languages[0] == lp)
5934887Schin 				{
5944887Schin 					if (tp->flags & LC_primary)
5954887Schin 					{
5964887Schin 						n = 1;
5974887Schin 						primary = tp;
5984887Schin 						break;
5994887Schin 					}
6004887Schin 					n++;
6014887Schin 					primary = tp;
6024887Schin 				}
6034887Schin 			if (n == 1)
6044887Schin 				tp = primary;
6054887Schin 			s = (char*)lp->code;
6064887Schin 		}
6074887Schin 		if (!tp || !tp->code)
6084887Schin 		{
6094887Schin 			n = strlen(s);
6104887Schin 			if (n == 2)
6114887Schin 			{
612*8462SApril.Chin@Sun.COM 				for (tp = lc_territories; tp->code; tp++)
6134887Schin 					if (streq(s, tp->code))
6144887Schin 					{
6154887Schin 						for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
6164887Schin 						if (i >= elementsof(tp->languages))
6174887Schin 							tp = 0;
6184887Schin 						break;
6194887Schin 					}
6204887Schin 			}
6214887Schin 			else
6224887Schin 			{
623*8462SApril.Chin@Sun.COM 				for (tp = lc_territories; tp->code; tp++)
6244887Schin 					if (match(s, tp->name, 3, 0))
6254887Schin 					{
6264887Schin 						for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
6274887Schin 						if (i < elementsof(tp->languages))
6284887Schin 							break;
6294887Schin 					}
6304887Schin 			}
6314887Schin 			if (tp && !tp->code)
6324887Schin 				tp = 0;
6334887Schin 		}
6344887Schin 	}
6354887Schin 
6364887Schin 	/*
6374887Schin 	 * attributes -- done here to catch misplaced charset references
6384887Schin 	 */
6394887Schin 
6404887Schin 	if (s = attributes_name)
6414887Schin 	{
6424887Schin 		do
6434887Schin 		{
6444887Schin 			for (w = s; *s && *s != ','; s++);
6454887Schin 			c = *s;
6464887Schin 			*s = 0;
6474887Schin 			if (!(cp = lp->charset) || !match_charset(w, cp))
648*8462SApril.Chin@Sun.COM 				for (cp = lc_charsets; cp->code; cp++)
6494887Schin 					if (match_charset(w, cp))
6504887Schin 					{
6514887Schin 						ppa = cp;
6524887Schin 						break;
6534887Schin 					}
6544887Schin 			if (!cp->code)
6554887Schin 			{
6564887Schin 				for (i = 0; i < elementsof(lp->attributes) && (ap = lp->attributes[i]); i++)
6574887Schin 					if (match(w, ap->name, 5, 0))
6584887Schin 					{
6594887Schin 						if (ai = newof(0, Lc_attribute_list_t, 1, 0))
6604887Schin 						{
6614887Schin 							ai->attribute = ap;
6624887Schin 							ai->next = al;
6634887Schin 							al = ai;
6644887Schin 						}
6654887Schin 						break;
6664887Schin 					}
6674887Schin 				if (i >= elementsof(lp->attributes) && (ap = newof(0, Lc_attribute_t, 1, sizeof(Lc_attribute_list_t) + s - w + 1)))
6684887Schin 				{
6694887Schin 					ai = (Lc_attribute_list_t*)(ap + 1);
6704887Schin 					strcpy((char*)(((Lc_attribute_t*)ap)->name = (const char*)(ai + 1)), w);
6714887Schin 					ai->attribute = ap;
6724887Schin 					ai->next = al;
6734887Schin 					al = ai;
6744887Schin 				}
6754887Schin 			}
6764887Schin 			*s = c;
6774887Schin 		} while (*s++);
6784887Schin 	}
6794887Schin 
6804887Schin 	/*
6814887Schin 	 * charset
6824887Schin 	 */
6834887Schin 
6844887Schin 	if (s = charset_name)
685*8462SApril.Chin@Sun.COM 		for (cp = lc_charsets; cp->code; cp++)
6864887Schin 			if (match_charset(s, cp))
6874887Schin 				break;
6884887Schin 	if (!cp || !cp->code)
6894887Schin 		cp = ppa ? ppa : lp->charset;
6904887Schin  mapped:
6914887Schin 	z = canonical(lp, tp, cp, al, 0, s = tmp, sizeof(tmp));
6924887Schin 
6934887Schin 	/*
6944887Schin 	 * add to the list of possibly active locales
6954887Schin 	 */
6964887Schin 
6974887Schin  override:
6984887Schin 	n = strlen(name) + 1;
6994887Schin 	if (!(lc = newof(0, Lc_t, 1, n + z)))
7004887Schin 		return 0;
7014887Schin 	strcpy((char*)(lc->name = (const char*)(lc + 1)), name);
7024887Schin 	strcpy((char*)(lc->code = lc->name + n), s);
703*8462SApril.Chin@Sun.COM 	lc->language = lp ? lp : &lc_languages[0];
704*8462SApril.Chin@Sun.COM 	lc->territory = tp ? tp : &lc_territories[0];
705*8462SApril.Chin@Sun.COM 	lc->charset = cp ? cp : &lc_charsets[0];
7064887Schin 	lc->attributes = al;
7074887Schin 	for (i = 0; i < elementsof(lc->info); i++)
7084887Schin 		lc->info[i].lc = lc;
7094887Schin #if _WINIX
7104887Schin 	n = SUBLANG_DEFAULT;
7114887Schin 	if (tp)
7124887Schin 		for (i = 0; i < elementsof(tp->languages); i++)
7134887Schin 			if (lp == tp->languages[i])
7144887Schin 			{
7154887Schin 				n = tp->indices[i];
7164887Schin 				break;
7174887Schin 			}
7184887Schin 	lc->index = MAKELCID(MAKELANGID(lp->index, n), SORT_DEFAULT);
7194887Schin #endif
7204887Schin 	lc->next = lcs;
7214887Schin 	lcs = lc;
7224887Schin 	return lc;
7234887Schin }
7244887Schin 
7254887Schin /*
7264887Schin  * return an Lc_t* for each locale in the tables
7274887Schin  * one Lc_t is allocated on the first call with lc==0
7284887Schin  * this is freed when 0 returned
7294887Schin  * the return value is not part of the lcmake() cache
7304887Schin  */
7314887Schin 
7324887Schin typedef struct Lc_scan_s
7334887Schin {
7344887Schin 	Lc_t			lc;
7354887Schin 	Lc_attribute_list_t	list;
7364887Schin 	int			territory;
7374887Schin 	int			language;
7384887Schin 	int			attribute;
7394887Schin 	char			buf[256];
7404887Schin } Lc_scan_t;
7414887Schin 
7424887Schin Lc_t*
7434887Schin lcscan(Lc_t* lc)
7444887Schin {
7454887Schin 	register Lc_scan_t*	ls;
7464887Schin 
7474887Schin 	if (!(ls = (Lc_scan_t*)lc))
7484887Schin 	{
7494887Schin 		if (!(ls = newof(0, Lc_scan_t, 1, 0)))
7504887Schin 			return 0;
7514887Schin 		ls->lc.code = ls->lc.name = ls->buf;
7524887Schin 		ls->territory = -1;
7534887Schin 		ls->language = elementsof(ls->lc.territory->languages);
7544887Schin 		ls->attribute = elementsof(ls->lc.language->attributes);
7554887Schin 	}
7564887Schin 	if (++ls->attribute >= elementsof(ls->lc.language->attributes) || !(ls->list.attribute = ls->lc.language->attributes[ls->attribute]))
7574887Schin 	{
7584887Schin 		if (++ls->language >= elementsof(ls->lc.territory->languages) || !(ls->lc.language = ls->lc.territory->languages[ls->language]))
7594887Schin 		{
760*8462SApril.Chin@Sun.COM 			if (!lc_territories[++ls->territory].code)
7614887Schin 			{
7624887Schin 				free(ls);
7634887Schin 				return 0;
7644887Schin 			}
765*8462SApril.Chin@Sun.COM 			ls->lc.territory = &lc_territories[ls->territory];
7664887Schin 			ls->lc.language = ls->lc.territory->languages[ls->language = 0];
7674887Schin 		}
7684887Schin 		if (ls->lc.language)
7694887Schin 		{
770*8462SApril.Chin@Sun.COM 			ls->lc.charset = ls->lc.language->charset ? ls->lc.language->charset : &lc_charsets[0];
7714887Schin 			ls->list.attribute = ls->lc.language->attributes[ls->attribute = 0];
7724887Schin 		}
7734887Schin 		else
7744887Schin 		{
775*8462SApril.Chin@Sun.COM 			ls->lc.charset = &lc_charsets[0];
7764887Schin 			ls->list.attribute = 0;
7774887Schin 		}
7784887Schin 	}
7794887Schin 	ls->lc.attributes = ls->list.attribute ? &ls->list : (Lc_attribute_list_t*)0;
7804887Schin #if _WINIX
7814887Schin 	if (!ls->lc.language || !ls->lc.language->index)
7824887Schin 		ls->lc.index = 0;
7834887Schin 	else
7844887Schin 	{
7854887Schin 		if ((!ls->list.attribute || !(ls->lc.index = ls->list.attribute->index)) &&
7864887Schin 		    (!ls->lc.territory || !(ls->lc.index = ls->lc.territory->indices[ls->language])))
7874887Schin 			ls->lc.index = SUBLANG_DEFAULT;
7884887Schin 		ls->lc.index = MAKELCID(MAKELANGID(ls->lc.language->index, ls->lc.index), SORT_DEFAULT);
7894887Schin 	}
7904887Schin #endif
7914887Schin 	canonical(ls->lc.language, ls->lc.territory, ls->lc.charset, ls->lc.attributes, 0, ls->buf, sizeof(ls->buf));
7924887Schin 	return (Lc_t*)ls;
7934887Schin }
794