xref: /titanic_51/usr/src/lib/libast/common/port/mc.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin 
24da2e3ebdSchin /*
25da2e3ebdSchin  * Glenn Fowler
26da2e3ebdSchin  * AT&T Research
27da2e3ebdSchin  *
28da2e3ebdSchin  * machine independent binary message catalog implementation
29da2e3ebdSchin  */
30da2e3ebdSchin 
31da2e3ebdSchin #include "sfhdr.h"
32da2e3ebdSchin #include "lclib.h"
33da2e3ebdSchin 
34da2e3ebdSchin #include <iconv.h>
35da2e3ebdSchin 
36da2e3ebdSchin #define _MC_PRIVATE_ \
37da2e3ebdSchin 	size_t		nstrs; \
38da2e3ebdSchin 	size_t		nmsgs; \
39da2e3ebdSchin 	iconv_t		cvt; \
40da2e3ebdSchin 	Sfio_t*		tmp; \
41da2e3ebdSchin 	Vmalloc_t*	vm;
42da2e3ebdSchin 
43da2e3ebdSchin #include <vmalloc.h>
44da2e3ebdSchin #include <error.h>
45da2e3ebdSchin #include <mc.h>
46da2e3ebdSchin #include <nl_types.h>
47da2e3ebdSchin 
48da2e3ebdSchin /*
49da2e3ebdSchin  * find the binary message catalog path for <locale,catalog>
50da2e3ebdSchin  * result placed in path of size PATH_MAX
51da2e3ebdSchin  * pointer to path returned
52da2e3ebdSchin  * catalog==0 tests for category directory or file
53da2e3ebdSchin  * nls!=0 enables NLSPATH+LANG hack (not implemented yet)
54da2e3ebdSchin  */
55da2e3ebdSchin 
56da2e3ebdSchin char*
mcfind(char * path,const char * locale,const char * catalog,int category,int nls)57da2e3ebdSchin mcfind(char* path, const char* locale, const char* catalog, int category, int nls)
58da2e3ebdSchin {
59da2e3ebdSchin 	register int		c;
60da2e3ebdSchin 	register char*		s;
61da2e3ebdSchin 	register char*		e;
62da2e3ebdSchin 	register char*		p;
63da2e3ebdSchin 	register const char*	v;
64da2e3ebdSchin 	int			i;
65da2e3ebdSchin 	int			first;
66da2e3ebdSchin 	int			next;
67da2e3ebdSchin 	int			last;
68da2e3ebdSchin 	int			oerrno;
69da2e3ebdSchin 	Lc_t*			lc;
70da2e3ebdSchin 	char			file[PATH_MAX];
71da2e3ebdSchin 	char*			paths[5];
72da2e3ebdSchin 
73da2e3ebdSchin 	static char		lc_messages[] = "LC_MESSAGES";
74da2e3ebdSchin 
75da2e3ebdSchin 	if ((category = lcindex(category, 1)) < 0)
76da2e3ebdSchin 		return 0;
77da2e3ebdSchin 	if (!(lc = locale ? lcmake(locale) : locales[category]))
78da2e3ebdSchin 		return 0;
79da2e3ebdSchin 	oerrno = errno;
80da2e3ebdSchin 	if (catalog && *catalog == '/')
81da2e3ebdSchin 	{
82da2e3ebdSchin 		i = eaccess(catalog, R_OK);
83da2e3ebdSchin 		errno = oerrno;
84da2e3ebdSchin 		if (i)
85da2e3ebdSchin 			return 0;
86da2e3ebdSchin 		strncpy(path, catalog, PATH_MAX-1);
87da2e3ebdSchin 		return path;
88da2e3ebdSchin 	}
89da2e3ebdSchin 	i = 0;
90da2e3ebdSchin #if !_lib_catopen
91da2e3ebdSchin 	if ((p = getenv("NLSPATH")) && *p)
92da2e3ebdSchin 		paths[i++] = p;
93da2e3ebdSchin #endif
94da2e3ebdSchin 	paths[i++] = "share/lib/locale/%l/%C/%N";
95da2e3ebdSchin 	paths[i++] = "share/locale/%l/%C/%N";
96da2e3ebdSchin 	paths[i++] = "lib/locale/%l/%C/%N";
97da2e3ebdSchin 	paths[i] = 0;
98da2e3ebdSchin 	next = 1;
99da2e3ebdSchin 	for (i = 0; p = paths[i]; i += next)
100da2e3ebdSchin 	{
101da2e3ebdSchin 		first = 1;
102da2e3ebdSchin 		last = 0;
103da2e3ebdSchin 		e = &file[elementsof(file) - 1];
104da2e3ebdSchin 		while (*p)
105da2e3ebdSchin 		{
106da2e3ebdSchin 			s = file;
107da2e3ebdSchin 			for (;;)
108da2e3ebdSchin 			{
109da2e3ebdSchin 				switch (c = *p++)
110da2e3ebdSchin 				{
111da2e3ebdSchin 				case 0:
112da2e3ebdSchin 					p--;
113da2e3ebdSchin 					break;
114da2e3ebdSchin 				case ':':
115da2e3ebdSchin 					break;
116da2e3ebdSchin 				case '%':
117da2e3ebdSchin 					if (s < e)
118da2e3ebdSchin 					{
119da2e3ebdSchin 						switch (c = *p++)
120da2e3ebdSchin 						{
121da2e3ebdSchin 						case 0:
122da2e3ebdSchin 							p--;
123da2e3ebdSchin 							continue;
124da2e3ebdSchin 						case 'N':
125da2e3ebdSchin 							v = catalog;
126da2e3ebdSchin 							break;
127da2e3ebdSchin 						case 'L':
128da2e3ebdSchin 							if (first)
129da2e3ebdSchin 							{
130da2e3ebdSchin 								first = 0;
131da2e3ebdSchin 								if (next)
132da2e3ebdSchin 								{
133da2e3ebdSchin 									v = lc->code;
134da2e3ebdSchin 									if (lc->code != lc->language->code)
135da2e3ebdSchin 										next = 0;
136da2e3ebdSchin 								}
137da2e3ebdSchin 								else
138da2e3ebdSchin 								{
139da2e3ebdSchin 									next = 1;
140da2e3ebdSchin 									v = lc->language->code;
141da2e3ebdSchin 								}
142da2e3ebdSchin 							}
143da2e3ebdSchin 							break;
144da2e3ebdSchin 						case 'l':
145da2e3ebdSchin 							v = lc->language->code;
146da2e3ebdSchin 							break;
147da2e3ebdSchin 						case 't':
148da2e3ebdSchin 							v = lc->territory->code;
149da2e3ebdSchin 							break;
150da2e3ebdSchin 						case 'c':
151da2e3ebdSchin 							v = lc->charset->code;
152da2e3ebdSchin 							break;
153da2e3ebdSchin 						case 'C':
154da2e3ebdSchin 						case_C:
155da2e3ebdSchin 							if (!catalog)
156da2e3ebdSchin 								last = 1;
1577c2fbfb3SApril Chin 							v = lc_categories[category].name;
158da2e3ebdSchin 							break;
159da2e3ebdSchin 						default:
160da2e3ebdSchin 							*s++ = c;
161da2e3ebdSchin 							continue;
162da2e3ebdSchin 						}
163da2e3ebdSchin 						if (v)
164da2e3ebdSchin 							while (*v && s < e)
165da2e3ebdSchin 								*s++ = *v++;
166da2e3ebdSchin 					}
167da2e3ebdSchin 					continue;
168da2e3ebdSchin 				case '/':
169da2e3ebdSchin 					if (last)
170da2e3ebdSchin 						break;
171da2e3ebdSchin 					if (category != AST_LC_MESSAGES && strneq(p, lc_messages, sizeof(lc_messages) - 1) && p[sizeof(lc_messages)-1] == '/')
172da2e3ebdSchin 					{
173da2e3ebdSchin 						p += sizeof(lc_messages) - 1;
174da2e3ebdSchin 						goto case_C;
175da2e3ebdSchin 					}
176da2e3ebdSchin 					/*FALLTHROUGH*/
177da2e3ebdSchin 				default:
178da2e3ebdSchin 					if (s < e)
179da2e3ebdSchin 						*s++ = c;
180da2e3ebdSchin 					continue;
181da2e3ebdSchin 				}
182da2e3ebdSchin 				break;
183da2e3ebdSchin 			}
184da2e3ebdSchin 			if (s > file)
185da2e3ebdSchin 				*s = 0;
186da2e3ebdSchin 			else if (!catalog)
187da2e3ebdSchin 				continue;
188da2e3ebdSchin 			else
189da2e3ebdSchin 				strncpy(file, catalog, elementsof(file));
190da2e3ebdSchin 			if (ast.locale.set & AST_LC_find)
191da2e3ebdSchin 				sfprintf(sfstderr, "locale find %s\n", file);
192da2e3ebdSchin 			if (s = pathpath(path, file, "", (!catalog && category == AST_LC_MESSAGES) ? PATH_READ : (PATH_REGULAR|PATH_READ|PATH_ABSOLUTE)))
193da2e3ebdSchin 			{
194da2e3ebdSchin 				if (ast.locale.set & (AST_LC_find|AST_LC_setlocale))
195da2e3ebdSchin 					sfprintf(sfstderr, "locale path %s\n", s);
196da2e3ebdSchin 				errno = oerrno;
197da2e3ebdSchin 				return s;
198da2e3ebdSchin 			}
199da2e3ebdSchin 		}
200da2e3ebdSchin 	}
201da2e3ebdSchin 	errno = oerrno;
202da2e3ebdSchin 	return 0;
203da2e3ebdSchin }
204da2e3ebdSchin 
205da2e3ebdSchin /*
206da2e3ebdSchin  * allocate and read the binary message catalog ip
207da2e3ebdSchin  * if ip==0 then space is allocated for mcput()
208da2e3ebdSchin  * 0 returned on any error
209da2e3ebdSchin  */
210da2e3ebdSchin 
211da2e3ebdSchin Mc_t*
mcopen(register Sfio_t * ip)212da2e3ebdSchin mcopen(register Sfio_t* ip)
213da2e3ebdSchin {
214da2e3ebdSchin 	register Mc_t*		mc;
215da2e3ebdSchin 	register char**		mp;
216da2e3ebdSchin 	register char*		sp;
217da2e3ebdSchin 	Vmalloc_t*		vm;
218da2e3ebdSchin 	char*			rp;
219da2e3ebdSchin 	int			i;
220da2e3ebdSchin 	int			j;
221da2e3ebdSchin 	int			oerrno;
222da2e3ebdSchin 	size_t			n;
223da2e3ebdSchin 	char			buf[MC_MAGIC_SIZE];
224da2e3ebdSchin 
225da2e3ebdSchin 	oerrno = errno;
226da2e3ebdSchin 	if (ip)
227da2e3ebdSchin 	{
228da2e3ebdSchin 		/*
229da2e3ebdSchin 		 * check the magic
230da2e3ebdSchin 		 */
231da2e3ebdSchin 
232da2e3ebdSchin 		if (sfread(ip, buf, MC_MAGIC_SIZE) != MC_MAGIC_SIZE)
233da2e3ebdSchin 		{
234da2e3ebdSchin 			errno = oerrno;
235da2e3ebdSchin 			return 0;
236da2e3ebdSchin 		}
237da2e3ebdSchin 		if (memcmp(buf, MC_MAGIC, MC_MAGIC_SIZE))
238da2e3ebdSchin 			return 0;
239da2e3ebdSchin 	}
240da2e3ebdSchin 
241da2e3ebdSchin 	/*
242da2e3ebdSchin 	 * allocate the region
243da2e3ebdSchin 	 */
244da2e3ebdSchin 
245da2e3ebdSchin 	if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(mc = vmnewof(vm, 0, Mc_t, 1, 0)))
246da2e3ebdSchin 	{
247da2e3ebdSchin 		errno = oerrno;
248da2e3ebdSchin 		return 0;
249da2e3ebdSchin 	}
250da2e3ebdSchin 	mc->vm = vm;
251da2e3ebdSchin 	mc->cvt = (iconv_t)(-1);
252da2e3ebdSchin 	if (ip)
253da2e3ebdSchin 	{
254da2e3ebdSchin 		/*
255da2e3ebdSchin 		 * read the translation record
256da2e3ebdSchin 		 */
257da2e3ebdSchin 
258da2e3ebdSchin 		if (!(sp = sfgetr(ip, 0, 0)) || !(mc->translation = vmstrdup(vm, sp)))
259da2e3ebdSchin 			goto bad;
260da2e3ebdSchin 
261da2e3ebdSchin 		/*
262da2e3ebdSchin 		 * read the optional header records
263da2e3ebdSchin 		 */
264da2e3ebdSchin 
265da2e3ebdSchin 		do
266da2e3ebdSchin 		{
267da2e3ebdSchin 			if (!(sp = sfgetr(ip, 0, 0)))
268da2e3ebdSchin 				goto bad;
269da2e3ebdSchin 		} while (*sp);
270da2e3ebdSchin 
271da2e3ebdSchin 		/*
272da2e3ebdSchin 		 * get the component dimensions
273da2e3ebdSchin 		 */
274da2e3ebdSchin 
275da2e3ebdSchin 		mc->nstrs = sfgetu(ip);
276da2e3ebdSchin 		mc->nmsgs = sfgetu(ip);
277da2e3ebdSchin 		mc->num = sfgetu(ip);
278da2e3ebdSchin 		if (sfeof(ip))
279da2e3ebdSchin 			goto bad;
280da2e3ebdSchin 	}
281da2e3ebdSchin 	else if (!(mc->translation = vmnewof(vm, 0, char, 1, 0)))
282da2e3ebdSchin 		goto bad;
283da2e3ebdSchin 
284da2e3ebdSchin 	/*
285da2e3ebdSchin 	 * allocate the remaining space
286da2e3ebdSchin 	 */
287da2e3ebdSchin 
288da2e3ebdSchin 	if (!(mc->set = vmnewof(vm, 0, Mcset_t, mc->num + 1, 0)))
289da2e3ebdSchin 		goto bad;
290da2e3ebdSchin 	if (!ip)
291da2e3ebdSchin 		return mc;
292da2e3ebdSchin 	if (!(mp = vmnewof(vm, 0, char*, mc->nmsgs + mc->num + 1, 0)))
293da2e3ebdSchin 		goto bad;
294da2e3ebdSchin 	if (!(rp = sp = vmalloc(vm, mc->nstrs + 1)))
295da2e3ebdSchin 		goto bad;
296da2e3ebdSchin 
297da2e3ebdSchin 	/*
298da2e3ebdSchin 	 * get the set dimensions and initialize the msg pointers
299da2e3ebdSchin 	 */
300da2e3ebdSchin 
301da2e3ebdSchin 	while (i = sfgetu(ip))
302da2e3ebdSchin 	{
303da2e3ebdSchin 		if (i > mc->num)
304da2e3ebdSchin 			goto bad;
305da2e3ebdSchin 		n = sfgetu(ip);
306da2e3ebdSchin 		mc->set[i].num = n;
307da2e3ebdSchin 		mc->set[i].msg = mp;
308da2e3ebdSchin 		mp += n + 1;
309da2e3ebdSchin 	}
310da2e3ebdSchin 
311da2e3ebdSchin 	/*
312da2e3ebdSchin 	 * read the msg sizes and set up the msg pointers
313da2e3ebdSchin 	 */
314da2e3ebdSchin 
315da2e3ebdSchin 	for (i = 1; i <= mc->num; i++)
316da2e3ebdSchin 		for (j = 1; j <= mc->set[i].num; j++)
317da2e3ebdSchin 			if (n = sfgetu(ip))
318da2e3ebdSchin 			{
319da2e3ebdSchin 				mc->set[i].msg[j] = sp;
320da2e3ebdSchin 				sp += n;
321da2e3ebdSchin 			}
322da2e3ebdSchin 
323da2e3ebdSchin 	/*
324da2e3ebdSchin 	 * read the string table
325da2e3ebdSchin 	 */
326da2e3ebdSchin 
327da2e3ebdSchin 	if (sfread(ip, rp, mc->nstrs) != mc->nstrs || sfgetc(ip) != EOF)
328da2e3ebdSchin 		goto bad;
329da2e3ebdSchin 	if (!(mc->tmp = sfstropen()))
330da2e3ebdSchin 		goto bad;
331da2e3ebdSchin 	mc->cvt = iconv_open("", "utf");
332da2e3ebdSchin 	errno = oerrno;
333da2e3ebdSchin 	return mc;
334da2e3ebdSchin  bad:
335da2e3ebdSchin 	vmclose(vm);
336da2e3ebdSchin 	errno = oerrno;
337da2e3ebdSchin 	return 0;
338da2e3ebdSchin }
339da2e3ebdSchin 
340da2e3ebdSchin /*
341da2e3ebdSchin  * return the <set,num> message in mc
342da2e3ebdSchin  * msg returned on error
343da2e3ebdSchin  * utf message text converted to ucs
344da2e3ebdSchin  */
345da2e3ebdSchin 
346da2e3ebdSchin char*
mcget(register Mc_t * mc,int set,int num,const char * msg)347da2e3ebdSchin mcget(register Mc_t* mc, int set, int num, const char* msg)
348da2e3ebdSchin {
349da2e3ebdSchin 	char*		s;
350da2e3ebdSchin 	size_t		n;
351da2e3ebdSchin 	int		p;
352da2e3ebdSchin 
353da2e3ebdSchin 	if (!mc || set < 0 || set > mc->num || num < 1 || num > mc->set[set].num || !(s = mc->set[set].msg[num]))
354da2e3ebdSchin 		return (char*)msg;
355da2e3ebdSchin 	if (mc->cvt == (iconv_t)(-1))
356da2e3ebdSchin 		return s;
357da2e3ebdSchin 	if ((p = sfstrtell(mc->tmp)) > sfstrsize(mc->tmp) / 2)
358da2e3ebdSchin 	{
359da2e3ebdSchin 		p = 0;
360da2e3ebdSchin 		sfstrseek(mc->tmp, p, SEEK_SET);
361da2e3ebdSchin 	}
362da2e3ebdSchin 	n = strlen(s) + 1;
363da2e3ebdSchin 	iconv_write(mc->cvt, mc->tmp, &s, &n, NiL);
364da2e3ebdSchin 	return sfstrbase(mc->tmp) + p;
365da2e3ebdSchin }
366da2e3ebdSchin 
367da2e3ebdSchin /*
368da2e3ebdSchin  * set message <set,num> to msg
369da2e3ebdSchin  * msg==0 deletes the message
370da2e3ebdSchin  * the message and set counts are adjusted
371da2e3ebdSchin  * 0 returned on success, -1 otherwise
372da2e3ebdSchin  */
373da2e3ebdSchin 
374da2e3ebdSchin int
mcput(register Mc_t * mc,int set,int num,const char * msg)375da2e3ebdSchin mcput(register Mc_t* mc, int set, int num, const char* msg)
376da2e3ebdSchin {
377da2e3ebdSchin 	register int		i;
378da2e3ebdSchin 	register char*		s;
379da2e3ebdSchin 	register Mcset_t*	sp;
380da2e3ebdSchin 	register char**		mp;
381da2e3ebdSchin 
382da2e3ebdSchin 	/*
383da2e3ebdSchin 	 * validate the arguments
384da2e3ebdSchin 	 */
385da2e3ebdSchin 
386da2e3ebdSchin 	if (!mc || set > MC_SET_MAX || num > MC_NUM_MAX)
387da2e3ebdSchin 		return -1;
388da2e3ebdSchin 
389da2e3ebdSchin 	/*
390da2e3ebdSchin 	 * deletions don't kick in allocations (duh)
391da2e3ebdSchin 	 */
392da2e3ebdSchin 
393da2e3ebdSchin 	if (!msg)
394da2e3ebdSchin 	{
395da2e3ebdSchin 		if (set <= mc->num && num <= mc->set[set].num && (s = mc->set[set].msg[num]))
396da2e3ebdSchin 		{
397da2e3ebdSchin 			/*
398da2e3ebdSchin 			 * decrease the string table size
399da2e3ebdSchin 			 */
400da2e3ebdSchin 
401da2e3ebdSchin 			mc->set[set].msg[num] = 0;
402da2e3ebdSchin 			mc->nstrs -= strlen(s) + 1;
403da2e3ebdSchin 			if (mc->set[set].num == num)
404da2e3ebdSchin 			{
405da2e3ebdSchin 				/*
406da2e3ebdSchin 				 * decrease the max msg num
407da2e3ebdSchin 				 */
408da2e3ebdSchin 
409da2e3ebdSchin 				mp = mc->set[set].msg + num;
410da2e3ebdSchin 				while (num && !mp[--num]);
411da2e3ebdSchin 				mc->nmsgs -= mc->set[set].num - num;
412da2e3ebdSchin 				if (!(mc->set[set].num = num) && mc->num == set)
413da2e3ebdSchin 				{
414da2e3ebdSchin 					/*
415da2e3ebdSchin 					 * decrease the max set num
416da2e3ebdSchin 					 */
417da2e3ebdSchin 
418da2e3ebdSchin 					while (num && !mc->set[--num].num);
419da2e3ebdSchin 					mc->num = num;
420da2e3ebdSchin 				}
421da2e3ebdSchin 			}
422da2e3ebdSchin 		}
423da2e3ebdSchin 		return 0;
424da2e3ebdSchin 	}
425da2e3ebdSchin 
426da2e3ebdSchin 	/*
427da2e3ebdSchin 	 * keep track of the highest set and allocate if necessary
428da2e3ebdSchin 	 */
429da2e3ebdSchin 
430da2e3ebdSchin 	if (set > mc->num)
431da2e3ebdSchin 	{
432da2e3ebdSchin 		if (set > mc->gen)
433da2e3ebdSchin 		{
434da2e3ebdSchin 			i = MC_SET_MAX;
435da2e3ebdSchin 			if (!(sp = vmnewof(mc->vm, 0, Mcset_t, i + 1, 0)))
436da2e3ebdSchin 				return -1;
437da2e3ebdSchin 			mc->gen = i;
438da2e3ebdSchin 			for (i = 1; i <= mc->num; i++)
439da2e3ebdSchin 				sp[i] = mc->set[i];
440da2e3ebdSchin 			mc->set = sp;
441da2e3ebdSchin 		}
442da2e3ebdSchin 		mc->num = set;
443da2e3ebdSchin 	}
444da2e3ebdSchin 	sp = mc->set + set;
445da2e3ebdSchin 
446da2e3ebdSchin 	/*
447da2e3ebdSchin 	 * keep track of the highest msg and allocate if necessary
448da2e3ebdSchin 	 */
449da2e3ebdSchin 
450da2e3ebdSchin 	if (num > sp->num)
451da2e3ebdSchin 	{
452da2e3ebdSchin 		if (num > sp->gen)
453da2e3ebdSchin 		{
454da2e3ebdSchin 			if (!mc->gen)
455da2e3ebdSchin 			{
456da2e3ebdSchin 				i = (MC_NUM_MAX + 1) / 32;
457da2e3ebdSchin 				if (i <= num)
458da2e3ebdSchin 					i = 2 * num;
459da2e3ebdSchin 				if (i > MC_NUM_MAX)
460da2e3ebdSchin 					i = MC_NUM_MAX;
461da2e3ebdSchin 				if (!(mp = vmnewof(mc->vm, 0, char*, i + 1, 0)))
462da2e3ebdSchin 					return -1;
463da2e3ebdSchin 				mc->gen = i;
464da2e3ebdSchin 				sp->msg = mp;
465da2e3ebdSchin 				for (i = 1; i <= sp->num; i++)
466da2e3ebdSchin 					mp[i] = sp->msg[i];
467da2e3ebdSchin 			}
468da2e3ebdSchin 			else
469da2e3ebdSchin 			{
470da2e3ebdSchin 				i = 2 * mc->gen;
471da2e3ebdSchin 				if (i > MC_NUM_MAX)
472da2e3ebdSchin 					i = MC_NUM_MAX;
473da2e3ebdSchin 				if (!(mp = vmnewof(mc->vm, sp->msg, char*, i + 1, 0)))
474da2e3ebdSchin 					return -1;
475da2e3ebdSchin 				sp->gen = i;
476da2e3ebdSchin 				sp->msg = mp;
477da2e3ebdSchin 			}
478da2e3ebdSchin 		}
479da2e3ebdSchin 		mc->nmsgs += num - sp->num;
480da2e3ebdSchin 		sp->num = num;
481da2e3ebdSchin 	}
482da2e3ebdSchin 
483da2e3ebdSchin 	/*
484da2e3ebdSchin 	 * decrease the string table size
485da2e3ebdSchin 	 */
486da2e3ebdSchin 
487da2e3ebdSchin 	if (s = sp->msg[num])
488da2e3ebdSchin 	{
489da2e3ebdSchin 		/*
490da2e3ebdSchin 		 * no-op if no change
491da2e3ebdSchin 		 */
492da2e3ebdSchin 
493da2e3ebdSchin 		if (streq(s, msg))
494da2e3ebdSchin 			return 0;
495da2e3ebdSchin 		mc->nstrs -= strlen(s) + 1;
496da2e3ebdSchin 	}
497da2e3ebdSchin 
498da2e3ebdSchin 	/*
499da2e3ebdSchin 	 * allocate, add and adjust the string table size
500da2e3ebdSchin 	 */
501da2e3ebdSchin 
502da2e3ebdSchin 	if (!(s = vmstrdup(mc->vm, msg)))
503da2e3ebdSchin 		return -1;
504da2e3ebdSchin 	sp->msg[num] = s;
505da2e3ebdSchin 	mc->nstrs += strlen(s) + 1;
506da2e3ebdSchin 	return 0;
507da2e3ebdSchin }
508da2e3ebdSchin 
509da2e3ebdSchin /*
510da2e3ebdSchin  * dump message catalog mc to op
511da2e3ebdSchin  * 0 returned on success, -1 otherwise
512da2e3ebdSchin  */
513da2e3ebdSchin 
514da2e3ebdSchin int
mcdump(register Mc_t * mc,register Sfio_t * op)515da2e3ebdSchin mcdump(register Mc_t* mc, register Sfio_t* op)
516da2e3ebdSchin {
517da2e3ebdSchin 	register int		i;
518da2e3ebdSchin 	register int		j;
519da2e3ebdSchin 	register int		n;
520da2e3ebdSchin 	register char*		s;
521da2e3ebdSchin 	register Mcset_t*	sp;
522da2e3ebdSchin 
523da2e3ebdSchin 	/*
524da2e3ebdSchin 	 * write the magic
525da2e3ebdSchin 	 */
526da2e3ebdSchin 
527da2e3ebdSchin 	if (sfwrite(op, MC_MAGIC, MC_MAGIC_SIZE) != MC_MAGIC_SIZE)
528da2e3ebdSchin 		return -1;
529da2e3ebdSchin 
530da2e3ebdSchin 	/*
531da2e3ebdSchin 	 * write the translation record
532da2e3ebdSchin 	 */
533da2e3ebdSchin 
534da2e3ebdSchin 	sfputr(op, mc->translation, 0);
535da2e3ebdSchin 
536da2e3ebdSchin 	/* optional header records here */
537da2e3ebdSchin 
538da2e3ebdSchin 	/*
539da2e3ebdSchin 	 * end of optional header records
540da2e3ebdSchin 	 */
541da2e3ebdSchin 
542da2e3ebdSchin 	sfputu(op, 0);
543da2e3ebdSchin 
544da2e3ebdSchin 	/*
545da2e3ebdSchin 	 * write the global dimensions
546da2e3ebdSchin 	 */
547da2e3ebdSchin 
548da2e3ebdSchin 	sfputu(op, mc->nstrs);
549da2e3ebdSchin 	sfputu(op, mc->nmsgs);
550da2e3ebdSchin 	sfputu(op, mc->num);
551da2e3ebdSchin 
552da2e3ebdSchin 	/*
553da2e3ebdSchin 	 * write the set dimensions
554da2e3ebdSchin 	 */
555da2e3ebdSchin 
556da2e3ebdSchin 	for (i = 1; i <= mc->num; i++)
557da2e3ebdSchin 		if (mc->set[i].num)
558da2e3ebdSchin 		{
559da2e3ebdSchin 			sfputu(op, i);
560da2e3ebdSchin 			sfputu(op, mc->set[i].num);
561da2e3ebdSchin 		}
562da2e3ebdSchin 	sfputu(op, 0);
563da2e3ebdSchin 
564da2e3ebdSchin 	/*
565da2e3ebdSchin 	 * write the message sizes
566da2e3ebdSchin 	 */
567da2e3ebdSchin 
568da2e3ebdSchin 	for (i = 1; i <= mc->num; i++)
569da2e3ebdSchin 		if (mc->set[i].num)
570da2e3ebdSchin 		{
571da2e3ebdSchin 			sp = mc->set + i;
572da2e3ebdSchin 			for (j = 1; j <= sp->num; j++)
573da2e3ebdSchin 			{
574da2e3ebdSchin 				n = (s = sp->msg[j]) ? (strlen(s) + 1) : 0;
575da2e3ebdSchin 				sfputu(op, n);
576da2e3ebdSchin 			}
577da2e3ebdSchin 		}
578da2e3ebdSchin 
579da2e3ebdSchin 	/*
580da2e3ebdSchin 	 * write the string table
581da2e3ebdSchin 	 */
582da2e3ebdSchin 
583da2e3ebdSchin 	for (i = 1; i <= mc->num; i++)
584da2e3ebdSchin 		if (mc->set[i].num)
585da2e3ebdSchin 		{
586da2e3ebdSchin 			sp = mc->set + i;
587da2e3ebdSchin 			for (j = 1; j <= sp->num; j++)
588da2e3ebdSchin 				if (s = sp->msg[j])
589da2e3ebdSchin 					sfputr(op, s, 0);
590da2e3ebdSchin 		}
591da2e3ebdSchin 
592da2e3ebdSchin 	/*
593da2e3ebdSchin 	 * sync and return
594da2e3ebdSchin 	 */
595da2e3ebdSchin 
596da2e3ebdSchin 	return sfsync(op);
597da2e3ebdSchin }
598da2e3ebdSchin 
599da2e3ebdSchin /*
600da2e3ebdSchin  * parse <set,msg> number from s
601da2e3ebdSchin  * e!=0 is set to the next char after the parse
602da2e3ebdSchin  * set!=0 is set to message set number
603da2e3ebdSchin  * msg!=0 is set to message number
604da2e3ebdSchin  * the message set number is returned
605da2e3ebdSchin  *
606da2e3ebdSchin  * the base 36 hash gives reasonable values for these:
607da2e3ebdSchin  *
608da2e3ebdSchin  *	"ast" : ((((36#a^36#s^36#t)-9)&63)+1) = 3
609da2e3ebdSchin  *	"gnu" : ((((36#g^36#n^36#u)-9)&63)+1) = 17
610da2e3ebdSchin  *	"sgi" : ((((36#s^36#g^36#i)-9)&63)+1) = 22
611da2e3ebdSchin  *	"sun" : ((((36#s^36#u^36#n)-9)&63)+1) = 13
612da2e3ebdSchin  */
613da2e3ebdSchin 
614da2e3ebdSchin int
mcindex(register const char * s,char ** e,int * set,int * msg)615da2e3ebdSchin mcindex(register const char* s, char** e, int* set, int* msg)
616da2e3ebdSchin {
617da2e3ebdSchin 	register int		c;
618da2e3ebdSchin 	register int		m;
619da2e3ebdSchin 	register int		n;
620da2e3ebdSchin 	register int		r;
621da2e3ebdSchin 	register unsigned char*	cv;
622da2e3ebdSchin 	char*			t;
623da2e3ebdSchin 
624da2e3ebdSchin 	m = 0;
625da2e3ebdSchin 	n = strtol(s, &t, 0);
626da2e3ebdSchin 	if (t == (char*)s)
627da2e3ebdSchin 	{
628da2e3ebdSchin 		SFCVINIT();
629da2e3ebdSchin 		cv = _Sfcv36;
630da2e3ebdSchin 		for (n = m = 0; (c = cv[*s]) < 36; s++)
631da2e3ebdSchin 		{
632da2e3ebdSchin 			m++;
633da2e3ebdSchin 			n ^= c;
634da2e3ebdSchin 		}
635da2e3ebdSchin 		m = (m <= 3) ? 63 : ((1 << (m + 3)) - 1);
636da2e3ebdSchin 		n = ((n - 9) & m) + 1;
637da2e3ebdSchin 	}
638da2e3ebdSchin 	else
639da2e3ebdSchin 		s = (const char*)t;
640da2e3ebdSchin 	r = n;
641da2e3ebdSchin 	if (*s)
642da2e3ebdSchin 		m = strtol(s + 1, e, 0);
643da2e3ebdSchin 	else
644da2e3ebdSchin 	{
645da2e3ebdSchin 		if (e)
646da2e3ebdSchin 			*e = (char*)s;
647da2e3ebdSchin 		if (m)
648da2e3ebdSchin 			m = 0;
649da2e3ebdSchin 		else
650da2e3ebdSchin 		{
651da2e3ebdSchin 			m = n;
652da2e3ebdSchin 			n = 1;
653da2e3ebdSchin 		}
654da2e3ebdSchin 	}
655da2e3ebdSchin 	if (set)
656da2e3ebdSchin 		*set = n;
657da2e3ebdSchin 	if (msg)
658da2e3ebdSchin 		*msg = m;
659da2e3ebdSchin 	return r;
660da2e3ebdSchin }
661da2e3ebdSchin 
662da2e3ebdSchin /*
663da2e3ebdSchin  * close the message catalog mc
664da2e3ebdSchin  */
665da2e3ebdSchin 
666da2e3ebdSchin int
mcclose(register Mc_t * mc)667da2e3ebdSchin mcclose(register Mc_t* mc)
668da2e3ebdSchin {
669da2e3ebdSchin 	if (!mc)
670da2e3ebdSchin 		return -1;
671da2e3ebdSchin 	if (mc->tmp)
672da2e3ebdSchin 		sfclose(mc->tmp);
673da2e3ebdSchin 	if (mc->cvt != (iconv_t)(-1))
674da2e3ebdSchin 		iconv_close(mc->cvt);
675da2e3ebdSchin 	vmclose(mc->vm);
676da2e3ebdSchin 	return 0;
677da2e3ebdSchin }
678