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