9 #include "locale_impl.h"
13 #include "fork_impl.h"
15 #define malloc __libc_malloc
16 #define calloc __libc_calloc
29 static void *volatile bindings
;
31 static char *gettextdir(const char *domainname
, size_t *dirlen
)
34 for (p
=bindings
; p
; p
=p
->next
) {
35 if (!strcmp(p
->domainname
, domainname
) && p
->active
) {
37 return (char *)p
->dirname
;
43 static volatile int lock
[1];
44 volatile int *const __gettext_lockptr
= lock
;
46 char *bindtextdomain(const char *domainname
, const char *dirname
)
48 struct binding
*p
, *q
;
50 if (!domainname
) return 0;
51 if (!dirname
) return gettextdir(domainname
, &(size_t){0});
53 size_t domlen
= strnlen(domainname
, NAME_MAX
+1);
54 size_t dirlen
= strnlen(dirname
, PATH_MAX
);
55 if (domlen
> NAME_MAX
|| dirlen
>= PATH_MAX
) {
62 for (p
=bindings
; p
; p
=p
->next
) {
63 if (!strcmp(p
->domainname
, domainname
) &&
64 !strcmp(p
->dirname
, dirname
)) {
70 p
= calloc(sizeof *p
+ domlen
+ dirlen
+ 2, 1);
77 p
->domainname
= p
->buf
;
78 p
->dirname
= p
->buf
+ domlen
+ 1;
79 memcpy(p
->domainname
, domainname
, domlen
+1);
80 memcpy(p
->dirname
, dirname
, dirlen
+1);
81 a_cas_p(&bindings
, bindings
, p
);
84 a_store(&p
->active
, 1);
86 for (q
=bindings
; q
; q
=q
->next
) {
87 if (!strcmp(q
->domainname
, domainname
) && q
!= p
)
88 a_store(&q
->active
, 0);
93 return (char *)p
->dirname
;
96 static const char catnames
[][12] = {
105 static const char catlens
[] = { 8, 10, 7, 10, 11, 11 };
111 const char *plural_rule
;
113 struct binding
*binding
;
114 const struct __locale_map
*lm
;
118 static char *dummy_gettextdomain()
123 weak_alias(dummy_gettextdomain
, __gettextdomain
);
125 char *dcngettext(const char *domainname
, const char *msgid1
, const char *msgid2
, unsigned long int n
, int category
)
127 static struct msgcat
*volatile cats
;
129 struct __locale_struct
*loc
= CURRENT_LOCALE
;
130 const struct __locale_map
*lm
;
133 int old_errno
= errno
;
135 /* match gnu gettext behaviour */
136 if (!msgid1
) goto notrans
;
138 if ((unsigned)category
>= LC_ALL
) goto notrans
;
140 if (!domainname
) domainname
= __gettextdomain();
142 domlen
= strnlen(domainname
, NAME_MAX
+1);
143 if (domlen
> NAME_MAX
) goto notrans
;
145 for (q
=bindings
; q
; q
=q
->next
)
146 if (!strcmp(q
->domainname
, domainname
) && q
->active
)
148 if (!q
) goto notrans
;
150 lm
= loc
->cat
[category
];
154 return (char *) ((n
== 1) ? msgid1
: msgid2
);
157 for (p
=cats
; p
; p
=p
->next
)
158 if (p
->binding
== q
&& p
->lm
== lm
&& p
->cat
== category
)
162 const char *dirname
, *locname
, *catname
, *modname
, *locp
;
163 size_t dirlen
, loclen
, catlen
, modlen
, alt_modlen
;
167 dirname
= q
->dirname
;
169 catname
= catnames
[category
];
172 loclen
= strlen(locname
);
173 catlen
= catlens
[category
];
175 /* Logically split @mod suffix from locale name. */
176 modname
= memchr(locname
, '@', loclen
);
177 if (!modname
) modname
= locname
+ loclen
;
178 alt_modlen
= modlen
= loclen
- (modname
-locname
);
179 loclen
= modname
-locname
;
181 /* Drop .charset identifier; it is not used. */
182 const char *csp
= memchr(locname
, '.', loclen
);
183 if (csp
) loclen
= csp
-locname
;
185 char name
[dirlen
+1 + loclen
+modlen
+1 + catlen
+1 + domlen
+3 + 1];
189 snprintf(name
, sizeof name
, "%s/%.*s%.*s/%s/%s.mo\0",
190 dirname
, (int)loclen
, locname
,
191 (int)alt_modlen
, modname
, catname
, domainname
);
192 if (map
= __map_file(name
, &map_size
)) break;
194 /* Try dropping @mod, _YY, then both. */
197 } else if ((locp
= memchr(locname
, '_', loclen
))) {
198 loclen
= locp
-locname
;
204 if (!map
) goto notrans
;
206 p
= calloc(sizeof *p
, 1);
208 __munmap((void *)map
, map_size
);
215 p
->map_size
= map_size
;
217 const char *rule
= "n!=1;";
218 unsigned long np
= 2;
219 const char *r
= __mo_lookup(p
->map
, p
->map_size
, "");
221 while (r
&& strncmp(r
, "Plural-Forms:", 13)) {
227 while (isspace(*r
)) r
++;
228 if (!strncmp(r
, "nplurals=", 9)) {
229 np
= strtoul(r
+9, &z
, 10);
232 while (*r
&& *r
!= ';') r
++;
235 while (isspace(*r
)) r
++;
236 if (!strncmp(r
, "plural=", 7))
241 p
->plural_rule
= rule
;
246 } while (a_cas_p(&cats
, old_cats
, p
) != old_cats
);
249 const char *trans
= __mo_lookup(p
->map
, p
->map_size
, msgid1
);
250 if (!trans
) goto notrans
;
252 /* Non-plural-processing gettext forms pass a null pointer as
253 * msgid2 to request that dcngettext suppress plural processing. */
255 if (msgid2
&& p
->nplurals
) {
256 unsigned long plural
= __pleval(p
->plural_rule
, n
);
257 if (plural
> p
->nplurals
) goto notrans
;
259 size_t rem
= p
->map_size
- (trans
- (char *)p
->map
);
260 size_t l
= strnlen(trans
, rem
);
267 return (char *)trans
;
270 char *dcgettext(const char *domainname
, const char *msgid
, int category
)
272 return dcngettext(domainname
, msgid
, 0, 1, category
);
275 char *dngettext(const char *domainname
, const char *msgid1
, const char *msgid2
, unsigned long int n
)
277 return dcngettext(domainname
, msgid1
, msgid2
, n
, LC_MESSAGES
);
280 char *dgettext(const char *domainname
, const char *msgid
)
282 return dcngettext(domainname
, msgid
, 0, 1, LC_MESSAGES
);