Blame src/lib/libast/port/mc.c

Packit Service a8c26c
/***********************************************************************
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*               This software is part of the ast package               *
Packit Service a8c26c
*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
Packit Service a8c26c
*                      and is licensed under the                       *
Packit Service a8c26c
*                 Eclipse Public License, Version 1.0                  *
Packit Service a8c26c
*                    by AT&T Intellectual Property                     *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                A copy of the License is available at                 *
Packit Service a8c26c
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit Service a8c26c
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*              Information and Software Systems Research               *
Packit Service a8c26c
*                            AT&T Research                             *
Packit Service a8c26c
*                           Florham Park NJ                            *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                 Glenn Fowler <gsf@research.att.com>                  *
Packit Service a8c26c
*                  David Korn <dgk@research.att.com>                   *
Packit Service a8c26c
*                   Phong Vo <kpv@research.att.com>                    *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
***********************************************************************/
Packit Service a8c26c
#pragma prototyped
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * Glenn Fowler
Packit Service a8c26c
 * AT&T Research
Packit Service a8c26c
 *
Packit Service a8c26c
 * machine independent binary message catalog implementation
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
#include "sfhdr.h"
Packit Service a8c26c
#include "lclib.h"
Packit Service a8c26c
Packit Service a8c26c
#include <iconv.h>
Packit Service a8c26c
Packit Service a8c26c
#define _MC_PRIVATE_ \
Packit Service a8c26c
	size_t		nstrs; \
Packit Service a8c26c
	size_t		nmsgs; \
Packit Service a8c26c
	iconv_t		cvt; \
Packit Service a8c26c
	Sfio_t*		tmp; \
Packit Service a8c26c
	Vmalloc_t*	vm;
Packit Service a8c26c
	
Packit Service a8c26c
#include <vmalloc.h>
Packit Service a8c26c
#include <error.h>
Packit Service a8c26c
#include <mc.h>
Packit Service a8c26c
#include <nl_types.h>
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * find the binary message catalog path for <locale,catalog>
Packit Service a8c26c
 * result placed in path of size PATH_MAX
Packit Service a8c26c
 * pointer to path returned
Packit Service a8c26c
 * catalog==0 tests for category directory or file
Packit Service a8c26c
 * nls!=0 enables NLSPATH+LANG hack (not implemented yet)
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
char*
Packit Service a8c26c
mcfind(const char* locale, const char* catalog, int category, int nls, char* path, size_t size)
Packit Service a8c26c
{
Packit Service a8c26c
	register int		c;
Packit Service a8c26c
	register char*		s;
Packit Service a8c26c
	register char*		e;
Packit Service a8c26c
	register char*		p;
Packit Service a8c26c
	register const char*	v;
Packit Service a8c26c
	int			i;
Packit Service a8c26c
	int			first;
Packit Service a8c26c
	int			next;
Packit Service a8c26c
	int			last;
Packit Service a8c26c
	int			oerrno;
Packit Service a8c26c
	Lc_t*			lc;
Packit Service a8c26c
	char			file[PATH_MAX];
Packit Service a8c26c
	char*			paths[5];
Packit Service a8c26c
Packit Service a8c26c
	static char		lc_messages[] = "LC_MESSAGES";
Packit Service a8c26c
Packit Service a8c26c
	if ((category = lcindex(category, 1)) < 0)
Packit Service a8c26c
		return 0;
Packit Service a8c26c
	if (!(lc = locale ? lcmake(locale) : locales[category]))
Packit Service a8c26c
		return 0;
Packit Service a8c26c
	oerrno = errno;
Packit Service a8c26c
	if (catalog && *catalog == '/')
Packit Service a8c26c
	{
Packit Service a8c26c
		i = eaccess(catalog, R_OK);
Packit Service a8c26c
		errno = oerrno;
Packit Service a8c26c
		if (i)
Packit Service a8c26c
			return 0;
Packit Service a8c26c
		strlcpy(path, catalog, size);
Packit Service a8c26c
		return path;
Packit Service a8c26c
	}
Packit Service a8c26c
	i = 0;
Packit Service a8c26c
	if ((p = getenv("NLSPATH")) && *p)
Packit Service a8c26c
		paths[i++] = p;
Packit Service a8c26c
	paths[i++] = "share/lib/locale/%l/%C/%N";
Packit Service a8c26c
	paths[i++] = "share/locale/%l/%C/%N";
Packit Service a8c26c
	paths[i++] = "lib/locale/%l/%C/%N";
Packit Service a8c26c
	paths[i] = 0;
Packit Service a8c26c
	next = 1;
Packit Service a8c26c
	for (i = 0; p = paths[i]; i += next)
Packit Service a8c26c
	{
Packit Service a8c26c
		first = 1;
Packit Service a8c26c
		last = 0;
Packit Service a8c26c
		e = &file[elementsof(file) - 1];
Packit Service a8c26c
		while (*p)
Packit Service a8c26c
		{
Packit Service a8c26c
			s = file;
Packit Service a8c26c
			for (;;)
Packit Service a8c26c
			{
Packit Service a8c26c
				switch (c = *p++)
Packit Service a8c26c
				{
Packit Service a8c26c
				case 0:
Packit Service a8c26c
					p--;
Packit Service a8c26c
					break;
Packit Service a8c26c
				case ':':
Packit Service a8c26c
					break;
Packit Service a8c26c
				case '%':
Packit Service a8c26c
					if (s < e)
Packit Service a8c26c
					{
Packit Service a8c26c
						switch (c = *p++)
Packit Service a8c26c
						{
Packit Service a8c26c
						case 0:
Packit Service a8c26c
							p--;
Packit Service a8c26c
							continue;
Packit Service a8c26c
						case 'N':
Packit Service a8c26c
							v = catalog;
Packit Service a8c26c
							break;
Packit Service a8c26c
						case 'L':
Packit Service a8c26c
							if (first)
Packit Service a8c26c
							{
Packit Service a8c26c
								first = 0;
Packit Service a8c26c
								if (next)
Packit Service a8c26c
								{
Packit Service a8c26c
									v = lc->code;
Packit Service a8c26c
									if (lc->code != lc->language->code)
Packit Service a8c26c
										next = 0;
Packit Service a8c26c
								}
Packit Service a8c26c
								else
Packit Service a8c26c
								{
Packit Service a8c26c
									next = 1;
Packit Service a8c26c
									v = lc->language->code;
Packit Service a8c26c
								}
Packit Service a8c26c
							}
Packit Service a8c26c
							break;
Packit Service a8c26c
						case 'l':
Packit Service a8c26c
							v = lc->language->code;
Packit Service a8c26c
							break;
Packit Service a8c26c
						case 't':
Packit Service a8c26c
							v = lc->territory->code;
Packit Service a8c26c
							break;
Packit Service a8c26c
						case 'c':
Packit Service a8c26c
							v = lc->charset->code;
Packit Service a8c26c
							break;
Packit Service a8c26c
						case 'C':
Packit Service a8c26c
						case_C:
Packit Service a8c26c
							if (!catalog)
Packit Service a8c26c
								last = 1;
Packit Service a8c26c
							v = lc_categories[category].name;
Packit Service a8c26c
							break;
Packit Service a8c26c
						default:
Packit Service a8c26c
							*s++ = c;
Packit Service a8c26c
							continue;
Packit Service a8c26c
						}
Packit Service a8c26c
						if (v)
Packit Service a8c26c
							while (*v && s < e)
Packit Service a8c26c
								*s++ = *v++;
Packit Service a8c26c
					}
Packit Service a8c26c
					continue;
Packit Service a8c26c
				case '/':
Packit Service a8c26c
					if (last)
Packit Service a8c26c
						break;
Packit Service a8c26c
					if (category != AST_LC_MESSAGES && strneq(p, lc_messages, sizeof(lc_messages) - 1) && p[sizeof(lc_messages)-1] == '/')
Packit Service a8c26c
					{
Packit Service a8c26c
						p += sizeof(lc_messages) - 1;
Packit Service a8c26c
						goto case_C;
Packit Service a8c26c
					}
Packit Service a8c26c
					/*FALLTHROUGH*/
Packit Service a8c26c
				default:
Packit Service a8c26c
					if (s < e)
Packit Service a8c26c
						*s++ = c;
Packit Service a8c26c
					continue;
Packit Service a8c26c
				}
Packit Service a8c26c
				break;
Packit Service a8c26c
			}
Packit Service a8c26c
			if (s > file)
Packit Service a8c26c
				*s = 0;
Packit Service a8c26c
			else if (!catalog)
Packit Service a8c26c
				continue;
Packit Service a8c26c
			else
Packit Service a8c26c
				strlcpy(file, catalog, elementsof(file));
Packit Service a8c26c
			if (ast.locale.set & AST_LC_find)
Packit Service a8c26c
				sfprintf(sfstderr, "locale find %s\n", file);
Packit Service a8c26c
			if (s = pathpath(file, "", (!catalog && category == AST_LC_MESSAGES) ? PATH_READ : (PATH_REGULAR|PATH_READ|PATH_ABSOLUTE), path, size))
Packit Service a8c26c
			{
Packit Service a8c26c
				if (ast.locale.set & (AST_LC_find|AST_LC_setlocale))
Packit Service a8c26c
					sfprintf(sfstderr, "locale path %s\n", s);
Packit Service a8c26c
				errno = oerrno;
Packit Service a8c26c
				return s;
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
	}
Packit Service a8c26c
	errno = oerrno;
Packit Service a8c26c
	return 0;
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * allocate and read the binary message catalog ip
Packit Service a8c26c
 * if ip==0 then space is allocated for mcput()
Packit Service a8c26c
 * 0 returned on any error
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
Mc_t*
Packit Service a8c26c
mcopen(register Sfio_t* ip)
Packit Service a8c26c
{
Packit Service a8c26c
	register Mc_t*		mc;
Packit Service a8c26c
	register char**		mp;
Packit Service a8c26c
	register char*		sp;
Packit Service a8c26c
	Vmalloc_t*		vm;
Packit Service a8c26c
	char*			rp;
Packit Service a8c26c
	int			i;
Packit Service a8c26c
	int			j;
Packit Service a8c26c
	int			oerrno;
Packit Service a8c26c
	size_t			n;
Packit Service a8c26c
	char			buf[MC_MAGIC_SIZE];
Packit Service a8c26c
Packit Service a8c26c
	oerrno = errno;
Packit Service a8c26c
	if (ip)
Packit Service a8c26c
	{
Packit Service a8c26c
		/*
Packit Service a8c26c
		 * check the magic
Packit Service a8c26c
		 */
Packit Service a8c26c
Packit Service a8c26c
		if (sfread(ip, buf, MC_MAGIC_SIZE) != MC_MAGIC_SIZE)
Packit Service a8c26c
		{
Packit Service a8c26c
			errno = oerrno;
Packit Service a8c26c
			return 0;
Packit Service a8c26c
		}
Packit Service a8c26c
		if (memcmp(buf, MC_MAGIC, MC_MAGIC_SIZE))
Packit Service a8c26c
			return 0;
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * allocate the region
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(mc = vmnewof(vm, 0, Mc_t, 1, 0)))
Packit Service a8c26c
	{
Packit Service a8c26c
		errno = oerrno;
Packit Service a8c26c
		return 0;
Packit Service a8c26c
	}
Packit Service a8c26c
	mc->vm = vm;
Packit Service a8c26c
	mc->cvt = (iconv_t)(-1);
Packit Service a8c26c
	if (ip)
Packit Service a8c26c
	{
Packit Service a8c26c
		/*
Packit Service a8c26c
		 * read the translation record
Packit Service a8c26c
		 */
Packit Service a8c26c
Packit Service a8c26c
		if (!(sp = sfgetr(ip, 0, 0)) || !(mc->translation = vmstrdup(vm, sp)))
Packit Service a8c26c
			goto bad;
Packit Service a8c26c
Packit Service a8c26c
		/*
Packit Service a8c26c
		 * read the optional header records
Packit Service a8c26c
		 */
Packit Service a8c26c
Packit Service a8c26c
		do
Packit Service a8c26c
		{
Packit Service a8c26c
			if (!(sp = sfgetr(ip, 0, 0)))
Packit Service a8c26c
				goto bad;
Packit Service a8c26c
		} while (*sp);
Packit Service a8c26c
Packit Service a8c26c
		/*
Packit Service a8c26c
		 * get the component dimensions
Packit Service a8c26c
		 */
Packit Service a8c26c
Packit Service a8c26c
		mc->nstrs = sfgetu(ip);
Packit Service a8c26c
		mc->nmsgs = sfgetu(ip);
Packit Service a8c26c
		mc->num = sfgetu(ip);
Packit Service a8c26c
		if (sfeof(ip))
Packit Service a8c26c
			goto bad;
Packit Service a8c26c
	}
Packit Service a8c26c
	else if (!(mc->translation = vmnewof(vm, 0, char, 1, 0)))
Packit Service a8c26c
		goto bad;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * allocate the remaining space
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (!(mc->set = vmnewof(vm, 0, Mcset_t, mc->num + 1, 0)))
Packit Service a8c26c
		goto bad;
Packit Service a8c26c
	if (!ip)
Packit Service a8c26c
		return mc;
Packit Service a8c26c
	if (!(mp = vmnewof(vm, 0, char*, mc->nmsgs + mc->num + 1, 0)))
Packit Service a8c26c
		goto bad;
Packit Service a8c26c
	if (!(rp = sp = vmalloc(vm, mc->nstrs + 1)))
Packit Service a8c26c
		goto bad;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * get the set dimensions and initialize the msg pointers
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	while (i = sfgetu(ip))
Packit Service a8c26c
	{
Packit Service a8c26c
		if (i > mc->num)
Packit Service a8c26c
			goto bad;
Packit Service a8c26c
		n = sfgetu(ip);
Packit Service a8c26c
		mc->set[i].num = n;
Packit Service a8c26c
		mc->set[i].msg = mp;
Packit Service a8c26c
		mp += n + 1;
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * read the msg sizes and set up the msg pointers
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	for (i = 1; i <= mc->num; i++)
Packit Service a8c26c
		for (j = 1; j <= mc->set[i].num; j++)
Packit Service a8c26c
			if (n = sfgetu(ip))
Packit Service a8c26c
			{
Packit Service a8c26c
				mc->set[i].msg[j] = sp;
Packit Service a8c26c
				sp += n;
Packit Service a8c26c
			}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * read the string table
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (sfread(ip, rp, mc->nstrs) != mc->nstrs || sfgetc(ip) != EOF)
Packit Service a8c26c
		goto bad;
Packit Service a8c26c
	if (!(mc->tmp = sfstropen()))
Packit Service a8c26c
		goto bad;
Packit Service a8c26c
	mc->cvt = iconv_open("", "utf");
Packit Service a8c26c
	errno = oerrno;
Packit Service a8c26c
	return mc;
Packit Service a8c26c
 bad:
Packit Service a8c26c
	vmclose(vm);
Packit Service a8c26c
	errno = oerrno;
Packit Service a8c26c
	return 0;
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * return the <set,num> message in mc
Packit Service a8c26c
 * msg returned on error
Packit Service a8c26c
 * utf message text converted to ucs
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
char*
Packit Service a8c26c
mcget(register Mc_t* mc, int set, int num, const char* msg)
Packit Service a8c26c
{
Packit Service a8c26c
	char*		s;
Packit Service a8c26c
	size_t		n;
Packit Service a8c26c
	int		p;
Packit Service a8c26c
Packit Service a8c26c
	if (!mc || set < 0 || set > mc->num || num < 1 || num > mc->set[set].num || !(s = mc->set[set].msg[num]))
Packit Service a8c26c
		return (char*)msg;
Packit Service a8c26c
	if (mc->cvt == (iconv_t)(-1))
Packit Service a8c26c
		return s;
Packit Service a8c26c
	if ((p = sfstrtell(mc->tmp)) > sfstrsize(mc->tmp) / 2)
Packit Service a8c26c
	{
Packit Service a8c26c
		p = 0;
Packit Service a8c26c
		sfstrseek(mc->tmp, p, SEEK_SET);
Packit Service a8c26c
	}
Packit Service a8c26c
	n = strlen(s) + 1;
Packit Service a8c26c
	iconv_write(mc->cvt, mc->tmp, &s, &n, NiL);
Packit Service a8c26c
	return sfstrbase(mc->tmp) + p;
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * set message <set,num> to msg
Packit Service a8c26c
 * msg==0 deletes the message
Packit Service a8c26c
 * the message and set counts are adjusted
Packit Service a8c26c
 * 0 returned on success, -1 otherwise
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
int
Packit Service a8c26c
mcput(register Mc_t* mc, int set, int num, const char* msg)
Packit Service a8c26c
{
Packit Service a8c26c
	register int		i;
Packit Service a8c26c
	register char*		s;
Packit Service a8c26c
	register Mcset_t*	sp;
Packit Service a8c26c
	register char**		mp;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * validate the arguments
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (!mc || set > MC_SET_MAX || num > MC_NUM_MAX)
Packit Service a8c26c
		return -1;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * deletions don't kick in allocations (duh)
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (!msg)
Packit Service a8c26c
	{
Packit Service a8c26c
		if (set <= mc->num && num <= mc->set[set].num && (s = mc->set[set].msg[num]))
Packit Service a8c26c
		{
Packit Service a8c26c
			/*
Packit Service a8c26c
			 * decrease the string table size
Packit Service a8c26c
			 */
Packit Service a8c26c
Packit Service a8c26c
			mc->set[set].msg[num] = 0;
Packit Service a8c26c
			mc->nstrs -= strlen(s) + 1;
Packit Service a8c26c
			if (mc->set[set].num == num)
Packit Service a8c26c
			{
Packit Service a8c26c
				/*
Packit Service a8c26c
				 * decrease the max msg num
Packit Service a8c26c
				 */
Packit Service a8c26c
Packit Service a8c26c
				mp = mc->set[set].msg + num;
Packit Service a8c26c
				while (num && !mp[--num]);
Packit Service a8c26c
				mc->nmsgs -= mc->set[set].num - num;
Packit Service a8c26c
				if (!(mc->set[set].num = num) && mc->num == set)
Packit Service a8c26c
				{
Packit Service a8c26c
					/*
Packit Service a8c26c
					 * decrease the max set num
Packit Service a8c26c
					 */
Packit Service a8c26c
Packit Service a8c26c
					while (num && !mc->set[--num].num);
Packit Service a8c26c
					mc->num = num;
Packit Service a8c26c
				}
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
		return 0;
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * keep track of the highest set and allocate if necessary
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (set > mc->num)
Packit Service a8c26c
	{
Packit Service a8c26c
		if (set > mc->gen)
Packit Service a8c26c
		{
Packit Service a8c26c
			i = MC_SET_MAX;
Packit Service a8c26c
			if (!(sp = vmnewof(mc->vm, 0, Mcset_t, i + 1, 0)))
Packit Service a8c26c
				return -1;
Packit Service a8c26c
			mc->gen = i;
Packit Service a8c26c
			for (i = 1; i <= mc->num; i++)
Packit Service a8c26c
				sp[i] = mc->set[i];
Packit Service a8c26c
			mc->set = sp;
Packit Service a8c26c
		}
Packit Service a8c26c
		mc->num = set;
Packit Service a8c26c
	}
Packit Service a8c26c
	sp = mc->set + set;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * keep track of the highest msg and allocate if necessary
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (num > sp->num)
Packit Service a8c26c
	{
Packit Service a8c26c
		if (num > sp->gen)
Packit Service a8c26c
		{
Packit Service a8c26c
			if (!mc->gen)
Packit Service a8c26c
			{
Packit Service a8c26c
				i = (MC_NUM_MAX + 1) / 32;
Packit Service a8c26c
				if (i <= num)
Packit Service a8c26c
					i = 2 * num;
Packit Service a8c26c
				if (i > MC_NUM_MAX)
Packit Service a8c26c
					i = MC_NUM_MAX;
Packit Service a8c26c
				if (!(mp = vmnewof(mc->vm, 0, char*, i + 1, 0)))
Packit Service a8c26c
					return -1;
Packit Service a8c26c
				mc->gen = i;
Packit Service a8c26c
				sp->msg = mp;
Packit Service a8c26c
				for (i = 1; i <= sp->num; i++)
Packit Service a8c26c
					mp[i] = sp->msg[i];
Packit Service a8c26c
			}
Packit Service a8c26c
			else
Packit Service a8c26c
			{
Packit Service a8c26c
				i = 2 * mc->gen;
Packit Service a8c26c
				if (i > MC_NUM_MAX)
Packit Service a8c26c
					i = MC_NUM_MAX;
Packit Service a8c26c
				if (!(mp = vmnewof(mc->vm, sp->msg, char*, i + 1, 0)))
Packit Service a8c26c
					return -1;
Packit Service a8c26c
				sp->gen = i;
Packit Service a8c26c
				sp->msg = mp;
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
		mc->nmsgs += num - sp->num;
Packit Service a8c26c
		sp->num = num;
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * decrease the string table size
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (s = sp->msg[num])
Packit Service a8c26c
	{
Packit Service a8c26c
		/*
Packit Service a8c26c
		 * no-op if no change
Packit Service a8c26c
		 */
Packit Service a8c26c
Packit Service a8c26c
		if (streq(s, msg))
Packit Service a8c26c
			return 0;
Packit Service a8c26c
		mc->nstrs -= strlen(s) + 1;
Packit Service a8c26c
	}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * allocate, add and adjust the string table size
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	if (!(s = vmstrdup(mc->vm, msg)))
Packit Service a8c26c
		return -1;
Packit Service a8c26c
	sp->msg[num] = s;
Packit Service a8c26c
	mc->nstrs += strlen(s) + 1;
Packit Service a8c26c
	return 0;
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * dump message catalog mc to op
Packit Service a8c26c
 * 0 returned on success, -1 otherwise
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
int
Packit Service a8c26c
mcdump(register Mc_t* mc, register Sfio_t* op)
Packit Service a8c26c
{
Packit Service a8c26c
	register int		i;
Packit Service a8c26c
	register int		j;
Packit Service a8c26c
	register int		n;
Packit Service a8c26c
	register char*		s;
Packit Service a8c26c
	register Mcset_t*	sp;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * write the magic
Packit Service a8c26c
	 */
Packit Service a8c26c
	
Packit Service a8c26c
	if (sfwrite(op, MC_MAGIC, MC_MAGIC_SIZE) != MC_MAGIC_SIZE)
Packit Service a8c26c
		return -1;
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * write the translation record
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	sfputr(op, mc->translation, 0);
Packit Service a8c26c
Packit Service a8c26c
	/* optional header records here */
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * end of optional header records
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	sfputu(op, 0);
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * write the global dimensions
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	sfputu(op, mc->nstrs);
Packit Service a8c26c
	sfputu(op, mc->nmsgs);
Packit Service a8c26c
	sfputu(op, mc->num);
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * write the set dimensions
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	for (i = 1; i <= mc->num; i++)
Packit Service a8c26c
		if (mc->set[i].num)
Packit Service a8c26c
		{
Packit Service a8c26c
			sfputu(op, i);
Packit Service a8c26c
			sfputu(op, mc->set[i].num);
Packit Service a8c26c
		}
Packit Service a8c26c
	sfputu(op, 0);
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * write the message sizes
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	for (i = 1; i <= mc->num; i++)
Packit Service a8c26c
		if (mc->set[i].num)
Packit Service a8c26c
		{
Packit Service a8c26c
			sp = mc->set + i;
Packit Service a8c26c
			for (j = 1; j <= sp->num; j++)
Packit Service a8c26c
			{
Packit Service a8c26c
				n = (s = sp->msg[j]) ? (strlen(s) + 1) : 0;
Packit Service a8c26c
				sfputu(op, n);
Packit Service a8c26c
			}
Packit Service a8c26c
		}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * write the string table
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	for (i = 1; i <= mc->num; i++)
Packit Service a8c26c
		if (mc->set[i].num)
Packit Service a8c26c
		{
Packit Service a8c26c
			sp = mc->set + i;
Packit Service a8c26c
			for (j = 1; j <= sp->num; j++)
Packit Service a8c26c
				if (s = sp->msg[j])
Packit Service a8c26c
					sfputr(op, s, 0);
Packit Service a8c26c
		}
Packit Service a8c26c
Packit Service a8c26c
	/*
Packit Service a8c26c
	 * sync and return
Packit Service a8c26c
	 */
Packit Service a8c26c
Packit Service a8c26c
	return sfsync(op);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * parse <set,msg> number from s
Packit Service a8c26c
 * e!=0 is set to the next char after the parse
Packit Service a8c26c
 * set!=0 is set to message set number
Packit Service a8c26c
 * msg!=0 is set to message number
Packit Service a8c26c
 * the message set number is returned
Packit Service a8c26c
 *
Packit Service a8c26c
 * the base 36 hash gives reasonable values for these:
Packit Service a8c26c
 *
Packit Service a8c26c
 *	"ast" : ((((36#a^36#s^36#t)-9)&63)+1) = 3
Packit Service a8c26c
 *	"gnu" : ((((36#g^36#n^36#u)-9)&63)+1) = 17
Packit Service a8c26c
 *	"sgi" : ((((36#s^36#g^36#i)-9)&63)+1) = 22
Packit Service a8c26c
 *	"sun" : ((((36#s^36#u^36#n)-9)&63)+1) = 13
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
int
Packit Service a8c26c
mcindex(register const char* s, char** e, int* set, int* msg)
Packit Service a8c26c
{
Packit Service a8c26c
	register int		c;
Packit Service a8c26c
	register int		m;
Packit Service a8c26c
	register int		n;
Packit Service a8c26c
	register int		r;
Packit Service a8c26c
	register unsigned char*	cv;
Packit Service a8c26c
	char*			t;
Packit Service a8c26c
Packit Service a8c26c
	m = 0;
Packit Service a8c26c
	n = strtol(s, &t, 0);
Packit Service a8c26c
	if (t == (char*)s)
Packit Service a8c26c
	{
Packit Service a8c26c
		SFCVINIT();
Packit Service a8c26c
		cv = _Sfcv36;
Packit Service a8c26c
		for (n = m = 0; (c = cv[*s]) < 36; s++)
Packit Service a8c26c
		{
Packit Service a8c26c
			m++;
Packit Service a8c26c
			n ^= c;
Packit Service a8c26c
		}
Packit Service a8c26c
		m = (m <= 3) ? 63 : ((1 << (m + 3)) - 1);
Packit Service a8c26c
		n = ((n - 9) & m) + 1;
Packit Service a8c26c
	}
Packit Service a8c26c
	else
Packit Service a8c26c
		s = (const char*)t;
Packit Service a8c26c
	r = n;
Packit Service a8c26c
	if (*s)
Packit Service a8c26c
		m = strtol(s + 1, e, 0);
Packit Service a8c26c
	else
Packit Service a8c26c
	{
Packit Service a8c26c
		if (e)
Packit Service a8c26c
			*e = (char*)s;
Packit Service a8c26c
		if (m)
Packit Service a8c26c
			m = 0;
Packit Service a8c26c
		else
Packit Service a8c26c
		{
Packit Service a8c26c
			m = n;
Packit Service a8c26c
			n = 1;
Packit Service a8c26c
		}
Packit Service a8c26c
	}
Packit Service a8c26c
	if (set)
Packit Service a8c26c
		*set = n;
Packit Service a8c26c
	if (msg)
Packit Service a8c26c
		*msg = m;
Packit Service a8c26c
	return r;
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * close the message catalog mc
Packit Service a8c26c
 */
Packit Service a8c26c
Packit Service a8c26c
int
Packit Service a8c26c
mcclose(register Mc_t* mc)
Packit Service a8c26c
{
Packit Service a8c26c
	if (!mc)
Packit Service a8c26c
		return -1;
Packit Service a8c26c
	if (mc->tmp)
Packit Service a8c26c
		sfclose(mc->tmp);
Packit Service a8c26c
	if (mc->cvt != (iconv_t)(-1))
Packit Service a8c26c
		iconv_close(mc->cvt);
Packit Service a8c26c
	vmclose(mc->vm);
Packit Service a8c26c
	return 0;
Packit Service a8c26c
}