1*36dcc4a4SLionel Sambuc /* $NetBSD: gettext.c,v 1.29 2015/05/29 12:26:28 christos Exp $ */
2*36dcc4a4SLionel Sambuc
3*36dcc4a4SLionel Sambuc /*-
4*36dcc4a4SLionel Sambuc * Copyright (c) 2000, 2001 Citrus Project,
5*36dcc4a4SLionel Sambuc * All rights reserved.
6*36dcc4a4SLionel Sambuc *
7*36dcc4a4SLionel Sambuc * Redistribution and use in source and binary forms, with or without
8*36dcc4a4SLionel Sambuc * modification, are permitted provided that the following conditions
9*36dcc4a4SLionel Sambuc * are met:
10*36dcc4a4SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
11*36dcc4a4SLionel Sambuc * notice, this list of conditions and the following disclaimer.
12*36dcc4a4SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
13*36dcc4a4SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
14*36dcc4a4SLionel Sambuc * documentation and/or other materials provided with the distribution.
15*36dcc4a4SLionel Sambuc *
16*36dcc4a4SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*36dcc4a4SLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*36dcc4a4SLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*36dcc4a4SLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*36dcc4a4SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*36dcc4a4SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*36dcc4a4SLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*36dcc4a4SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*36dcc4a4SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*36dcc4a4SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*36dcc4a4SLionel Sambuc * SUCH DAMAGE.
27*36dcc4a4SLionel Sambuc *
28*36dcc4a4SLionel Sambuc * $Citrus: xpg4dl/FreeBSD/lib/libintl/gettext.c,v 1.31 2001/09/27 15:18:45 yamt Exp $
29*36dcc4a4SLionel Sambuc */
30*36dcc4a4SLionel Sambuc
31*36dcc4a4SLionel Sambuc #include <sys/cdefs.h>
32*36dcc4a4SLionel Sambuc __RCSID("$NetBSD: gettext.c,v 1.29 2015/05/29 12:26:28 christos Exp $");
33*36dcc4a4SLionel Sambuc
34*36dcc4a4SLionel Sambuc #include <sys/param.h>
35*36dcc4a4SLionel Sambuc #include <sys/stat.h>
36*36dcc4a4SLionel Sambuc #include <sys/mman.h>
37*36dcc4a4SLionel Sambuc #include <sys/uio.h>
38*36dcc4a4SLionel Sambuc
39*36dcc4a4SLionel Sambuc #include <assert.h>
40*36dcc4a4SLionel Sambuc #include <fcntl.h>
41*36dcc4a4SLionel Sambuc #include <stdio.h>
42*36dcc4a4SLionel Sambuc #include <stdlib.h>
43*36dcc4a4SLionel Sambuc #include <unistd.h>
44*36dcc4a4SLionel Sambuc #include <string.h>
45*36dcc4a4SLionel Sambuc #if 0
46*36dcc4a4SLionel Sambuc #include <util.h>
47*36dcc4a4SLionel Sambuc #endif
48*36dcc4a4SLionel Sambuc #include <libintl.h>
49*36dcc4a4SLionel Sambuc #include <locale.h>
50*36dcc4a4SLionel Sambuc #include "libintl_local.h"
51*36dcc4a4SLionel Sambuc #include "plural_parser.h"
52*36dcc4a4SLionel Sambuc #include "pathnames.h"
53*36dcc4a4SLionel Sambuc
54*36dcc4a4SLionel Sambuc /* GNU gettext added a hack to add some context to messages. If a message is
55*36dcc4a4SLionel Sambuc * used in multiple locations, it needs some amount of context to make the
56*36dcc4a4SLionel Sambuc * translation clear to translators. GNU gettext, rather than modifying the
57*36dcc4a4SLionel Sambuc * message format, concatenates the context, \004 and the message id.
58*36dcc4a4SLionel Sambuc */
59*36dcc4a4SLionel Sambuc #define MSGCTXT_ID_SEPARATOR '\004'
60*36dcc4a4SLionel Sambuc
61*36dcc4a4SLionel Sambuc static const char *pgettext_impl(const char *, const char *, const char *,
62*36dcc4a4SLionel Sambuc const char *, unsigned long int, int);
63*36dcc4a4SLionel Sambuc static char *concatenate_ctxt_id(const char *, const char *);
64*36dcc4a4SLionel Sambuc static const char *lookup_category(int);
65*36dcc4a4SLionel Sambuc static const char *split_locale(const char *);
66*36dcc4a4SLionel Sambuc static const char *lookup_mofile(char *, size_t, const char *, const char *,
67*36dcc4a4SLionel Sambuc const char *, const char *,
68*36dcc4a4SLionel Sambuc struct domainbinding *);
69*36dcc4a4SLionel Sambuc static uint32_t flip(uint32_t, uint32_t);
70*36dcc4a4SLionel Sambuc static int validate(void *, struct mohandle *);
71*36dcc4a4SLionel Sambuc static int mapit(const char *, struct domainbinding *);
72*36dcc4a4SLionel Sambuc static int unmapit(struct domainbinding *);
73*36dcc4a4SLionel Sambuc static const char *lookup_hash(const char *, struct domainbinding *, size_t *);
74*36dcc4a4SLionel Sambuc static const char *lookup_bsearch(const char *, struct domainbinding *,
75*36dcc4a4SLionel Sambuc size_t *);
76*36dcc4a4SLionel Sambuc static const char *lookup(const char *, struct domainbinding *, size_t *);
77*36dcc4a4SLionel Sambuc static const char *get_lang_env(const char *);
78*36dcc4a4SLionel Sambuc
79*36dcc4a4SLionel Sambuc /*
80*36dcc4a4SLionel Sambuc * shortcut functions. the main implementation resides in dcngettext().
81*36dcc4a4SLionel Sambuc */
82*36dcc4a4SLionel Sambuc char *
gettext(const char * msgid)83*36dcc4a4SLionel Sambuc gettext(const char *msgid)
84*36dcc4a4SLionel Sambuc {
85*36dcc4a4SLionel Sambuc
86*36dcc4a4SLionel Sambuc return dcngettext(NULL, msgid, NULL, 1UL, LC_MESSAGES);
87*36dcc4a4SLionel Sambuc }
88*36dcc4a4SLionel Sambuc
89*36dcc4a4SLionel Sambuc char *
dgettext(const char * domainname,const char * msgid)90*36dcc4a4SLionel Sambuc dgettext(const char *domainname, const char *msgid)
91*36dcc4a4SLionel Sambuc {
92*36dcc4a4SLionel Sambuc
93*36dcc4a4SLionel Sambuc return dcngettext(domainname, msgid, NULL, 1UL, LC_MESSAGES);
94*36dcc4a4SLionel Sambuc }
95*36dcc4a4SLionel Sambuc
96*36dcc4a4SLionel Sambuc char *
dcgettext(const char * domainname,const char * msgid,int category)97*36dcc4a4SLionel Sambuc dcgettext(const char *domainname, const char *msgid, int category)
98*36dcc4a4SLionel Sambuc {
99*36dcc4a4SLionel Sambuc
100*36dcc4a4SLionel Sambuc return dcngettext(domainname, msgid, NULL, 1UL, category);
101*36dcc4a4SLionel Sambuc }
102*36dcc4a4SLionel Sambuc
103*36dcc4a4SLionel Sambuc char *
ngettext(const char * msgid1,const char * msgid2,unsigned long int n)104*36dcc4a4SLionel Sambuc ngettext(const char *msgid1, const char *msgid2, unsigned long int n)
105*36dcc4a4SLionel Sambuc {
106*36dcc4a4SLionel Sambuc
107*36dcc4a4SLionel Sambuc return dcngettext(NULL, msgid1, msgid2, n, LC_MESSAGES);
108*36dcc4a4SLionel Sambuc }
109*36dcc4a4SLionel Sambuc
110*36dcc4a4SLionel Sambuc char *
dngettext(const char * domainname,const char * msgid1,const char * msgid2,unsigned long int n)111*36dcc4a4SLionel Sambuc dngettext(const char *domainname, const char *msgid1, const char *msgid2,
112*36dcc4a4SLionel Sambuc unsigned long int n)
113*36dcc4a4SLionel Sambuc {
114*36dcc4a4SLionel Sambuc
115*36dcc4a4SLionel Sambuc return dcngettext(domainname, msgid1, msgid2, n, LC_MESSAGES);
116*36dcc4a4SLionel Sambuc }
117*36dcc4a4SLionel Sambuc
118*36dcc4a4SLionel Sambuc const char *
pgettext(const char * msgctxt,const char * msgid)119*36dcc4a4SLionel Sambuc pgettext(const char *msgctxt, const char *msgid)
120*36dcc4a4SLionel Sambuc {
121*36dcc4a4SLionel Sambuc
122*36dcc4a4SLionel Sambuc return pgettext_impl(NULL, msgctxt, msgid, NULL, 1UL, LC_MESSAGES);
123*36dcc4a4SLionel Sambuc }
124*36dcc4a4SLionel Sambuc
125*36dcc4a4SLionel Sambuc const char *
dpgettext(const char * domainname,const char * msgctxt,const char * msgid)126*36dcc4a4SLionel Sambuc dpgettext(const char *domainname, const char *msgctxt, const char *msgid)
127*36dcc4a4SLionel Sambuc {
128*36dcc4a4SLionel Sambuc
129*36dcc4a4SLionel Sambuc return pgettext_impl(domainname, msgctxt, msgid, NULL, 1UL, LC_MESSAGES);
130*36dcc4a4SLionel Sambuc }
131*36dcc4a4SLionel Sambuc
132*36dcc4a4SLionel Sambuc const char *
dcpgettext(const char * domainname,const char * msgctxt,const char * msgid,int category)133*36dcc4a4SLionel Sambuc dcpgettext(const char *domainname, const char *msgctxt, const char *msgid,
134*36dcc4a4SLionel Sambuc int category)
135*36dcc4a4SLionel Sambuc {
136*36dcc4a4SLionel Sambuc
137*36dcc4a4SLionel Sambuc return pgettext_impl(domainname, msgctxt, msgid, NULL, 1UL, category);
138*36dcc4a4SLionel Sambuc }
139*36dcc4a4SLionel Sambuc
140*36dcc4a4SLionel Sambuc const char *
npgettext(const char * msgctxt,const char * msgid1,const char * msgid2,unsigned long int n)141*36dcc4a4SLionel Sambuc npgettext(const char *msgctxt, const char *msgid1, const char *msgid2,
142*36dcc4a4SLionel Sambuc unsigned long int n)
143*36dcc4a4SLionel Sambuc {
144*36dcc4a4SLionel Sambuc
145*36dcc4a4SLionel Sambuc return pgettext_impl(NULL, msgctxt, msgid1, msgid2, n, LC_MESSAGES);
146*36dcc4a4SLionel Sambuc }
147*36dcc4a4SLionel Sambuc
148*36dcc4a4SLionel Sambuc const char *
dnpgettext(const char * domainname,const char * msgctxt,const char * msgid1,const char * msgid2,unsigned long int n)149*36dcc4a4SLionel Sambuc dnpgettext(const char *domainname, const char *msgctxt, const char *msgid1,
150*36dcc4a4SLionel Sambuc const char *msgid2, unsigned long int n)
151*36dcc4a4SLionel Sambuc {
152*36dcc4a4SLionel Sambuc
153*36dcc4a4SLionel Sambuc return pgettext_impl(domainname, msgctxt, msgid1, msgid2, n, LC_MESSAGES);
154*36dcc4a4SLionel Sambuc }
155*36dcc4a4SLionel Sambuc
156*36dcc4a4SLionel Sambuc const char *
dcnpgettext(const char * domainname,const char * msgctxt,const char * msgid1,const char * msgid2,unsigned long int n,int category)157*36dcc4a4SLionel Sambuc dcnpgettext(const char *domainname, const char *msgctxt, const char *msgid1,
158*36dcc4a4SLionel Sambuc const char *msgid2, unsigned long int n, int category)
159*36dcc4a4SLionel Sambuc {
160*36dcc4a4SLionel Sambuc
161*36dcc4a4SLionel Sambuc return pgettext_impl(domainname, msgctxt, msgid1, msgid2, n, category);
162*36dcc4a4SLionel Sambuc }
163*36dcc4a4SLionel Sambuc
164*36dcc4a4SLionel Sambuc static const char *
pgettext_impl(const char * domainname,const char * msgctxt,const char * msgid1,const char * msgid2,unsigned long int n,int category)165*36dcc4a4SLionel Sambuc pgettext_impl(const char *domainname, const char *msgctxt, const char *msgid1,
166*36dcc4a4SLionel Sambuc const char *msgid2, unsigned long int n, int category)
167*36dcc4a4SLionel Sambuc {
168*36dcc4a4SLionel Sambuc char *msgctxt_id;
169*36dcc4a4SLionel Sambuc char *translation;
170*36dcc4a4SLionel Sambuc char *p;
171*36dcc4a4SLionel Sambuc
172*36dcc4a4SLionel Sambuc if ((msgctxt_id = concatenate_ctxt_id(msgctxt, msgid1)) == NULL)
173*36dcc4a4SLionel Sambuc return msgid1;
174*36dcc4a4SLionel Sambuc
175*36dcc4a4SLionel Sambuc translation = dcngettext(domainname, msgctxt_id,
176*36dcc4a4SLionel Sambuc msgid2, n, category);
177*36dcc4a4SLionel Sambuc free(msgctxt_id);
178*36dcc4a4SLionel Sambuc
179*36dcc4a4SLionel Sambuc p = strchr(translation, '\004');
180*36dcc4a4SLionel Sambuc if (p)
181*36dcc4a4SLionel Sambuc return p + 1;
182*36dcc4a4SLionel Sambuc return translation;
183*36dcc4a4SLionel Sambuc }
184*36dcc4a4SLionel Sambuc
185*36dcc4a4SLionel Sambuc /*
186*36dcc4a4SLionel Sambuc * dcngettext() -
187*36dcc4a4SLionel Sambuc * lookup internationalized message on database locale/category/domainname
188*36dcc4a4SLionel Sambuc * (like ja_JP.eucJP/LC_MESSAGES/domainname).
189*36dcc4a4SLionel Sambuc * if n equals to 1, internationalized message will be looked up for msgid1.
190*36dcc4a4SLionel Sambuc * otherwise, message will be looked up for msgid2.
191*36dcc4a4SLionel Sambuc * if the lookup fails, the function will return msgid1 or msgid2 as is.
192*36dcc4a4SLionel Sambuc *
193*36dcc4a4SLionel Sambuc * Even though the return type is "char *", caller should not rewrite the
194*36dcc4a4SLionel Sambuc * region pointed to by the return value (should be "const char *", but can't
195*36dcc4a4SLionel Sambuc * change it for compatibility with other implementations).
196*36dcc4a4SLionel Sambuc *
197*36dcc4a4SLionel Sambuc * by default (if domainname == NULL), domainname is taken from the value set
198*36dcc4a4SLionel Sambuc * by textdomain(). usually name of the application (like "ls") is used as
199*36dcc4a4SLionel Sambuc * domainname. category is usually LC_MESSAGES.
200*36dcc4a4SLionel Sambuc *
201*36dcc4a4SLionel Sambuc * the code reads in *.mo files generated by GNU gettext. *.mo is a host-
202*36dcc4a4SLionel Sambuc * endian encoded file. both endians are supported here, as the files are in
203*36dcc4a4SLionel Sambuc * /usr/share/locale! (or we should move those files into /usr/libdata)
204*36dcc4a4SLionel Sambuc */
205*36dcc4a4SLionel Sambuc
206*36dcc4a4SLionel Sambuc static char *
concatenate_ctxt_id(const char * msgctxt,const char * msgid)207*36dcc4a4SLionel Sambuc concatenate_ctxt_id(const char *msgctxt, const char *msgid)
208*36dcc4a4SLionel Sambuc {
209*36dcc4a4SLionel Sambuc char *ret;
210*36dcc4a4SLionel Sambuc
211*36dcc4a4SLionel Sambuc if (asprintf(&ret, "%s%c%s", msgctxt, MSGCTXT_ID_SEPARATOR, msgid) == -1)
212*36dcc4a4SLionel Sambuc return NULL;
213*36dcc4a4SLionel Sambuc
214*36dcc4a4SLionel Sambuc return ret;
215*36dcc4a4SLionel Sambuc }
216*36dcc4a4SLionel Sambuc
217*36dcc4a4SLionel Sambuc static const char *
lookup_category(int category)218*36dcc4a4SLionel Sambuc lookup_category(int category)
219*36dcc4a4SLionel Sambuc {
220*36dcc4a4SLionel Sambuc
221*36dcc4a4SLionel Sambuc switch (category) {
222*36dcc4a4SLionel Sambuc case LC_COLLATE: return "LC_COLLATE";
223*36dcc4a4SLionel Sambuc case LC_CTYPE: return "LC_CTYPE";
224*36dcc4a4SLionel Sambuc case LC_MONETARY: return "LC_MONETARY";
225*36dcc4a4SLionel Sambuc case LC_NUMERIC: return "LC_NUMERIC";
226*36dcc4a4SLionel Sambuc case LC_TIME: return "LC_TIME";
227*36dcc4a4SLionel Sambuc case LC_MESSAGES: return "LC_MESSAGES";
228*36dcc4a4SLionel Sambuc }
229*36dcc4a4SLionel Sambuc return NULL;
230*36dcc4a4SLionel Sambuc }
231*36dcc4a4SLionel Sambuc
232*36dcc4a4SLionel Sambuc /*
233*36dcc4a4SLionel Sambuc * XPG syntax: language[_territory[.codeset]][@modifier]
234*36dcc4a4SLionel Sambuc * XXX boundary check on "result" is lacking
235*36dcc4a4SLionel Sambuc */
236*36dcc4a4SLionel Sambuc static const char *
split_locale(const char * lname)237*36dcc4a4SLionel Sambuc split_locale(const char *lname)
238*36dcc4a4SLionel Sambuc {
239*36dcc4a4SLionel Sambuc char buf[BUFSIZ], tmp[BUFSIZ];
240*36dcc4a4SLionel Sambuc char *l, *t, *c, *m;
241*36dcc4a4SLionel Sambuc static char result[BUFSIZ];
242*36dcc4a4SLionel Sambuc
243*36dcc4a4SLionel Sambuc memset(result, 0, sizeof(result));
244*36dcc4a4SLionel Sambuc
245*36dcc4a4SLionel Sambuc if (strlen(lname) + 1 > sizeof(buf)) {
246*36dcc4a4SLionel Sambuc fail:
247*36dcc4a4SLionel Sambuc return lname;
248*36dcc4a4SLionel Sambuc }
249*36dcc4a4SLionel Sambuc
250*36dcc4a4SLionel Sambuc strlcpy(buf, lname, sizeof(buf));
251*36dcc4a4SLionel Sambuc m = strrchr(buf, '@');
252*36dcc4a4SLionel Sambuc if (m)
253*36dcc4a4SLionel Sambuc *m++ = '\0';
254*36dcc4a4SLionel Sambuc c = strrchr(buf, '.');
255*36dcc4a4SLionel Sambuc if (c)
256*36dcc4a4SLionel Sambuc *c++ = '\0';
257*36dcc4a4SLionel Sambuc t = strrchr(buf, '_');
258*36dcc4a4SLionel Sambuc if (t)
259*36dcc4a4SLionel Sambuc *t++ = '\0';
260*36dcc4a4SLionel Sambuc l = buf;
261*36dcc4a4SLionel Sambuc if (strlen(l) == 0)
262*36dcc4a4SLionel Sambuc goto fail;
263*36dcc4a4SLionel Sambuc if (c && !t)
264*36dcc4a4SLionel Sambuc goto fail;
265*36dcc4a4SLionel Sambuc
266*36dcc4a4SLionel Sambuc if (m) {
267*36dcc4a4SLionel Sambuc if (t) {
268*36dcc4a4SLionel Sambuc if (c) {
269*36dcc4a4SLionel Sambuc snprintf(tmp, sizeof(tmp), "%s_%s.%s@%s",
270*36dcc4a4SLionel Sambuc l, t, c, m);
271*36dcc4a4SLionel Sambuc strlcat(result, tmp, sizeof(result));
272*36dcc4a4SLionel Sambuc strlcat(result, ":", sizeof(result));
273*36dcc4a4SLionel Sambuc }
274*36dcc4a4SLionel Sambuc snprintf(tmp, sizeof(tmp), "%s_%s@%s", l, t, m);
275*36dcc4a4SLionel Sambuc strlcat(result, tmp, sizeof(result));
276*36dcc4a4SLionel Sambuc strlcat(result, ":", sizeof(result));
277*36dcc4a4SLionel Sambuc }
278*36dcc4a4SLionel Sambuc snprintf(tmp, sizeof(tmp), "%s@%s", l, m);
279*36dcc4a4SLionel Sambuc strlcat(result, tmp, sizeof(result));
280*36dcc4a4SLionel Sambuc strlcat(result, ":", sizeof(result));
281*36dcc4a4SLionel Sambuc }
282*36dcc4a4SLionel Sambuc if (t) {
283*36dcc4a4SLionel Sambuc if (c) {
284*36dcc4a4SLionel Sambuc snprintf(tmp, sizeof(tmp), "%s_%s.%s", l, t, c);
285*36dcc4a4SLionel Sambuc strlcat(result, tmp, sizeof(result));
286*36dcc4a4SLionel Sambuc strlcat(result, ":", sizeof(result));
287*36dcc4a4SLionel Sambuc }
288*36dcc4a4SLionel Sambuc snprintf(tmp, sizeof(tmp), "%s_%s", l, t);
289*36dcc4a4SLionel Sambuc strlcat(result, tmp, sizeof(result));
290*36dcc4a4SLionel Sambuc strlcat(result, ":", sizeof(result));
291*36dcc4a4SLionel Sambuc }
292*36dcc4a4SLionel Sambuc strlcat(result, l, sizeof(result));
293*36dcc4a4SLionel Sambuc
294*36dcc4a4SLionel Sambuc return result;
295*36dcc4a4SLionel Sambuc }
296*36dcc4a4SLionel Sambuc
297*36dcc4a4SLionel Sambuc static const char *
lookup_mofile(char * buf,size_t len,const char * dir,const char * lpath,const char * category,const char * domainname,struct domainbinding * db)298*36dcc4a4SLionel Sambuc lookup_mofile(char *buf, size_t len, const char *dir, const char *lpath,
299*36dcc4a4SLionel Sambuc const char *category, const char *domainname,
300*36dcc4a4SLionel Sambuc struct domainbinding *db)
301*36dcc4a4SLionel Sambuc {
302*36dcc4a4SLionel Sambuc struct stat st;
303*36dcc4a4SLionel Sambuc char *p, *q;
304*36dcc4a4SLionel Sambuc char lpath_tmp[BUFSIZ];
305*36dcc4a4SLionel Sambuc
306*36dcc4a4SLionel Sambuc /*
307*36dcc4a4SLionel Sambuc * LANGUAGE is a colon separated list of locale names.
308*36dcc4a4SLionel Sambuc */
309*36dcc4a4SLionel Sambuc
310*36dcc4a4SLionel Sambuc strlcpy(lpath_tmp, lpath, sizeof(lpath_tmp));
311*36dcc4a4SLionel Sambuc q = lpath_tmp;
312*36dcc4a4SLionel Sambuc /* CONSTCOND */
313*36dcc4a4SLionel Sambuc while (1) {
314*36dcc4a4SLionel Sambuc p = strsep(&q, ":");
315*36dcc4a4SLionel Sambuc if (!p)
316*36dcc4a4SLionel Sambuc break;
317*36dcc4a4SLionel Sambuc if (!*p)
318*36dcc4a4SLionel Sambuc continue;
319*36dcc4a4SLionel Sambuc
320*36dcc4a4SLionel Sambuc /* don't mess with default locales */
321*36dcc4a4SLionel Sambuc if (strcmp(p, "C") == 0 || strcmp(p, "POSIX") == 0)
322*36dcc4a4SLionel Sambuc return NULL;
323*36dcc4a4SLionel Sambuc
324*36dcc4a4SLionel Sambuc /* validate pathname */
325*36dcc4a4SLionel Sambuc if (strchr(p, '/') || strchr(category, '/'))
326*36dcc4a4SLionel Sambuc continue;
327*36dcc4a4SLionel Sambuc #if 1 /*?*/
328*36dcc4a4SLionel Sambuc if (strchr(domainname, '/'))
329*36dcc4a4SLionel Sambuc continue;
330*36dcc4a4SLionel Sambuc #endif
331*36dcc4a4SLionel Sambuc
332*36dcc4a4SLionel Sambuc snprintf(buf, len, "%s/%s/%s/%s.mo", dir, p,
333*36dcc4a4SLionel Sambuc category, domainname);
334*36dcc4a4SLionel Sambuc if (stat(buf, &st) < 0)
335*36dcc4a4SLionel Sambuc continue;
336*36dcc4a4SLionel Sambuc if ((st.st_mode & S_IFMT) != S_IFREG)
337*36dcc4a4SLionel Sambuc continue;
338*36dcc4a4SLionel Sambuc
339*36dcc4a4SLionel Sambuc if (mapit(buf, db) == 0)
340*36dcc4a4SLionel Sambuc return buf;
341*36dcc4a4SLionel Sambuc }
342*36dcc4a4SLionel Sambuc
343*36dcc4a4SLionel Sambuc return NULL;
344*36dcc4a4SLionel Sambuc }
345*36dcc4a4SLionel Sambuc
346*36dcc4a4SLionel Sambuc static uint32_t
flip(uint32_t v,uint32_t magic)347*36dcc4a4SLionel Sambuc flip(uint32_t v, uint32_t magic)
348*36dcc4a4SLionel Sambuc {
349*36dcc4a4SLionel Sambuc
350*36dcc4a4SLionel Sambuc if (magic == MO_MAGIC)
351*36dcc4a4SLionel Sambuc return v;
352*36dcc4a4SLionel Sambuc else if (magic == MO_MAGIC_SWAPPED) {
353*36dcc4a4SLionel Sambuc v = ((v >> 24) & 0xff) | ((v >> 8) & 0xff00) |
354*36dcc4a4SLionel Sambuc ((v << 8) & 0xff0000) | ((v << 24) & 0xff000000);
355*36dcc4a4SLionel Sambuc return v;
356*36dcc4a4SLionel Sambuc } else {
357*36dcc4a4SLionel Sambuc abort();
358*36dcc4a4SLionel Sambuc /*NOTREACHED*/
359*36dcc4a4SLionel Sambuc }
360*36dcc4a4SLionel Sambuc }
361*36dcc4a4SLionel Sambuc
362*36dcc4a4SLionel Sambuc static int
validate(void * arg,struct mohandle * mohandle)363*36dcc4a4SLionel Sambuc validate(void *arg, struct mohandle *mohandle)
364*36dcc4a4SLionel Sambuc {
365*36dcc4a4SLionel Sambuc char *p;
366*36dcc4a4SLionel Sambuc
367*36dcc4a4SLionel Sambuc p = (char *)arg;
368*36dcc4a4SLionel Sambuc if (p < (char *)mohandle->addr ||
369*36dcc4a4SLionel Sambuc p > (char *)mohandle->addr + mohandle->len)
370*36dcc4a4SLionel Sambuc return 0;
371*36dcc4a4SLionel Sambuc else
372*36dcc4a4SLionel Sambuc return 1;
373*36dcc4a4SLionel Sambuc }
374*36dcc4a4SLionel Sambuc
375*36dcc4a4SLionel Sambuc /*
376*36dcc4a4SLionel Sambuc * calculate the step value if the hash value is conflicted.
377*36dcc4a4SLionel Sambuc */
378*36dcc4a4SLionel Sambuc static __inline uint32_t
calc_collision_step(uint32_t hashval,uint32_t hashsize)379*36dcc4a4SLionel Sambuc calc_collision_step(uint32_t hashval, uint32_t hashsize)
380*36dcc4a4SLionel Sambuc {
381*36dcc4a4SLionel Sambuc _DIAGASSERT(hashsize>2);
382*36dcc4a4SLionel Sambuc return (hashval % (hashsize - 2)) + 1;
383*36dcc4a4SLionel Sambuc }
384*36dcc4a4SLionel Sambuc
385*36dcc4a4SLionel Sambuc /*
386*36dcc4a4SLionel Sambuc * calculate the next index while conflicting.
387*36dcc4a4SLionel Sambuc */
388*36dcc4a4SLionel Sambuc static __inline uint32_t
calc_next_index(uint32_t curidx,uint32_t hashsize,uint32_t step)389*36dcc4a4SLionel Sambuc calc_next_index(uint32_t curidx, uint32_t hashsize, uint32_t step)
390*36dcc4a4SLionel Sambuc {
391*36dcc4a4SLionel Sambuc return curidx+step - (curidx >= hashsize-step ? hashsize : 0);
392*36dcc4a4SLionel Sambuc }
393*36dcc4a4SLionel Sambuc
394*36dcc4a4SLionel Sambuc static int
get_sysdep_string_table(struct mosysdepstr_h ** table_h,uint32_t * ofstable,uint32_t nstrings,uint32_t magic,char * base)395*36dcc4a4SLionel Sambuc get_sysdep_string_table(struct mosysdepstr_h **table_h, uint32_t *ofstable,
396*36dcc4a4SLionel Sambuc uint32_t nstrings, uint32_t magic, char *base)
397*36dcc4a4SLionel Sambuc {
398*36dcc4a4SLionel Sambuc unsigned int i;
399*36dcc4a4SLionel Sambuc int j, count;
400*36dcc4a4SLionel Sambuc size_t l;
401*36dcc4a4SLionel Sambuc struct mosysdepstr *table;
402*36dcc4a4SLionel Sambuc
403*36dcc4a4SLionel Sambuc for (i=0; i<nstrings; i++) {
404*36dcc4a4SLionel Sambuc /* get mosysdepstr record */
405*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
406*36dcc4a4SLionel Sambuc table = (struct mosysdepstr *)(base + flip(ofstable[i], magic));
407*36dcc4a4SLionel Sambuc /* count number of segments */
408*36dcc4a4SLionel Sambuc count = 0;
409*36dcc4a4SLionel Sambuc while (flip(table->segs[count++].ref, magic) != MO_LASTSEG)
410*36dcc4a4SLionel Sambuc ;
411*36dcc4a4SLionel Sambuc /* get table */
412*36dcc4a4SLionel Sambuc l = sizeof(struct mosysdepstr_h) +
413*36dcc4a4SLionel Sambuc sizeof(struct mosysdepsegentry_h) * (count-1);
414*36dcc4a4SLionel Sambuc table_h[i] = (struct mosysdepstr_h *)malloc(l);
415*36dcc4a4SLionel Sambuc if (!table_h[i])
416*36dcc4a4SLionel Sambuc return -1;
417*36dcc4a4SLionel Sambuc memset(table_h[i], 0, l);
418*36dcc4a4SLionel Sambuc table_h[i]->off = (const char *)(base + flip(table->off, magic));
419*36dcc4a4SLionel Sambuc for (j=0; j<count; j++) {
420*36dcc4a4SLionel Sambuc table_h[i]->segs[j].len =
421*36dcc4a4SLionel Sambuc flip(table->segs[j].len, magic);
422*36dcc4a4SLionel Sambuc table_h[i]->segs[j].ref =
423*36dcc4a4SLionel Sambuc flip(table->segs[j].ref, magic);
424*36dcc4a4SLionel Sambuc }
425*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
426*36dcc4a4SLionel Sambuc table = (struct mosysdepstr *)&table->segs[count];
427*36dcc4a4SLionel Sambuc }
428*36dcc4a4SLionel Sambuc return 0;
429*36dcc4a4SLionel Sambuc }
430*36dcc4a4SLionel Sambuc
431*36dcc4a4SLionel Sambuc static int
expand_sysdep(struct mohandle * mohandle,struct mosysdepstr_h * str)432*36dcc4a4SLionel Sambuc expand_sysdep(struct mohandle *mohandle, struct mosysdepstr_h *str)
433*36dcc4a4SLionel Sambuc {
434*36dcc4a4SLionel Sambuc int i;
435*36dcc4a4SLionel Sambuc const char *src;
436*36dcc4a4SLionel Sambuc char *dst;
437*36dcc4a4SLionel Sambuc
438*36dcc4a4SLionel Sambuc /* check whether already expanded */
439*36dcc4a4SLionel Sambuc if (str->expanded)
440*36dcc4a4SLionel Sambuc return 0;
441*36dcc4a4SLionel Sambuc
442*36dcc4a4SLionel Sambuc /* calc total length */
443*36dcc4a4SLionel Sambuc str->expanded_len = 1;
444*36dcc4a4SLionel Sambuc for (i=0; /*CONSTCOND*/1; i++) {
445*36dcc4a4SLionel Sambuc str->expanded_len += str->segs[i].len;
446*36dcc4a4SLionel Sambuc if (str->segs[i].ref == MO_LASTSEG)
447*36dcc4a4SLionel Sambuc break;
448*36dcc4a4SLionel Sambuc str->expanded_len +=
449*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_segs[str->segs[i].ref].len;
450*36dcc4a4SLionel Sambuc }
451*36dcc4a4SLionel Sambuc /* expand */
452*36dcc4a4SLionel Sambuc str->expanded = malloc(str->expanded_len);
453*36dcc4a4SLionel Sambuc if (!str->expanded)
454*36dcc4a4SLionel Sambuc return -1;
455*36dcc4a4SLionel Sambuc src = str->off;
456*36dcc4a4SLionel Sambuc dst = str->expanded;
457*36dcc4a4SLionel Sambuc for (i=0; /*CONSTCOND*/1; i++) {
458*36dcc4a4SLionel Sambuc memcpy(dst, src, str->segs[i].len);
459*36dcc4a4SLionel Sambuc src += str->segs[i].len;
460*36dcc4a4SLionel Sambuc dst += str->segs[i].len;
461*36dcc4a4SLionel Sambuc if (str->segs[i].ref == MO_LASTSEG)
462*36dcc4a4SLionel Sambuc break;
463*36dcc4a4SLionel Sambuc memcpy(dst, mohandle->mo.mo_sysdep_segs[str->segs[i].ref].str,
464*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_segs[str->segs[i].ref].len);
465*36dcc4a4SLionel Sambuc dst += mohandle->mo.mo_sysdep_segs[str->segs[i].ref].len;
466*36dcc4a4SLionel Sambuc }
467*36dcc4a4SLionel Sambuc *dst = '\0';
468*36dcc4a4SLionel Sambuc
469*36dcc4a4SLionel Sambuc return 0;
470*36dcc4a4SLionel Sambuc }
471*36dcc4a4SLionel Sambuc
472*36dcc4a4SLionel Sambuc static void
insert_to_hash(uint32_t * htable,uint32_t hsize,const char * str,uint32_t ref)473*36dcc4a4SLionel Sambuc insert_to_hash(uint32_t *htable, uint32_t hsize, const char *str, uint32_t ref)
474*36dcc4a4SLionel Sambuc {
475*36dcc4a4SLionel Sambuc uint32_t hashval, idx, step;
476*36dcc4a4SLionel Sambuc
477*36dcc4a4SLionel Sambuc hashval = __intl_string_hash(str);
478*36dcc4a4SLionel Sambuc step = calc_collision_step(hashval, hsize);
479*36dcc4a4SLionel Sambuc idx = hashval % hsize;
480*36dcc4a4SLionel Sambuc
481*36dcc4a4SLionel Sambuc while (htable[idx])
482*36dcc4a4SLionel Sambuc idx = calc_next_index(idx, hsize, step);
483*36dcc4a4SLionel Sambuc
484*36dcc4a4SLionel Sambuc htable[idx] = ref;
485*36dcc4a4SLionel Sambuc }
486*36dcc4a4SLionel Sambuc
487*36dcc4a4SLionel Sambuc static int
setup_sysdep_stuffs(struct mo * mo,struct mohandle * mohandle,char * base)488*36dcc4a4SLionel Sambuc setup_sysdep_stuffs(struct mo *mo, struct mohandle *mohandle, char *base)
489*36dcc4a4SLionel Sambuc {
490*36dcc4a4SLionel Sambuc uint32_t magic;
491*36dcc4a4SLionel Sambuc struct moentry *stable;
492*36dcc4a4SLionel Sambuc size_t l;
493*36dcc4a4SLionel Sambuc unsigned int i;
494*36dcc4a4SLionel Sambuc char *v;
495*36dcc4a4SLionel Sambuc uint32_t *ofstable;
496*36dcc4a4SLionel Sambuc
497*36dcc4a4SLionel Sambuc magic = mo->mo_magic;
498*36dcc4a4SLionel Sambuc
499*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_nsegs = flip(mo->mo_sysdep_nsegs, magic);
500*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_nstring = flip(mo->mo_sysdep_nstring, magic);
501*36dcc4a4SLionel Sambuc
502*36dcc4a4SLionel Sambuc if (mohandle->mo.mo_sysdep_nstring == 0)
503*36dcc4a4SLionel Sambuc return 0;
504*36dcc4a4SLionel Sambuc
505*36dcc4a4SLionel Sambuc /* check hash size */
506*36dcc4a4SLionel Sambuc if (mohandle->mo.mo_hsize <= 2 ||
507*36dcc4a4SLionel Sambuc mohandle->mo.mo_hsize <
508*36dcc4a4SLionel Sambuc (mohandle->mo.mo_nstring + mohandle->mo.mo_sysdep_nstring))
509*36dcc4a4SLionel Sambuc return -1;
510*36dcc4a4SLionel Sambuc
511*36dcc4a4SLionel Sambuc /* get sysdep segments */
512*36dcc4a4SLionel Sambuc l = sizeof(struct mosysdepsegs_h) * mohandle->mo.mo_sysdep_nsegs;
513*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_segs = (struct mosysdepsegs_h *)malloc(l);
514*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_sysdep_segs)
515*36dcc4a4SLionel Sambuc return -1;
516*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
517*36dcc4a4SLionel Sambuc stable = (struct moentry *)(base + flip(mo->mo_sysdep_segoff, magic));
518*36dcc4a4SLionel Sambuc for (i=0; i<mohandle->mo.mo_sysdep_nsegs; i++) {
519*36dcc4a4SLionel Sambuc v = base + flip(stable[i].off, magic);
520*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_segs[i].str =
521*36dcc4a4SLionel Sambuc __intl_sysdep_get_string_by_tag(
522*36dcc4a4SLionel Sambuc v,
523*36dcc4a4SLionel Sambuc &mohandle->mo.mo_sysdep_segs[i].len);
524*36dcc4a4SLionel Sambuc }
525*36dcc4a4SLionel Sambuc
526*36dcc4a4SLionel Sambuc /* get sysdep string table */
527*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_otable =
528*36dcc4a4SLionel Sambuc (struct mosysdepstr_h **)calloc(mohandle->mo.mo_sysdep_nstring,
529*36dcc4a4SLionel Sambuc sizeof(struct mosysdepstr_h *));
530*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_sysdep_otable)
531*36dcc4a4SLionel Sambuc return -1;
532*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
533*36dcc4a4SLionel Sambuc ofstable = (uint32_t *)(base + flip(mo->mo_sysdep_otable, magic));
534*36dcc4a4SLionel Sambuc if (get_sysdep_string_table(mohandle->mo.mo_sysdep_otable, ofstable,
535*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_nstring, magic,
536*36dcc4a4SLionel Sambuc base))
537*36dcc4a4SLionel Sambuc return -1;
538*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_ttable =
539*36dcc4a4SLionel Sambuc (struct mosysdepstr_h **)calloc(mohandle->mo.mo_sysdep_nstring,
540*36dcc4a4SLionel Sambuc sizeof(struct mosysdepstr_h *));
541*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_sysdep_ttable)
542*36dcc4a4SLionel Sambuc return -1;
543*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
544*36dcc4a4SLionel Sambuc ofstable = (uint32_t *)(base + flip(mo->mo_sysdep_ttable, magic));
545*36dcc4a4SLionel Sambuc if (get_sysdep_string_table(mohandle->mo.mo_sysdep_ttable, ofstable,
546*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_nstring, magic,
547*36dcc4a4SLionel Sambuc base))
548*36dcc4a4SLionel Sambuc return -1;
549*36dcc4a4SLionel Sambuc
550*36dcc4a4SLionel Sambuc /* update hash */
551*36dcc4a4SLionel Sambuc for (i=0; i<mohandle->mo.mo_sysdep_nstring; i++) {
552*36dcc4a4SLionel Sambuc if (expand_sysdep(mohandle, mohandle->mo.mo_sysdep_otable[i]))
553*36dcc4a4SLionel Sambuc return -1;
554*36dcc4a4SLionel Sambuc insert_to_hash(mohandle->mo.mo_htable,
555*36dcc4a4SLionel Sambuc mohandle->mo.mo_hsize,
556*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_otable[i]->expanded,
557*36dcc4a4SLionel Sambuc (i+1) | MO_HASH_SYSDEP_MASK);
558*36dcc4a4SLionel Sambuc }
559*36dcc4a4SLionel Sambuc
560*36dcc4a4SLionel Sambuc return 0;
561*36dcc4a4SLionel Sambuc }
562*36dcc4a4SLionel Sambuc
563*36dcc4a4SLionel Sambuc int
mapit(const char * path,struct domainbinding * db)564*36dcc4a4SLionel Sambuc mapit(const char *path, struct domainbinding *db)
565*36dcc4a4SLionel Sambuc {
566*36dcc4a4SLionel Sambuc int fd;
567*36dcc4a4SLionel Sambuc struct stat st;
568*36dcc4a4SLionel Sambuc char *base;
569*36dcc4a4SLionel Sambuc uint32_t magic, revision, flags = 0;
570*36dcc4a4SLionel Sambuc struct moentry *otable, *ttable;
571*36dcc4a4SLionel Sambuc const uint32_t *htable;
572*36dcc4a4SLionel Sambuc struct moentry_h *p;
573*36dcc4a4SLionel Sambuc struct mo *mo;
574*36dcc4a4SLionel Sambuc size_t l, headerlen;
575*36dcc4a4SLionel Sambuc unsigned int i;
576*36dcc4a4SLionel Sambuc char *v;
577*36dcc4a4SLionel Sambuc struct mohandle *mohandle = &db->mohandle;
578*36dcc4a4SLionel Sambuc
579*36dcc4a4SLionel Sambuc if (mohandle->addr && mohandle->addr != MAP_FAILED &&
580*36dcc4a4SLionel Sambuc mohandle->mo.mo_magic)
581*36dcc4a4SLionel Sambuc return 0; /*already opened*/
582*36dcc4a4SLionel Sambuc
583*36dcc4a4SLionel Sambuc unmapit(db);
584*36dcc4a4SLionel Sambuc
585*36dcc4a4SLionel Sambuc #if 0
586*36dcc4a4SLionel Sambuc if (secure_path(path) != 0)
587*36dcc4a4SLionel Sambuc goto fail;
588*36dcc4a4SLionel Sambuc #endif
589*36dcc4a4SLionel Sambuc if (stat(path, &st) < 0)
590*36dcc4a4SLionel Sambuc goto fail;
591*36dcc4a4SLionel Sambuc if ((st.st_mode & S_IFMT) != S_IFREG || st.st_size > GETTEXT_MMAP_MAX)
592*36dcc4a4SLionel Sambuc goto fail;
593*36dcc4a4SLionel Sambuc fd = open(path, O_RDONLY);
594*36dcc4a4SLionel Sambuc if (fd < 0)
595*36dcc4a4SLionel Sambuc goto fail;
596*36dcc4a4SLionel Sambuc if (read(fd, &magic, sizeof(magic)) != sizeof(magic) ||
597*36dcc4a4SLionel Sambuc (magic != MO_MAGIC && magic != MO_MAGIC_SWAPPED)) {
598*36dcc4a4SLionel Sambuc close(fd);
599*36dcc4a4SLionel Sambuc goto fail;
600*36dcc4a4SLionel Sambuc }
601*36dcc4a4SLionel Sambuc if (read(fd, &revision, sizeof(revision)) != sizeof(revision)) {
602*36dcc4a4SLionel Sambuc close(fd);
603*36dcc4a4SLionel Sambuc goto fail;
604*36dcc4a4SLionel Sambuc }
605*36dcc4a4SLionel Sambuc switch (flip(revision, magic)) {
606*36dcc4a4SLionel Sambuc case MO_MAKE_REV(0, 0):
607*36dcc4a4SLionel Sambuc break;
608*36dcc4a4SLionel Sambuc case MO_MAKE_REV(0, 1):
609*36dcc4a4SLionel Sambuc case MO_MAKE_REV(1, 1):
610*36dcc4a4SLionel Sambuc flags |= MO_F_SYSDEP;
611*36dcc4a4SLionel Sambuc break;
612*36dcc4a4SLionel Sambuc default:
613*36dcc4a4SLionel Sambuc close(fd);
614*36dcc4a4SLionel Sambuc goto fail;
615*36dcc4a4SLionel Sambuc }
616*36dcc4a4SLionel Sambuc mohandle->addr = mmap(NULL, (size_t)st.st_size, PROT_READ,
617*36dcc4a4SLionel Sambuc MAP_FILE | MAP_SHARED, fd, (off_t)0);
618*36dcc4a4SLionel Sambuc if (!mohandle->addr || mohandle->addr == MAP_FAILED) {
619*36dcc4a4SLionel Sambuc close(fd);
620*36dcc4a4SLionel Sambuc goto fail;
621*36dcc4a4SLionel Sambuc }
622*36dcc4a4SLionel Sambuc close(fd);
623*36dcc4a4SLionel Sambuc mohandle->len = (size_t)st.st_size;
624*36dcc4a4SLionel Sambuc
625*36dcc4a4SLionel Sambuc base = mohandle->addr;
626*36dcc4a4SLionel Sambuc mo = (struct mo *)mohandle->addr;
627*36dcc4a4SLionel Sambuc
628*36dcc4a4SLionel Sambuc /* flip endian. do not flip magic number! */
629*36dcc4a4SLionel Sambuc mohandle->mo.mo_magic = mo->mo_magic;
630*36dcc4a4SLionel Sambuc mohandle->mo.mo_revision = flip(mo->mo_revision, magic);
631*36dcc4a4SLionel Sambuc mohandle->mo.mo_nstring = flip(mo->mo_nstring, magic);
632*36dcc4a4SLionel Sambuc mohandle->mo.mo_hsize = flip(mo->mo_hsize, magic);
633*36dcc4a4SLionel Sambuc mohandle->mo.mo_flags = flags;
634*36dcc4a4SLionel Sambuc
635*36dcc4a4SLionel Sambuc /* validate otable/ttable */
636*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
637*36dcc4a4SLionel Sambuc otable = (struct moentry *)(base + flip(mo->mo_otable, magic));
638*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
639*36dcc4a4SLionel Sambuc ttable = (struct moentry *)(base + flip(mo->mo_ttable, magic));
640*36dcc4a4SLionel Sambuc if (!validate(otable, mohandle) ||
641*36dcc4a4SLionel Sambuc !validate(&otable[mohandle->mo.mo_nstring], mohandle)) {
642*36dcc4a4SLionel Sambuc unmapit(db);
643*36dcc4a4SLionel Sambuc goto fail;
644*36dcc4a4SLionel Sambuc }
645*36dcc4a4SLionel Sambuc if (!validate(ttable, mohandle) ||
646*36dcc4a4SLionel Sambuc !validate(&ttable[mohandle->mo.mo_nstring], mohandle)) {
647*36dcc4a4SLionel Sambuc unmapit(db);
648*36dcc4a4SLionel Sambuc goto fail;
649*36dcc4a4SLionel Sambuc }
650*36dcc4a4SLionel Sambuc
651*36dcc4a4SLionel Sambuc /* allocate [ot]table, and convert to normal pointer representation. */
652*36dcc4a4SLionel Sambuc l = sizeof(struct moentry_h) * mohandle->mo.mo_nstring;
653*36dcc4a4SLionel Sambuc mohandle->mo.mo_otable = (struct moentry_h *)malloc(l);
654*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_otable) {
655*36dcc4a4SLionel Sambuc unmapit(db);
656*36dcc4a4SLionel Sambuc goto fail;
657*36dcc4a4SLionel Sambuc }
658*36dcc4a4SLionel Sambuc mohandle->mo.mo_ttable = (struct moentry_h *)malloc(l);
659*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_ttable) {
660*36dcc4a4SLionel Sambuc unmapit(db);
661*36dcc4a4SLionel Sambuc goto fail;
662*36dcc4a4SLionel Sambuc }
663*36dcc4a4SLionel Sambuc p = mohandle->mo.mo_otable;
664*36dcc4a4SLionel Sambuc for (i = 0; i < mohandle->mo.mo_nstring; i++) {
665*36dcc4a4SLionel Sambuc p[i].len = flip(otable[i].len, magic);
666*36dcc4a4SLionel Sambuc p[i].off = base + flip(otable[i].off, magic);
667*36dcc4a4SLionel Sambuc
668*36dcc4a4SLionel Sambuc if (!validate(p[i].off, mohandle) ||
669*36dcc4a4SLionel Sambuc !validate(p[i].off + p[i].len + 1, mohandle)) {
670*36dcc4a4SLionel Sambuc unmapit(db);
671*36dcc4a4SLionel Sambuc goto fail;
672*36dcc4a4SLionel Sambuc }
673*36dcc4a4SLionel Sambuc }
674*36dcc4a4SLionel Sambuc p = mohandle->mo.mo_ttable;
675*36dcc4a4SLionel Sambuc for (i = 0; i < mohandle->mo.mo_nstring; i++) {
676*36dcc4a4SLionel Sambuc p[i].len = flip(ttable[i].len, magic);
677*36dcc4a4SLionel Sambuc p[i].off = base + flip(ttable[i].off, magic);
678*36dcc4a4SLionel Sambuc
679*36dcc4a4SLionel Sambuc if (!validate(p[i].off, mohandle) ||
680*36dcc4a4SLionel Sambuc !validate(p[i].off + p[i].len + 1, mohandle)) {
681*36dcc4a4SLionel Sambuc unmapit(db);
682*36dcc4a4SLionel Sambuc goto fail;
683*36dcc4a4SLionel Sambuc }
684*36dcc4a4SLionel Sambuc }
685*36dcc4a4SLionel Sambuc /* allocate htable, and convert it to the host order. */
686*36dcc4a4SLionel Sambuc if (mohandle->mo.mo_hsize > 2) {
687*36dcc4a4SLionel Sambuc l = sizeof(uint32_t) * mohandle->mo.mo_hsize;
688*36dcc4a4SLionel Sambuc mohandle->mo.mo_htable = (uint32_t *)malloc(l);
689*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_htable) {
690*36dcc4a4SLionel Sambuc unmapit(db);
691*36dcc4a4SLionel Sambuc goto fail;
692*36dcc4a4SLionel Sambuc }
693*36dcc4a4SLionel Sambuc /* LINTED: ignore the alignment problem. */
694*36dcc4a4SLionel Sambuc htable = (const uint32_t *)(base+flip(mo->mo_hoffset, magic));
695*36dcc4a4SLionel Sambuc for (i=0; i < mohandle->mo.mo_hsize; i++) {
696*36dcc4a4SLionel Sambuc mohandle->mo.mo_htable[i] = flip(htable[i], magic);
697*36dcc4a4SLionel Sambuc if (mohandle->mo.mo_htable[i] >=
698*36dcc4a4SLionel Sambuc mohandle->mo.mo_nstring+1) {
699*36dcc4a4SLionel Sambuc /* illegal string number. */
700*36dcc4a4SLionel Sambuc unmapit(db);
701*36dcc4a4SLionel Sambuc goto fail;
702*36dcc4a4SLionel Sambuc }
703*36dcc4a4SLionel Sambuc }
704*36dcc4a4SLionel Sambuc }
705*36dcc4a4SLionel Sambuc /* grab MIME-header and charset field */
706*36dcc4a4SLionel Sambuc mohandle->mo.mo_header = lookup("", db, &headerlen);
707*36dcc4a4SLionel Sambuc if (mohandle->mo.mo_header)
708*36dcc4a4SLionel Sambuc v = strstr(mohandle->mo.mo_header, "charset=");
709*36dcc4a4SLionel Sambuc else
710*36dcc4a4SLionel Sambuc v = NULL;
711*36dcc4a4SLionel Sambuc if (v) {
712*36dcc4a4SLionel Sambuc mohandle->mo.mo_charset = strdup(v + 8);
713*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_charset)
714*36dcc4a4SLionel Sambuc goto fail;
715*36dcc4a4SLionel Sambuc v = strchr(mohandle->mo.mo_charset, '\n');
716*36dcc4a4SLionel Sambuc if (v)
717*36dcc4a4SLionel Sambuc *v = '\0';
718*36dcc4a4SLionel Sambuc }
719*36dcc4a4SLionel Sambuc if (!mohandle->mo.mo_header ||
720*36dcc4a4SLionel Sambuc _gettext_parse_plural(&mohandle->mo.mo_plural,
721*36dcc4a4SLionel Sambuc &mohandle->mo.mo_nplurals,
722*36dcc4a4SLionel Sambuc mohandle->mo.mo_header, headerlen))
723*36dcc4a4SLionel Sambuc mohandle->mo.mo_plural = NULL;
724*36dcc4a4SLionel Sambuc
725*36dcc4a4SLionel Sambuc /*
726*36dcc4a4SLionel Sambuc * XXX check charset, reject it if we are unable to support the charset
727*36dcc4a4SLionel Sambuc * with the current locale.
728*36dcc4a4SLionel Sambuc * for example, if we are using euc-jp locale and we are looking at
729*36dcc4a4SLionel Sambuc * *.mo file encoded by euc-kr (charset=euc-kr), we should reject
730*36dcc4a4SLionel Sambuc * the *.mo file as we cannot support it.
731*36dcc4a4SLionel Sambuc */
732*36dcc4a4SLionel Sambuc
733*36dcc4a4SLionel Sambuc /* system dependent string support */
734*36dcc4a4SLionel Sambuc if ((mohandle->mo.mo_flags & MO_F_SYSDEP) != 0) {
735*36dcc4a4SLionel Sambuc if (setup_sysdep_stuffs(mo, mohandle, base)) {
736*36dcc4a4SLionel Sambuc unmapit(db);
737*36dcc4a4SLionel Sambuc goto fail;
738*36dcc4a4SLionel Sambuc }
739*36dcc4a4SLionel Sambuc }
740*36dcc4a4SLionel Sambuc
741*36dcc4a4SLionel Sambuc return 0;
742*36dcc4a4SLionel Sambuc
743*36dcc4a4SLionel Sambuc fail:
744*36dcc4a4SLionel Sambuc return -1;
745*36dcc4a4SLionel Sambuc }
746*36dcc4a4SLionel Sambuc
747*36dcc4a4SLionel Sambuc static void
free_sysdep_table(struct mosysdepstr_h ** table,uint32_t nstring)748*36dcc4a4SLionel Sambuc free_sysdep_table(struct mosysdepstr_h **table, uint32_t nstring)
749*36dcc4a4SLionel Sambuc {
750*36dcc4a4SLionel Sambuc
751*36dcc4a4SLionel Sambuc if (! table)
752*36dcc4a4SLionel Sambuc return;
753*36dcc4a4SLionel Sambuc
754*36dcc4a4SLionel Sambuc for (uint32_t i = 0; i < nstring; i++) {
755*36dcc4a4SLionel Sambuc if (table[i]) {
756*36dcc4a4SLionel Sambuc free(table[i]->expanded);
757*36dcc4a4SLionel Sambuc free(table[i]);
758*36dcc4a4SLionel Sambuc }
759*36dcc4a4SLionel Sambuc }
760*36dcc4a4SLionel Sambuc free(table);
761*36dcc4a4SLionel Sambuc }
762*36dcc4a4SLionel Sambuc
763*36dcc4a4SLionel Sambuc static int
unmapit(struct domainbinding * db)764*36dcc4a4SLionel Sambuc unmapit(struct domainbinding *db)
765*36dcc4a4SLionel Sambuc {
766*36dcc4a4SLionel Sambuc struct mohandle *mohandle = &db->mohandle;
767*36dcc4a4SLionel Sambuc
768*36dcc4a4SLionel Sambuc /* unmap if there's already mapped region */
769*36dcc4a4SLionel Sambuc if (mohandle->addr && mohandle->addr != MAP_FAILED)
770*36dcc4a4SLionel Sambuc munmap(mohandle->addr, mohandle->len);
771*36dcc4a4SLionel Sambuc mohandle->addr = NULL;
772*36dcc4a4SLionel Sambuc free(mohandle->mo.mo_otable);
773*36dcc4a4SLionel Sambuc free(mohandle->mo.mo_ttable);
774*36dcc4a4SLionel Sambuc free(mohandle->mo.mo_charset);
775*36dcc4a4SLionel Sambuc free(mohandle->mo.mo_htable);
776*36dcc4a4SLionel Sambuc free(mohandle->mo.mo_sysdep_segs);
777*36dcc4a4SLionel Sambuc free_sysdep_table(mohandle->mo.mo_sysdep_otable,
778*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_nstring);
779*36dcc4a4SLionel Sambuc free_sysdep_table(mohandle->mo.mo_sysdep_ttable,
780*36dcc4a4SLionel Sambuc mohandle->mo.mo_sysdep_nstring);
781*36dcc4a4SLionel Sambuc _gettext_free_plural(mohandle->mo.mo_plural);
782*36dcc4a4SLionel Sambuc memset(&mohandle->mo, 0, sizeof(mohandle->mo));
783*36dcc4a4SLionel Sambuc return 0;
784*36dcc4a4SLionel Sambuc }
785*36dcc4a4SLionel Sambuc
786*36dcc4a4SLionel Sambuc /* ARGSUSED */
787*36dcc4a4SLionel Sambuc static const char *
lookup_hash(const char * msgid,struct domainbinding * db,size_t * rlen)788*36dcc4a4SLionel Sambuc lookup_hash(const char *msgid, struct domainbinding *db, size_t *rlen)
789*36dcc4a4SLionel Sambuc {
790*36dcc4a4SLionel Sambuc struct mohandle *mohandle = &db->mohandle;
791*36dcc4a4SLionel Sambuc uint32_t idx, hashval, step, strno;
792*36dcc4a4SLionel Sambuc size_t len;
793*36dcc4a4SLionel Sambuc struct mosysdepstr_h *sysdep_otable, *sysdep_ttable;
794*36dcc4a4SLionel Sambuc
795*36dcc4a4SLionel Sambuc if (mohandle->mo.mo_hsize <= 2 || mohandle->mo.mo_htable == NULL)
796*36dcc4a4SLionel Sambuc return NULL;
797*36dcc4a4SLionel Sambuc
798*36dcc4a4SLionel Sambuc hashval = __intl_string_hash(msgid);
799*36dcc4a4SLionel Sambuc step = calc_collision_step(hashval, mohandle->mo.mo_hsize);
800*36dcc4a4SLionel Sambuc idx = hashval % mohandle->mo.mo_hsize;
801*36dcc4a4SLionel Sambuc len = strlen(msgid);
802*36dcc4a4SLionel Sambuc while (/*CONSTCOND*/1) {
803*36dcc4a4SLionel Sambuc strno = mohandle->mo.mo_htable[idx];
804*36dcc4a4SLionel Sambuc if (strno == 0) {
805*36dcc4a4SLionel Sambuc /* unexpected miss */
806*36dcc4a4SLionel Sambuc return NULL;
807*36dcc4a4SLionel Sambuc }
808*36dcc4a4SLionel Sambuc strno--;
809*36dcc4a4SLionel Sambuc if ((strno & MO_HASH_SYSDEP_MASK) == 0) {
810*36dcc4a4SLionel Sambuc /* system independent strings */
811*36dcc4a4SLionel Sambuc if (len <= mohandle->mo.mo_otable[strno].len &&
812*36dcc4a4SLionel Sambuc !strcmp(msgid, mohandle->mo.mo_otable[strno].off)) {
813*36dcc4a4SLionel Sambuc /* hit */
814*36dcc4a4SLionel Sambuc if (rlen)
815*36dcc4a4SLionel Sambuc *rlen =
816*36dcc4a4SLionel Sambuc mohandle->mo.mo_ttable[strno].len;
817*36dcc4a4SLionel Sambuc return mohandle->mo.mo_ttable[strno].off;
818*36dcc4a4SLionel Sambuc }
819*36dcc4a4SLionel Sambuc } else {
820*36dcc4a4SLionel Sambuc /* system dependent strings */
821*36dcc4a4SLionel Sambuc strno &= ~MO_HASH_SYSDEP_MASK;
822*36dcc4a4SLionel Sambuc sysdep_otable = mohandle->mo.mo_sysdep_otable[strno];
823*36dcc4a4SLionel Sambuc sysdep_ttable = mohandle->mo.mo_sysdep_ttable[strno];
824*36dcc4a4SLionel Sambuc if (len <= sysdep_otable->expanded_len &&
825*36dcc4a4SLionel Sambuc !strcmp(msgid, sysdep_otable->expanded)) {
826*36dcc4a4SLionel Sambuc /* hit */
827*36dcc4a4SLionel Sambuc if (expand_sysdep(mohandle, sysdep_ttable))
828*36dcc4a4SLionel Sambuc /* memory exhausted */
829*36dcc4a4SLionel Sambuc return NULL;
830*36dcc4a4SLionel Sambuc if (rlen)
831*36dcc4a4SLionel Sambuc *rlen = sysdep_ttable->expanded_len;
832*36dcc4a4SLionel Sambuc return sysdep_ttable->expanded;
833*36dcc4a4SLionel Sambuc }
834*36dcc4a4SLionel Sambuc }
835*36dcc4a4SLionel Sambuc idx = calc_next_index(idx, mohandle->mo.mo_hsize, step);
836*36dcc4a4SLionel Sambuc }
837*36dcc4a4SLionel Sambuc /*NOTREACHED*/
838*36dcc4a4SLionel Sambuc }
839*36dcc4a4SLionel Sambuc
840*36dcc4a4SLionel Sambuc static const char *
lookup_bsearch(const char * msgid,struct domainbinding * db,size_t * rlen)841*36dcc4a4SLionel Sambuc lookup_bsearch(const char *msgid, struct domainbinding *db, size_t *rlen)
842*36dcc4a4SLionel Sambuc {
843*36dcc4a4SLionel Sambuc int top, bottom, middle, omiddle;
844*36dcc4a4SLionel Sambuc int n;
845*36dcc4a4SLionel Sambuc struct mohandle *mohandle = &db->mohandle;
846*36dcc4a4SLionel Sambuc
847*36dcc4a4SLionel Sambuc top = 0;
848*36dcc4a4SLionel Sambuc bottom = mohandle->mo.mo_nstring;
849*36dcc4a4SLionel Sambuc omiddle = -1;
850*36dcc4a4SLionel Sambuc /* CONSTCOND */
851*36dcc4a4SLionel Sambuc while (1) {
852*36dcc4a4SLionel Sambuc if (top > bottom)
853*36dcc4a4SLionel Sambuc break;
854*36dcc4a4SLionel Sambuc middle = (top + bottom) / 2;
855*36dcc4a4SLionel Sambuc /* avoid possible infinite loop, when the data is not sorted */
856*36dcc4a4SLionel Sambuc if (omiddle == middle)
857*36dcc4a4SLionel Sambuc break;
858*36dcc4a4SLionel Sambuc if ((size_t)middle >= mohandle->mo.mo_nstring)
859*36dcc4a4SLionel Sambuc break;
860*36dcc4a4SLionel Sambuc
861*36dcc4a4SLionel Sambuc n = strcmp(msgid, mohandle->mo.mo_otable[middle].off);
862*36dcc4a4SLionel Sambuc if (n == 0) {
863*36dcc4a4SLionel Sambuc if (rlen)
864*36dcc4a4SLionel Sambuc *rlen = mohandle->mo.mo_ttable[middle].len;
865*36dcc4a4SLionel Sambuc return (const char *)mohandle->mo.mo_ttable[middle].off;
866*36dcc4a4SLionel Sambuc }
867*36dcc4a4SLionel Sambuc else if (n < 0)
868*36dcc4a4SLionel Sambuc bottom = middle;
869*36dcc4a4SLionel Sambuc else
870*36dcc4a4SLionel Sambuc top = middle;
871*36dcc4a4SLionel Sambuc omiddle = middle;
872*36dcc4a4SLionel Sambuc }
873*36dcc4a4SLionel Sambuc
874*36dcc4a4SLionel Sambuc return NULL;
875*36dcc4a4SLionel Sambuc }
876*36dcc4a4SLionel Sambuc
877*36dcc4a4SLionel Sambuc static const char *
lookup(const char * msgid,struct domainbinding * db,size_t * rlen)878*36dcc4a4SLionel Sambuc lookup(const char *msgid, struct domainbinding *db, size_t *rlen)
879*36dcc4a4SLionel Sambuc {
880*36dcc4a4SLionel Sambuc const char *v;
881*36dcc4a4SLionel Sambuc
882*36dcc4a4SLionel Sambuc v = lookup_hash(msgid, db, rlen);
883*36dcc4a4SLionel Sambuc if (v)
884*36dcc4a4SLionel Sambuc return v;
885*36dcc4a4SLionel Sambuc
886*36dcc4a4SLionel Sambuc return lookup_bsearch(msgid, db, rlen);
887*36dcc4a4SLionel Sambuc }
888*36dcc4a4SLionel Sambuc
889*36dcc4a4SLionel Sambuc static const char *
get_lang_env(const char * category_name)890*36dcc4a4SLionel Sambuc get_lang_env(const char *category_name)
891*36dcc4a4SLionel Sambuc {
892*36dcc4a4SLionel Sambuc const char *lang;
893*36dcc4a4SLionel Sambuc
894*36dcc4a4SLionel Sambuc /*
895*36dcc4a4SLionel Sambuc * 1. see LANGUAGE variable first.
896*36dcc4a4SLionel Sambuc *
897*36dcc4a4SLionel Sambuc * LANGUAGE is a GNU extension.
898*36dcc4a4SLionel Sambuc * It's a colon separated list of locale names.
899*36dcc4a4SLionel Sambuc */
900*36dcc4a4SLionel Sambuc lang = getenv("LANGUAGE");
901*36dcc4a4SLionel Sambuc if (lang)
902*36dcc4a4SLionel Sambuc return lang;
903*36dcc4a4SLionel Sambuc
904*36dcc4a4SLionel Sambuc /*
905*36dcc4a4SLionel Sambuc * 2. if LANGUAGE isn't set, see LC_ALL, LC_xxx, LANG.
906*36dcc4a4SLionel Sambuc *
907*36dcc4a4SLionel Sambuc * It's essentially setlocale(LC_xxx, NULL).
908*36dcc4a4SLionel Sambuc */
909*36dcc4a4SLionel Sambuc lang = getenv("LC_ALL");
910*36dcc4a4SLionel Sambuc if (!lang)
911*36dcc4a4SLionel Sambuc lang = getenv(category_name);
912*36dcc4a4SLionel Sambuc if (!lang)
913*36dcc4a4SLionel Sambuc lang = getenv("LANG");
914*36dcc4a4SLionel Sambuc
915*36dcc4a4SLionel Sambuc if (!lang)
916*36dcc4a4SLionel Sambuc return 0; /* error */
917*36dcc4a4SLionel Sambuc
918*36dcc4a4SLionel Sambuc return split_locale(lang);
919*36dcc4a4SLionel Sambuc }
920*36dcc4a4SLionel Sambuc
921*36dcc4a4SLionel Sambuc static const char *
get_indexed_string(const char * str,size_t len,unsigned long idx)922*36dcc4a4SLionel Sambuc get_indexed_string(const char *str, size_t len, unsigned long idx)
923*36dcc4a4SLionel Sambuc {
924*36dcc4a4SLionel Sambuc while (idx > 0) {
925*36dcc4a4SLionel Sambuc if (len <= 1)
926*36dcc4a4SLionel Sambuc return str;
927*36dcc4a4SLionel Sambuc if (*str == '\0')
928*36dcc4a4SLionel Sambuc idx--;
929*36dcc4a4SLionel Sambuc if (len > 0) {
930*36dcc4a4SLionel Sambuc str++;
931*36dcc4a4SLionel Sambuc len--;
932*36dcc4a4SLionel Sambuc }
933*36dcc4a4SLionel Sambuc }
934*36dcc4a4SLionel Sambuc return str;
935*36dcc4a4SLionel Sambuc }
936*36dcc4a4SLionel Sambuc
937*36dcc4a4SLionel Sambuc #define _NGETTEXT_DEFAULT(msgid1, msgid2, n) \
938*36dcc4a4SLionel Sambuc ((char *)__UNCONST((n) == 1 ? (msgid1) : (msgid2)))
939*36dcc4a4SLionel Sambuc
940*36dcc4a4SLionel Sambuc char *
dcngettext(const char * domainname,const char * msgid1,const char * msgid2,unsigned long int n,int category)941*36dcc4a4SLionel Sambuc dcngettext(const char *domainname, const char *msgid1, const char *msgid2,
942*36dcc4a4SLionel Sambuc unsigned long int n, int category)
943*36dcc4a4SLionel Sambuc {
944*36dcc4a4SLionel Sambuc const char *msgid;
945*36dcc4a4SLionel Sambuc char path[PATH_MAX];
946*36dcc4a4SLionel Sambuc const char *lpath;
947*36dcc4a4SLionel Sambuc static char olpath[PATH_MAX];
948*36dcc4a4SLionel Sambuc const char *cname = NULL;
949*36dcc4a4SLionel Sambuc const char *v;
950*36dcc4a4SLionel Sambuc static char *ocname = NULL;
951*36dcc4a4SLionel Sambuc static char *odomainname = NULL;
952*36dcc4a4SLionel Sambuc struct domainbinding *db;
953*36dcc4a4SLionel Sambuc unsigned long plural_index = 0;
954*36dcc4a4SLionel Sambuc size_t len;
955*36dcc4a4SLionel Sambuc
956*36dcc4a4SLionel Sambuc if (!domainname)
957*36dcc4a4SLionel Sambuc domainname = __current_domainname;
958*36dcc4a4SLionel Sambuc cname = lookup_category(category);
959*36dcc4a4SLionel Sambuc if (!domainname || !cname)
960*36dcc4a4SLionel Sambuc goto fail;
961*36dcc4a4SLionel Sambuc
962*36dcc4a4SLionel Sambuc lpath = get_lang_env(cname);
963*36dcc4a4SLionel Sambuc if (!lpath)
964*36dcc4a4SLionel Sambuc goto fail;
965*36dcc4a4SLionel Sambuc
966*36dcc4a4SLionel Sambuc for (db = __bindings; db; db = db->next)
967*36dcc4a4SLionel Sambuc if (strcmp(db->domainname, domainname) == 0)
968*36dcc4a4SLionel Sambuc break;
969*36dcc4a4SLionel Sambuc if (!db) {
970*36dcc4a4SLionel Sambuc if (!bindtextdomain(domainname, _PATH_TEXTDOMAIN))
971*36dcc4a4SLionel Sambuc goto fail;
972*36dcc4a4SLionel Sambuc db = __bindings;
973*36dcc4a4SLionel Sambuc }
974*36dcc4a4SLionel Sambuc
975*36dcc4a4SLionel Sambuc /* resolve relative path */
976*36dcc4a4SLionel Sambuc /* XXX not necessary? */
977*36dcc4a4SLionel Sambuc if (db->path[0] != '/') {
978*36dcc4a4SLionel Sambuc char buf[PATH_MAX];
979*36dcc4a4SLionel Sambuc
980*36dcc4a4SLionel Sambuc if (getcwd(buf, sizeof(buf)) == 0)
981*36dcc4a4SLionel Sambuc goto fail;
982*36dcc4a4SLionel Sambuc if (strlcat(buf, "/", sizeof(buf)) >= sizeof(buf))
983*36dcc4a4SLionel Sambuc goto fail;
984*36dcc4a4SLionel Sambuc if (strlcat(buf, db->path, sizeof(buf)) >= sizeof(buf))
985*36dcc4a4SLionel Sambuc goto fail;
986*36dcc4a4SLionel Sambuc strlcpy(db->path, buf, sizeof(db->path));
987*36dcc4a4SLionel Sambuc }
988*36dcc4a4SLionel Sambuc
989*36dcc4a4SLionel Sambuc /* don't bother looking it up if the values are the same */
990*36dcc4a4SLionel Sambuc if (odomainname && strcmp(domainname, odomainname) == 0 &&
991*36dcc4a4SLionel Sambuc ocname && strcmp(cname, ocname) == 0 && strcmp(lpath, olpath) == 0 &&
992*36dcc4a4SLionel Sambuc db->mohandle.mo.mo_magic)
993*36dcc4a4SLionel Sambuc goto found;
994*36dcc4a4SLionel Sambuc
995*36dcc4a4SLionel Sambuc /* try to find appropriate file, from $LANGUAGE */
996*36dcc4a4SLionel Sambuc if (lookup_mofile(path, sizeof(path), db->path, lpath, cname,
997*36dcc4a4SLionel Sambuc domainname, db) == NULL)
998*36dcc4a4SLionel Sambuc goto fail;
999*36dcc4a4SLionel Sambuc
1000*36dcc4a4SLionel Sambuc free(odomainname);
1001*36dcc4a4SLionel Sambuc free(ocname);
1002*36dcc4a4SLionel Sambuc
1003*36dcc4a4SLionel Sambuc odomainname = strdup(domainname);
1004*36dcc4a4SLionel Sambuc ocname = strdup(cname);
1005*36dcc4a4SLionel Sambuc if (!odomainname || !ocname) {
1006*36dcc4a4SLionel Sambuc free(odomainname);
1007*36dcc4a4SLionel Sambuc free(ocname);
1008*36dcc4a4SLionel Sambuc
1009*36dcc4a4SLionel Sambuc odomainname = ocname = NULL;
1010*36dcc4a4SLionel Sambuc }
1011*36dcc4a4SLionel Sambuc else
1012*36dcc4a4SLionel Sambuc strlcpy(olpath, lpath, sizeof(olpath));
1013*36dcc4a4SLionel Sambuc
1014*36dcc4a4SLionel Sambuc found:
1015*36dcc4a4SLionel Sambuc if (db->mohandle.mo.mo_plural) {
1016*36dcc4a4SLionel Sambuc plural_index =
1017*36dcc4a4SLionel Sambuc _gettext_calculate_plural(db->mohandle.mo.mo_plural, n);
1018*36dcc4a4SLionel Sambuc if (plural_index >= db->mohandle.mo.mo_nplurals)
1019*36dcc4a4SLionel Sambuc plural_index = 0;
1020*36dcc4a4SLionel Sambuc msgid = msgid1;
1021*36dcc4a4SLionel Sambuc } else
1022*36dcc4a4SLionel Sambuc msgid = _NGETTEXT_DEFAULT(msgid1, msgid2, n);
1023*36dcc4a4SLionel Sambuc
1024*36dcc4a4SLionel Sambuc if (msgid == NULL)
1025*36dcc4a4SLionel Sambuc return NULL;
1026*36dcc4a4SLionel Sambuc
1027*36dcc4a4SLionel Sambuc v = lookup(msgid, db, &len);
1028*36dcc4a4SLionel Sambuc if (v) {
1029*36dcc4a4SLionel Sambuc if (db->mohandle.mo.mo_plural)
1030*36dcc4a4SLionel Sambuc v = get_indexed_string(v, len, plural_index);
1031*36dcc4a4SLionel Sambuc /*
1032*36dcc4a4SLionel Sambuc * convert the translated message's encoding.
1033*36dcc4a4SLionel Sambuc *
1034*36dcc4a4SLionel Sambuc * special case:
1035*36dcc4a4SLionel Sambuc * a result of gettext("") shouldn't need any conversion.
1036*36dcc4a4SLionel Sambuc */
1037*36dcc4a4SLionel Sambuc if (msgid[0])
1038*36dcc4a4SLionel Sambuc v = __gettext_iconv(v, db);
1039*36dcc4a4SLionel Sambuc
1040*36dcc4a4SLionel Sambuc /*
1041*36dcc4a4SLionel Sambuc * Given the amount of printf-format security issues, it may
1042*36dcc4a4SLionel Sambuc * be a good idea to validate if the original msgid and the
1043*36dcc4a4SLionel Sambuc * translated message format string carry the same printf-like
1044*36dcc4a4SLionel Sambuc * format identifiers.
1045*36dcc4a4SLionel Sambuc */
1046*36dcc4a4SLionel Sambuc
1047*36dcc4a4SLionel Sambuc msgid = v;
1048*36dcc4a4SLionel Sambuc }
1049*36dcc4a4SLionel Sambuc
1050*36dcc4a4SLionel Sambuc return (char *)__UNCONST(msgid);
1051*36dcc4a4SLionel Sambuc
1052*36dcc4a4SLionel Sambuc fail:
1053*36dcc4a4SLionel Sambuc return _NGETTEXT_DEFAULT(msgid1, msgid2, n);
1054*36dcc4a4SLionel Sambuc }
1055