xref: /onnv-gate/usr/src/lib/libast/common/port/mc.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  * Glenn Fowler
264887Schin  * AT&T Research
274887Schin  *
284887Schin  * machine independent binary message catalog implementation
294887Schin  */
304887Schin 
314887Schin #include "sfhdr.h"
324887Schin #include "lclib.h"
334887Schin 
344887Schin #include <iconv.h>
354887Schin 
364887Schin #define _MC_PRIVATE_ \
374887Schin 	size_t		nstrs; \
384887Schin 	size_t		nmsgs; \
394887Schin 	iconv_t		cvt; \
404887Schin 	Sfio_t*		tmp; \
414887Schin 	Vmalloc_t*	vm;
424887Schin 
434887Schin #include <vmalloc.h>
444887Schin #include <error.h>
454887Schin #include <mc.h>
464887Schin #include <nl_types.h>
474887Schin 
484887Schin /*
494887Schin  * find the binary message catalog path for <locale,catalog>
504887Schin  * result placed in path of size PATH_MAX
514887Schin  * pointer to path returned
524887Schin  * catalog==0 tests for category directory or file
534887Schin  * nls!=0 enables NLSPATH+LANG hack (not implemented yet)
544887Schin  */
554887Schin 
564887Schin char*
mcfind(char * path,const char * locale,const char * catalog,int category,int nls)574887Schin mcfind(char* path, const char* locale, const char* catalog, int category, int nls)
584887Schin {
594887Schin 	register int		c;
604887Schin 	register char*		s;
614887Schin 	register char*		e;
624887Schin 	register char*		p;
634887Schin 	register const char*	v;
644887Schin 	int			i;
654887Schin 	int			first;
664887Schin 	int			next;
674887Schin 	int			last;
684887Schin 	int			oerrno;
694887Schin 	Lc_t*			lc;
704887Schin 	char			file[PATH_MAX];
714887Schin 	char*			paths[5];
724887Schin 
734887Schin 	static char		lc_messages[] = "LC_MESSAGES";
744887Schin 
754887Schin 	if ((category = lcindex(category, 1)) < 0)
764887Schin 		return 0;
774887Schin 	if (!(lc = locale ? lcmake(locale) : locales[category]))
784887Schin 		return 0;
794887Schin 	oerrno = errno;
804887Schin 	if (catalog && *catalog == '/')
814887Schin 	{
824887Schin 		i = eaccess(catalog, R_OK);
834887Schin 		errno = oerrno;
844887Schin 		if (i)
854887Schin 			return 0;
864887Schin 		strncpy(path, catalog, PATH_MAX-1);
874887Schin 		return path;
884887Schin 	}
894887Schin 	i = 0;
904887Schin #if !_lib_catopen
914887Schin 	if ((p = getenv("NLSPATH")) && *p)
924887Schin 		paths[i++] = p;
934887Schin #endif
944887Schin 	paths[i++] = "share/lib/locale/%l/%C/%N";
954887Schin 	paths[i++] = "share/locale/%l/%C/%N";
964887Schin 	paths[i++] = "lib/locale/%l/%C/%N";
974887Schin 	paths[i] = 0;
984887Schin 	next = 1;
994887Schin 	for (i = 0; p = paths[i]; i += next)
1004887Schin 	{
1014887Schin 		first = 1;
1024887Schin 		last = 0;
1034887Schin 		e = &file[elementsof(file) - 1];
1044887Schin 		while (*p)
1054887Schin 		{
1064887Schin 			s = file;
1074887Schin 			for (;;)
1084887Schin 			{
1094887Schin 				switch (c = *p++)
1104887Schin 				{
1114887Schin 				case 0:
1124887Schin 					p--;
1134887Schin 					break;
1144887Schin 				case ':':
1154887Schin 					break;
1164887Schin 				case '%':
1174887Schin 					if (s < e)
1184887Schin 					{
1194887Schin 						switch (c = *p++)
1204887Schin 						{
1214887Schin 						case 0:
1224887Schin 							p--;
1234887Schin 							continue;
1244887Schin 						case 'N':
1254887Schin 							v = catalog;
1264887Schin 							break;
1274887Schin 						case 'L':
1284887Schin 							if (first)
1294887Schin 							{
1304887Schin 								first = 0;
1314887Schin 								if (next)
1324887Schin 								{
1334887Schin 									v = lc->code;
1344887Schin 									if (lc->code != lc->language->code)
1354887Schin 										next = 0;
1364887Schin 								}
1374887Schin 								else
1384887Schin 								{
1394887Schin 									next = 1;
1404887Schin 									v = lc->language->code;
1414887Schin 								}
1424887Schin 							}
1434887Schin 							break;
1444887Schin 						case 'l':
1454887Schin 							v = lc->language->code;
1464887Schin 							break;
1474887Schin 						case 't':
1484887Schin 							v = lc->territory->code;
1494887Schin 							break;
1504887Schin 						case 'c':
1514887Schin 							v = lc->charset->code;
1524887Schin 							break;
1534887Schin 						case 'C':
1544887Schin 						case_C:
1554887Schin 							if (!catalog)
1564887Schin 								last = 1;
1578462SApril.Chin@Sun.COM 							v = lc_categories[category].name;
1584887Schin 							break;
1594887Schin 						default:
1604887Schin 							*s++ = c;
1614887Schin 							continue;
1624887Schin 						}
1634887Schin 						if (v)
1644887Schin 							while (*v && s < e)
1654887Schin 								*s++ = *v++;
1664887Schin 					}
1674887Schin 					continue;
1684887Schin 				case '/':
1694887Schin 					if (last)
1704887Schin 						break;
1714887Schin 					if (category != AST_LC_MESSAGES && strneq(p, lc_messages, sizeof(lc_messages) - 1) && p[sizeof(lc_messages)-1] == '/')
1724887Schin 					{
1734887Schin 						p += sizeof(lc_messages) - 1;
1744887Schin 						goto case_C;
1754887Schin 					}
1764887Schin 					/*FALLTHROUGH*/
1774887Schin 				default:
1784887Schin 					if (s < e)
1794887Schin 						*s++ = c;
1804887Schin 					continue;
1814887Schin 				}
1824887Schin 				break;
1834887Schin 			}
1844887Schin 			if (s > file)
1854887Schin 				*s = 0;
1864887Schin 			else if (!catalog)
1874887Schin 				continue;
1884887Schin 			else
1894887Schin 				strncpy(file, catalog, elementsof(file));
1904887Schin 			if (ast.locale.set & AST_LC_find)
1914887Schin 				sfprintf(sfstderr, "locale find %s\n", file);
1924887Schin 			if (s = pathpath(path, file, "", (!catalog && category == AST_LC_MESSAGES) ? PATH_READ : (PATH_REGULAR|PATH_READ|PATH_ABSOLUTE)))
1934887Schin 			{
1944887Schin 				if (ast.locale.set & (AST_LC_find|AST_LC_setlocale))
1954887Schin 					sfprintf(sfstderr, "locale path %s\n", s);
1964887Schin 				errno = oerrno;
1974887Schin 				return s;
1984887Schin 			}
1994887Schin 		}
2004887Schin 	}
2014887Schin 	errno = oerrno;
2024887Schin 	return 0;
2034887Schin }
2044887Schin 
2054887Schin /*
2064887Schin  * allocate and read the binary message catalog ip
2074887Schin  * if ip==0 then space is allocated for mcput()
2084887Schin  * 0 returned on any error
2094887Schin  */
2104887Schin 
2114887Schin Mc_t*
mcopen(register Sfio_t * ip)2124887Schin mcopen(register Sfio_t* ip)
2134887Schin {
2144887Schin 	register Mc_t*		mc;
2154887Schin 	register char**		mp;
2164887Schin 	register char*		sp;
2174887Schin 	Vmalloc_t*		vm;
2184887Schin 	char*			rp;
2194887Schin 	int			i;
2204887Schin 	int			j;
2214887Schin 	int			oerrno;
2224887Schin 	size_t			n;
2234887Schin 	char			buf[MC_MAGIC_SIZE];
2244887Schin 
2254887Schin 	oerrno = errno;
2264887Schin 	if (ip)
2274887Schin 	{
2284887Schin 		/*
2294887Schin 		 * check the magic
2304887Schin 		 */
2314887Schin 
2324887Schin 		if (sfread(ip, buf, MC_MAGIC_SIZE) != MC_MAGIC_SIZE)
2334887Schin 		{
2344887Schin 			errno = oerrno;
2354887Schin 			return 0;
2364887Schin 		}
2374887Schin 		if (memcmp(buf, MC_MAGIC, MC_MAGIC_SIZE))
2384887Schin 			return 0;
2394887Schin 	}
2404887Schin 
2414887Schin 	/*
2424887Schin 	 * allocate the region
2434887Schin 	 */
2444887Schin 
2454887Schin 	if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(mc = vmnewof(vm, 0, Mc_t, 1, 0)))
2464887Schin 	{
2474887Schin 		errno = oerrno;
2484887Schin 		return 0;
2494887Schin 	}
2504887Schin 	mc->vm = vm;
2514887Schin 	mc->cvt = (iconv_t)(-1);
2524887Schin 	if (ip)
2534887Schin 	{
2544887Schin 		/*
2554887Schin 		 * read the translation record
2564887Schin 		 */
2574887Schin 
2584887Schin 		if (!(sp = sfgetr(ip, 0, 0)) || !(mc->translation = vmstrdup(vm, sp)))
2594887Schin 			goto bad;
2604887Schin 
2614887Schin 		/*
2624887Schin 		 * read the optional header records
2634887Schin 		 */
2644887Schin 
2654887Schin 		do
2664887Schin 		{
2674887Schin 			if (!(sp = sfgetr(ip, 0, 0)))
2684887Schin 				goto bad;
2694887Schin 		} while (*sp);
2704887Schin 
2714887Schin 		/*
2724887Schin 		 * get the component dimensions
2734887Schin 		 */
2744887Schin 
2754887Schin 		mc->nstrs = sfgetu(ip);
2764887Schin 		mc->nmsgs = sfgetu(ip);
2774887Schin 		mc->num = sfgetu(ip);
2784887Schin 		if (sfeof(ip))
2794887Schin 			goto bad;
2804887Schin 	}
2814887Schin 	else if (!(mc->translation = vmnewof(vm, 0, char, 1, 0)))
2824887Schin 		goto bad;
2834887Schin 
2844887Schin 	/*
2854887Schin 	 * allocate the remaining space
2864887Schin 	 */
2874887Schin 
2884887Schin 	if (!(mc->set = vmnewof(vm, 0, Mcset_t, mc->num + 1, 0)))
2894887Schin 		goto bad;
2904887Schin 	if (!ip)
2914887Schin 		return mc;
2924887Schin 	if (!(mp = vmnewof(vm, 0, char*, mc->nmsgs + mc->num + 1, 0)))
2934887Schin 		goto bad;
2944887Schin 	if (!(rp = sp = vmalloc(vm, mc->nstrs + 1)))
2954887Schin 		goto bad;
2964887Schin 
2974887Schin 	/*
2984887Schin 	 * get the set dimensions and initialize the msg pointers
2994887Schin 	 */
3004887Schin 
3014887Schin 	while (i = sfgetu(ip))
3024887Schin 	{
3034887Schin 		if (i > mc->num)
3044887Schin 			goto bad;
3054887Schin 		n = sfgetu(ip);
3064887Schin 		mc->set[i].num = n;
3074887Schin 		mc->set[i].msg = mp;
3084887Schin 		mp += n + 1;
3094887Schin 	}
3104887Schin 
3114887Schin 	/*
3124887Schin 	 * read the msg sizes and set up the msg pointers
3134887Schin 	 */
3144887Schin 
3154887Schin 	for (i = 1; i <= mc->num; i++)
3164887Schin 		for (j = 1; j <= mc->set[i].num; j++)
3174887Schin 			if (n = sfgetu(ip))
3184887Schin 			{
3194887Schin 				mc->set[i].msg[j] = sp;
3204887Schin 				sp += n;
3214887Schin 			}
3224887Schin 
3234887Schin 	/*
3244887Schin 	 * read the string table
3254887Schin 	 */
3264887Schin 
3274887Schin 	if (sfread(ip, rp, mc->nstrs) != mc->nstrs || sfgetc(ip) != EOF)
3284887Schin 		goto bad;
3294887Schin 	if (!(mc->tmp = sfstropen()))
3304887Schin 		goto bad;
3314887Schin 	mc->cvt = iconv_open("", "utf");
3324887Schin 	errno = oerrno;
3334887Schin 	return mc;
3344887Schin  bad:
3354887Schin 	vmclose(vm);
3364887Schin 	errno = oerrno;
3374887Schin 	return 0;
3384887Schin }
3394887Schin 
3404887Schin /*
3414887Schin  * return the <set,num> message in mc
3424887Schin  * msg returned on error
3434887Schin  * utf message text converted to ucs
3444887Schin  */
3454887Schin 
3464887Schin char*
mcget(register Mc_t * mc,int set,int num,const char * msg)3474887Schin mcget(register Mc_t* mc, int set, int num, const char* msg)
3484887Schin {
3494887Schin 	char*		s;
3504887Schin 	size_t		n;
3514887Schin 	int		p;
3524887Schin 
3534887Schin 	if (!mc || set < 0 || set > mc->num || num < 1 || num > mc->set[set].num || !(s = mc->set[set].msg[num]))
3544887Schin 		return (char*)msg;
3554887Schin 	if (mc->cvt == (iconv_t)(-1))
3564887Schin 		return s;
3574887Schin 	if ((p = sfstrtell(mc->tmp)) > sfstrsize(mc->tmp) / 2)
3584887Schin 	{
3594887Schin 		p = 0;
3604887Schin 		sfstrseek(mc->tmp, p, SEEK_SET);
3614887Schin 	}
3624887Schin 	n = strlen(s) + 1;
3634887Schin 	iconv_write(mc->cvt, mc->tmp, &s, &n, NiL);
3644887Schin 	return sfstrbase(mc->tmp) + p;
3654887Schin }
3664887Schin 
3674887Schin /*
3684887Schin  * set message <set,num> to msg
3694887Schin  * msg==0 deletes the message
3704887Schin  * the message and set counts are adjusted
3714887Schin  * 0 returned on success, -1 otherwise
3724887Schin  */
3734887Schin 
3744887Schin int
mcput(register Mc_t * mc,int set,int num,const char * msg)3754887Schin mcput(register Mc_t* mc, int set, int num, const char* msg)
3764887Schin {
3774887Schin 	register int		i;
3784887Schin 	register char*		s;
3794887Schin 	register Mcset_t*	sp;
3804887Schin 	register char**		mp;
3814887Schin 
3824887Schin 	/*
3834887Schin 	 * validate the arguments
3844887Schin 	 */
3854887Schin 
3864887Schin 	if (!mc || set > MC_SET_MAX || num > MC_NUM_MAX)
3874887Schin 		return -1;
3884887Schin 
3894887Schin 	/*
3904887Schin 	 * deletions don't kick in allocations (duh)
3914887Schin 	 */
3924887Schin 
3934887Schin 	if (!msg)
3944887Schin 	{
3954887Schin 		if (set <= mc->num && num <= mc->set[set].num && (s = mc->set[set].msg[num]))
3964887Schin 		{
3974887Schin 			/*
3984887Schin 			 * decrease the string table size
3994887Schin 			 */
4004887Schin 
4014887Schin 			mc->set[set].msg[num] = 0;
4024887Schin 			mc->nstrs -= strlen(s) + 1;
4034887Schin 			if (mc->set[set].num == num)
4044887Schin 			{
4054887Schin 				/*
4064887Schin 				 * decrease the max msg num
4074887Schin 				 */
4084887Schin 
4094887Schin 				mp = mc->set[set].msg + num;
4104887Schin 				while (num && !mp[--num]);
4114887Schin 				mc->nmsgs -= mc->set[set].num - num;
4124887Schin 				if (!(mc->set[set].num = num) && mc->num == set)
4134887Schin 				{
4144887Schin 					/*
4154887Schin 					 * decrease the max set num
4164887Schin 					 */
4174887Schin 
4184887Schin 					while (num && !mc->set[--num].num);
4194887Schin 					mc->num = num;
4204887Schin 				}
4214887Schin 			}
4224887Schin 		}
4234887Schin 		return 0;
4244887Schin 	}
4254887Schin 
4264887Schin 	/*
4274887Schin 	 * keep track of the highest set and allocate if necessary
4284887Schin 	 */
4294887Schin 
4304887Schin 	if (set > mc->num)
4314887Schin 	{
4324887Schin 		if (set > mc->gen)
4334887Schin 		{
4344887Schin 			i = MC_SET_MAX;
4354887Schin 			if (!(sp = vmnewof(mc->vm, 0, Mcset_t, i + 1, 0)))
4364887Schin 				return -1;
4374887Schin 			mc->gen = i;
4384887Schin 			for (i = 1; i <= mc->num; i++)
4394887Schin 				sp[i] = mc->set[i];
4404887Schin 			mc->set = sp;
4414887Schin 		}
4424887Schin 		mc->num = set;
4434887Schin 	}
4444887Schin 	sp = mc->set + set;
4454887Schin 
4464887Schin 	/*
4474887Schin 	 * keep track of the highest msg and allocate if necessary
4484887Schin 	 */
4494887Schin 
4504887Schin 	if (num > sp->num)
4514887Schin 	{
4524887Schin 		if (num > sp->gen)
4534887Schin 		{
4544887Schin 			if (!mc->gen)
4554887Schin 			{
4564887Schin 				i = (MC_NUM_MAX + 1) / 32;
4574887Schin 				if (i <= num)
4584887Schin 					i = 2 * num;
4594887Schin 				if (i > MC_NUM_MAX)
4604887Schin 					i = MC_NUM_MAX;
4614887Schin 				if (!(mp = vmnewof(mc->vm, 0, char*, i + 1, 0)))
4624887Schin 					return -1;
4634887Schin 				mc->gen = i;
4644887Schin 				sp->msg = mp;
4654887Schin 				for (i = 1; i <= sp->num; i++)
4664887Schin 					mp[i] = sp->msg[i];
4674887Schin 			}
4684887Schin 			else
4694887Schin 			{
4704887Schin 				i = 2 * mc->gen;
4714887Schin 				if (i > MC_NUM_MAX)
4724887Schin 					i = MC_NUM_MAX;
4734887Schin 				if (!(mp = vmnewof(mc->vm, sp->msg, char*, i + 1, 0)))
4744887Schin 					return -1;
4754887Schin 				sp->gen = i;
4764887Schin 				sp->msg = mp;
4774887Schin 			}
4784887Schin 		}
4794887Schin 		mc->nmsgs += num - sp->num;
4804887Schin 		sp->num = num;
4814887Schin 	}
4824887Schin 
4834887Schin 	/*
4844887Schin 	 * decrease the string table size
4854887Schin 	 */
4864887Schin 
4874887Schin 	if (s = sp->msg[num])
4884887Schin 	{
4894887Schin 		/*
4904887Schin 		 * no-op if no change
4914887Schin 		 */
4924887Schin 
4934887Schin 		if (streq(s, msg))
4944887Schin 			return 0;
4954887Schin 		mc->nstrs -= strlen(s) + 1;
4964887Schin 	}
4974887Schin 
4984887Schin 	/*
4994887Schin 	 * allocate, add and adjust the string table size
5004887Schin 	 */
5014887Schin 
5024887Schin 	if (!(s = vmstrdup(mc->vm, msg)))
5034887Schin 		return -1;
5044887Schin 	sp->msg[num] = s;
5054887Schin 	mc->nstrs += strlen(s) + 1;
5064887Schin 	return 0;
5074887Schin }
5084887Schin 
5094887Schin /*
5104887Schin  * dump message catalog mc to op
5114887Schin  * 0 returned on success, -1 otherwise
5124887Schin  */
5134887Schin 
5144887Schin int
mcdump(register Mc_t * mc,register Sfio_t * op)5154887Schin mcdump(register Mc_t* mc, register Sfio_t* op)
5164887Schin {
5174887Schin 	register int		i;
5184887Schin 	register int		j;
5194887Schin 	register int		n;
5204887Schin 	register char*		s;
5214887Schin 	register Mcset_t*	sp;
5224887Schin 
5234887Schin 	/*
5244887Schin 	 * write the magic
5254887Schin 	 */
5264887Schin 
5274887Schin 	if (sfwrite(op, MC_MAGIC, MC_MAGIC_SIZE) != MC_MAGIC_SIZE)
5284887Schin 		return -1;
5294887Schin 
5304887Schin 	/*
5314887Schin 	 * write the translation record
5324887Schin 	 */
5334887Schin 
5344887Schin 	sfputr(op, mc->translation, 0);
5354887Schin 
5364887Schin 	/* optional header records here */
5374887Schin 
5384887Schin 	/*
5394887Schin 	 * end of optional header records
5404887Schin 	 */
5414887Schin 
5424887Schin 	sfputu(op, 0);
5434887Schin 
5444887Schin 	/*
5454887Schin 	 * write the global dimensions
5464887Schin 	 */
5474887Schin 
5484887Schin 	sfputu(op, mc->nstrs);
5494887Schin 	sfputu(op, mc->nmsgs);
5504887Schin 	sfputu(op, mc->num);
5514887Schin 
5524887Schin 	/*
5534887Schin 	 * write the set dimensions
5544887Schin 	 */
5554887Schin 
5564887Schin 	for (i = 1; i <= mc->num; i++)
5574887Schin 		if (mc->set[i].num)
5584887Schin 		{
5594887Schin 			sfputu(op, i);
5604887Schin 			sfputu(op, mc->set[i].num);
5614887Schin 		}
5624887Schin 	sfputu(op, 0);
5634887Schin 
5644887Schin 	/*
5654887Schin 	 * write the message sizes
5664887Schin 	 */
5674887Schin 
5684887Schin 	for (i = 1; i <= mc->num; i++)
5694887Schin 		if (mc->set[i].num)
5704887Schin 		{
5714887Schin 			sp = mc->set + i;
5724887Schin 			for (j = 1; j <= sp->num; j++)
5734887Schin 			{
5744887Schin 				n = (s = sp->msg[j]) ? (strlen(s) + 1) : 0;
5754887Schin 				sfputu(op, n);
5764887Schin 			}
5774887Schin 		}
5784887Schin 
5794887Schin 	/*
5804887Schin 	 * write the string table
5814887Schin 	 */
5824887Schin 
5834887Schin 	for (i = 1; i <= mc->num; i++)
5844887Schin 		if (mc->set[i].num)
5854887Schin 		{
5864887Schin 			sp = mc->set + i;
5874887Schin 			for (j = 1; j <= sp->num; j++)
5884887Schin 				if (s = sp->msg[j])
5894887Schin 					sfputr(op, s, 0);
5904887Schin 		}
5914887Schin 
5924887Schin 	/*
5934887Schin 	 * sync and return
5944887Schin 	 */
5954887Schin 
5964887Schin 	return sfsync(op);
5974887Schin }
5984887Schin 
5994887Schin /*
6004887Schin  * parse <set,msg> number from s
6014887Schin  * e!=0 is set to the next char after the parse
6024887Schin  * set!=0 is set to message set number
6034887Schin  * msg!=0 is set to message number
6044887Schin  * the message set number is returned
6054887Schin  *
6064887Schin  * the base 36 hash gives reasonable values for these:
6074887Schin  *
6084887Schin  *	"ast" : ((((36#a^36#s^36#t)-9)&63)+1) = 3
6094887Schin  *	"gnu" : ((((36#g^36#n^36#u)-9)&63)+1) = 17
6104887Schin  *	"sgi" : ((((36#s^36#g^36#i)-9)&63)+1) = 22
6114887Schin  *	"sun" : ((((36#s^36#u^36#n)-9)&63)+1) = 13
6124887Schin  */
6134887Schin 
6144887Schin int
mcindex(register const char * s,char ** e,int * set,int * msg)6154887Schin mcindex(register const char* s, char** e, int* set, int* msg)
6164887Schin {
6174887Schin 	register int		c;
6184887Schin 	register int		m;
6194887Schin 	register int		n;
6204887Schin 	register int		r;
6214887Schin 	register unsigned char*	cv;
6224887Schin 	char*			t;
6234887Schin 
6244887Schin 	m = 0;
6254887Schin 	n = strtol(s, &t, 0);
6264887Schin 	if (t == (char*)s)
6274887Schin 	{
6284887Schin 		SFCVINIT();
6294887Schin 		cv = _Sfcv36;
6304887Schin 		for (n = m = 0; (c = cv[*s]) < 36; s++)
6314887Schin 		{
6324887Schin 			m++;
6334887Schin 			n ^= c;
6344887Schin 		}
6354887Schin 		m = (m <= 3) ? 63 : ((1 << (m + 3)) - 1);
6364887Schin 		n = ((n - 9) & m) + 1;
6374887Schin 	}
6384887Schin 	else
6394887Schin 		s = (const char*)t;
6404887Schin 	r = n;
6414887Schin 	if (*s)
6424887Schin 		m = strtol(s + 1, e, 0);
6434887Schin 	else
6444887Schin 	{
6454887Schin 		if (e)
6464887Schin 			*e = (char*)s;
6474887Schin 		if (m)
6484887Schin 			m = 0;
6494887Schin 		else
6504887Schin 		{
6514887Schin 			m = n;
6524887Schin 			n = 1;
6534887Schin 		}
6544887Schin 	}
6554887Schin 	if (set)
6564887Schin 		*set = n;
6574887Schin 	if (msg)
6584887Schin 		*msg = m;
6594887Schin 	return r;
6604887Schin }
6614887Schin 
6624887Schin /*
6634887Schin  * close the message catalog mc
6644887Schin  */
6654887Schin 
6664887Schin int
mcclose(register Mc_t * mc)6674887Schin mcclose(register Mc_t* mc)
6684887Schin {
6694887Schin 	if (!mc)
6704887Schin 		return -1;
6714887Schin 	if (mc->tmp)
6724887Schin 		sfclose(mc->tmp);
6734887Schin 	if (mc->cvt != (iconv_t)(-1))
6744887Schin 		iconv_close(mc->cvt);
6754887Schin 	vmclose(mc->vm);
6764887Schin 	return 0;
6774887Schin }
678