1*a8fa202aSchristos /* $NetBSD: loadmsgcat.c,v 1.1.1.1 2016/01/10 21:36:18 christos Exp $ */
2*a8fa202aSchristos
3*a8fa202aSchristos /* Load needed message catalogs.
4*a8fa202aSchristos Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
5*a8fa202aSchristos
6*a8fa202aSchristos This program is free software; you can redistribute it and/or modify it
7*a8fa202aSchristos under the terms of the GNU Library General Public License as published
8*a8fa202aSchristos by the Free Software Foundation; either version 2, or (at your option)
9*a8fa202aSchristos any later version.
10*a8fa202aSchristos
11*a8fa202aSchristos This program is distributed in the hope that it will be useful,
12*a8fa202aSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13*a8fa202aSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14*a8fa202aSchristos Library General Public License for more details.
15*a8fa202aSchristos
16*a8fa202aSchristos You should have received a copy of the GNU Library General Public
17*a8fa202aSchristos License along with this program; if not, write to the Free Software
18*a8fa202aSchristos Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19*a8fa202aSchristos USA. */
20*a8fa202aSchristos
21*a8fa202aSchristos /* Tell glibc's <string.h> to provide a prototype for mempcpy().
22*a8fa202aSchristos This must come before <config.h> because <config.h> may include
23*a8fa202aSchristos <features.h>, and once <features.h> has been included, it's too late. */
24*a8fa202aSchristos #ifndef _GNU_SOURCE
25*a8fa202aSchristos # define _GNU_SOURCE 1
26*a8fa202aSchristos #endif
27*a8fa202aSchristos
28*a8fa202aSchristos #ifdef HAVE_CONFIG_H
29*a8fa202aSchristos # include <config.h>
30*a8fa202aSchristos #endif
31*a8fa202aSchristos
32*a8fa202aSchristos #include <ctype.h>
33*a8fa202aSchristos #include <errno.h>
34*a8fa202aSchristos #include <fcntl.h>
35*a8fa202aSchristos #include <sys/types.h>
36*a8fa202aSchristos #include <sys/stat.h>
37*a8fa202aSchristos
38*a8fa202aSchristos #ifdef __GNUC__
39*a8fa202aSchristos # define alloca __builtin_alloca
40*a8fa202aSchristos # define HAVE_ALLOCA 1
41*a8fa202aSchristos #else
42*a8fa202aSchristos # if defined HAVE_ALLOCA_H || defined _LIBC
43*a8fa202aSchristos # include <alloca.h>
44*a8fa202aSchristos # else
45*a8fa202aSchristos # ifdef _AIX
46*a8fa202aSchristos #pragma alloca
47*a8fa202aSchristos # else
48*a8fa202aSchristos # ifndef alloca
49*a8fa202aSchristos char *alloca ();
50*a8fa202aSchristos # endif
51*a8fa202aSchristos # endif
52*a8fa202aSchristos # endif
53*a8fa202aSchristos #endif
54*a8fa202aSchristos
55*a8fa202aSchristos #include <stdlib.h>
56*a8fa202aSchristos #include <string.h>
57*a8fa202aSchristos
58*a8fa202aSchristos #if defined HAVE_UNISTD_H || defined _LIBC
59*a8fa202aSchristos # include <unistd.h>
60*a8fa202aSchristos #endif
61*a8fa202aSchristos
62*a8fa202aSchristos #ifdef _LIBC
63*a8fa202aSchristos # include <langinfo.h>
64*a8fa202aSchristos # include <locale.h>
65*a8fa202aSchristos #endif
66*a8fa202aSchristos
67*a8fa202aSchristos #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
68*a8fa202aSchristos || (defined _LIBC && defined _POSIX_MAPPED_FILES)
69*a8fa202aSchristos # include <sys/mman.h>
70*a8fa202aSchristos # undef HAVE_MMAP
71*a8fa202aSchristos # define HAVE_MMAP 1
72*a8fa202aSchristos #else
73*a8fa202aSchristos # undef HAVE_MMAP
74*a8fa202aSchristos #endif
75*a8fa202aSchristos
76*a8fa202aSchristos #include "gmo.h"
77*a8fa202aSchristos #include "gettextP.h"
78*a8fa202aSchristos #include "plural-exp.h"
79*a8fa202aSchristos
80*a8fa202aSchristos #ifdef _LIBC
81*a8fa202aSchristos # include "../locale/localeinfo.h"
82*a8fa202aSchristos #endif
83*a8fa202aSchristos
84*a8fa202aSchristos /* @@ end of prolog @@ */
85*a8fa202aSchristos
86*a8fa202aSchristos #ifdef _LIBC
87*a8fa202aSchristos /* Rename the non ISO C functions. This is required by the standard
88*a8fa202aSchristos because some ISO C functions will require linking with this object
89*a8fa202aSchristos file and the name space must not be polluted. */
90*a8fa202aSchristos # define open __open
91*a8fa202aSchristos # define close __close
92*a8fa202aSchristos # define read __read
93*a8fa202aSchristos # define mmap __mmap
94*a8fa202aSchristos # define munmap __munmap
95*a8fa202aSchristos #endif
96*a8fa202aSchristos
97*a8fa202aSchristos /* For those losing systems which don't have `alloca' we have to add
98*a8fa202aSchristos some additional code emulating it. */
99*a8fa202aSchristos #ifdef HAVE_ALLOCA
100*a8fa202aSchristos # define freea(p) /* nothing */
101*a8fa202aSchristos #else
102*a8fa202aSchristos # define alloca(n) malloc (n)
103*a8fa202aSchristos # define freea(p) free (p)
104*a8fa202aSchristos #endif
105*a8fa202aSchristos
106*a8fa202aSchristos /* For systems that distinguish between text and binary I/O.
107*a8fa202aSchristos O_BINARY is usually declared in <fcntl.h>. */
108*a8fa202aSchristos #if !defined O_BINARY && defined _O_BINARY
109*a8fa202aSchristos /* For MSC-compatible compilers. */
110*a8fa202aSchristos # define O_BINARY _O_BINARY
111*a8fa202aSchristos # define O_TEXT _O_TEXT
112*a8fa202aSchristos #endif
113*a8fa202aSchristos #ifdef __BEOS__
114*a8fa202aSchristos /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
115*a8fa202aSchristos # undef O_BINARY
116*a8fa202aSchristos # undef O_TEXT
117*a8fa202aSchristos #endif
118*a8fa202aSchristos /* On reasonable systems, binary I/O is the default. */
119*a8fa202aSchristos #ifndef O_BINARY
120*a8fa202aSchristos # define O_BINARY 0
121*a8fa202aSchristos #endif
122*a8fa202aSchristos
123*a8fa202aSchristos /* We need a sign, whether a new catalog was loaded, which can be associated
124*a8fa202aSchristos with all translations. This is important if the translations are
125*a8fa202aSchristos cached by one of GCC's features. */
126*a8fa202aSchristos int _nl_msg_cat_cntr;
127*a8fa202aSchristos
128*a8fa202aSchristos
129*a8fa202aSchristos /* Initialize the codeset dependent parts of an opened message catalog.
130*a8fa202aSchristos Return the header entry. */
131*a8fa202aSchristos const char *
132*a8fa202aSchristos internal_function
_nl_init_domain_conv(domain_file,domain,domainbinding)133*a8fa202aSchristos _nl_init_domain_conv (domain_file, domain, domainbinding)
134*a8fa202aSchristos struct loaded_l10nfile *domain_file;
135*a8fa202aSchristos struct loaded_domain *domain;
136*a8fa202aSchristos struct binding *domainbinding;
137*a8fa202aSchristos {
138*a8fa202aSchristos /* Find out about the character set the file is encoded with.
139*a8fa202aSchristos This can be found (in textual form) in the entry "". If this
140*a8fa202aSchristos entry does not exist or if this does not contain the `charset='
141*a8fa202aSchristos information, we will assume the charset matches the one the
142*a8fa202aSchristos current locale and we don't have to perform any conversion. */
143*a8fa202aSchristos char *nullentry;
144*a8fa202aSchristos size_t nullentrylen;
145*a8fa202aSchristos
146*a8fa202aSchristos /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
147*a8fa202aSchristos domain->codeset_cntr =
148*a8fa202aSchristos (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
149*a8fa202aSchristos #ifdef _LIBC
150*a8fa202aSchristos domain->conv = (__gconv_t) -1;
151*a8fa202aSchristos #else
152*a8fa202aSchristos # if HAVE_ICONV
153*a8fa202aSchristos domain->conv = (iconv_t) -1;
154*a8fa202aSchristos # endif
155*a8fa202aSchristos #endif
156*a8fa202aSchristos domain->conv_tab = NULL;
157*a8fa202aSchristos
158*a8fa202aSchristos /* Get the header entry. */
159*a8fa202aSchristos nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
160*a8fa202aSchristos
161*a8fa202aSchristos if (nullentry != NULL)
162*a8fa202aSchristos {
163*a8fa202aSchristos #if defined _LIBC || HAVE_ICONV
164*a8fa202aSchristos const char *charsetstr;
165*a8fa202aSchristos
166*a8fa202aSchristos charsetstr = strstr (nullentry, "charset=");
167*a8fa202aSchristos if (charsetstr != NULL)
168*a8fa202aSchristos {
169*a8fa202aSchristos size_t len;
170*a8fa202aSchristos char *charset;
171*a8fa202aSchristos const char *outcharset;
172*a8fa202aSchristos
173*a8fa202aSchristos charsetstr += strlen ("charset=");
174*a8fa202aSchristos len = strcspn (charsetstr, " \t\n");
175*a8fa202aSchristos
176*a8fa202aSchristos charset = (char *) alloca (len + 1);
177*a8fa202aSchristos # if defined _LIBC || HAVE_MEMPCPY
178*a8fa202aSchristos *((char *) mempcpy (charset, charsetstr, len)) = '\0';
179*a8fa202aSchristos # else
180*a8fa202aSchristos memcpy (charset, charsetstr, len);
181*a8fa202aSchristos charset[len] = '\0';
182*a8fa202aSchristos # endif
183*a8fa202aSchristos
184*a8fa202aSchristos /* The output charset should normally be determined by the
185*a8fa202aSchristos locale. But sometimes the locale is not used or not correctly
186*a8fa202aSchristos set up, so we provide a possibility for the user to override
187*a8fa202aSchristos this. Moreover, the value specified through
188*a8fa202aSchristos bind_textdomain_codeset overrides both. */
189*a8fa202aSchristos if (domainbinding != NULL && domainbinding->codeset != NULL)
190*a8fa202aSchristos outcharset = domainbinding->codeset;
191*a8fa202aSchristos else
192*a8fa202aSchristos {
193*a8fa202aSchristos outcharset = getenv ("OUTPUT_CHARSET");
194*a8fa202aSchristos if (outcharset == NULL || outcharset[0] == '\0')
195*a8fa202aSchristos {
196*a8fa202aSchristos # ifdef _LIBC
197*a8fa202aSchristos outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
198*a8fa202aSchristos # else
199*a8fa202aSchristos # if HAVE_ICONV
200*a8fa202aSchristos extern const char *locale_charset PARAMS ((void));
201*a8fa202aSchristos outcharset = locale_charset ();
202*a8fa202aSchristos # endif
203*a8fa202aSchristos # endif
204*a8fa202aSchristos }
205*a8fa202aSchristos }
206*a8fa202aSchristos
207*a8fa202aSchristos # ifdef _LIBC
208*a8fa202aSchristos /* We always want to use transliteration. */
209*a8fa202aSchristos outcharset = norm_add_slashes (outcharset, "TRANSLIT");
210*a8fa202aSchristos charset = norm_add_slashes (charset, NULL);
211*a8fa202aSchristos if (__gconv_open (outcharset, charset, &domain->conv,
212*a8fa202aSchristos GCONV_AVOID_NOCONV)
213*a8fa202aSchristos != __GCONV_OK)
214*a8fa202aSchristos domain->conv = (__gconv_t) -1;
215*a8fa202aSchristos # else
216*a8fa202aSchristos # if HAVE_ICONV
217*a8fa202aSchristos /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
218*a8fa202aSchristos we want to use transliteration. */
219*a8fa202aSchristos # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
220*a8fa202aSchristos || _LIBICONV_VERSION >= 0x0105
221*a8fa202aSchristos len = strlen (outcharset);
222*a8fa202aSchristos {
223*a8fa202aSchristos char *tmp = (char *) alloca (len + 10 + 1);
224*a8fa202aSchristos memcpy (tmp, outcharset, len);
225*a8fa202aSchristos memcpy (tmp + len, "//TRANSLIT", 10 + 1);
226*a8fa202aSchristos outcharset = tmp;
227*a8fa202aSchristos }
228*a8fa202aSchristos # endif
229*a8fa202aSchristos domain->conv = iconv_open (outcharset, charset);
230*a8fa202aSchristos # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
231*a8fa202aSchristos || _LIBICONV_VERSION >= 0x0105
232*a8fa202aSchristos freea (outcharset);
233*a8fa202aSchristos # endif
234*a8fa202aSchristos # endif
235*a8fa202aSchristos # endif
236*a8fa202aSchristos
237*a8fa202aSchristos freea (charset);
238*a8fa202aSchristos }
239*a8fa202aSchristos #endif /* _LIBC || HAVE_ICONV */
240*a8fa202aSchristos }
241*a8fa202aSchristos
242*a8fa202aSchristos return nullentry;
243*a8fa202aSchristos }
244*a8fa202aSchristos
245*a8fa202aSchristos /* Frees the codeset dependent parts of an opened message catalog. */
246*a8fa202aSchristos void
247*a8fa202aSchristos internal_function
_nl_free_domain_conv(domain)248*a8fa202aSchristos _nl_free_domain_conv (domain)
249*a8fa202aSchristos struct loaded_domain *domain;
250*a8fa202aSchristos {
251*a8fa202aSchristos if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
252*a8fa202aSchristos free (domain->conv_tab);
253*a8fa202aSchristos
254*a8fa202aSchristos #ifdef _LIBC
255*a8fa202aSchristos if (domain->conv != (__gconv_t) -1)
256*a8fa202aSchristos __gconv_close (domain->conv);
257*a8fa202aSchristos #else
258*a8fa202aSchristos # if HAVE_ICONV
259*a8fa202aSchristos if (domain->conv != (iconv_t) -1)
260*a8fa202aSchristos iconv_close (domain->conv);
261*a8fa202aSchristos # endif
262*a8fa202aSchristos #endif
263*a8fa202aSchristos }
264*a8fa202aSchristos
265*a8fa202aSchristos /* Load the message catalogs specified by FILENAME. If it is no valid
266*a8fa202aSchristos message catalog do nothing. */
267*a8fa202aSchristos void
268*a8fa202aSchristos internal_function
_nl_load_domain(domain_file,domainbinding)269*a8fa202aSchristos _nl_load_domain (domain_file, domainbinding)
270*a8fa202aSchristos struct loaded_l10nfile *domain_file;
271*a8fa202aSchristos struct binding *domainbinding;
272*a8fa202aSchristos {
273*a8fa202aSchristos int fd;
274*a8fa202aSchristos size_t size;
275*a8fa202aSchristos #ifdef _LIBC
276*a8fa202aSchristos struct stat64 st;
277*a8fa202aSchristos #else
278*a8fa202aSchristos struct stat st;
279*a8fa202aSchristos #endif
280*a8fa202aSchristos struct mo_file_header *data = (struct mo_file_header *) -1;
281*a8fa202aSchristos int use_mmap = 0;
282*a8fa202aSchristos struct loaded_domain *domain;
283*a8fa202aSchristos const char *nullentry;
284*a8fa202aSchristos
285*a8fa202aSchristos domain_file->decided = 1;
286*a8fa202aSchristos domain_file->data = NULL;
287*a8fa202aSchristos
288*a8fa202aSchristos /* Note that it would be useless to store domainbinding in domain_file
289*a8fa202aSchristos because domainbinding might be == NULL now but != NULL later (after
290*a8fa202aSchristos a call to bind_textdomain_codeset). */
291*a8fa202aSchristos
292*a8fa202aSchristos /* If the record does not represent a valid locale the FILENAME
293*a8fa202aSchristos might be NULL. This can happen when according to the given
294*a8fa202aSchristos specification the locale file name is different for XPG and CEN
295*a8fa202aSchristos syntax. */
296*a8fa202aSchristos if (domain_file->filename == NULL)
297*a8fa202aSchristos return;
298*a8fa202aSchristos
299*a8fa202aSchristos /* Try to open the addressed file. */
300*a8fa202aSchristos fd = open (domain_file->filename, O_RDONLY | O_BINARY);
301*a8fa202aSchristos if (fd == -1)
302*a8fa202aSchristos return;
303*a8fa202aSchristos
304*a8fa202aSchristos /* We must know about the size of the file. */
305*a8fa202aSchristos if (
306*a8fa202aSchristos #ifdef _LIBC
307*a8fa202aSchristos __builtin_expect (fstat64 (fd, &st) != 0, 0)
308*a8fa202aSchristos #else
309*a8fa202aSchristos __builtin_expect (fstat (fd, &st) != 0, 0)
310*a8fa202aSchristos #endif
311*a8fa202aSchristos || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
312*a8fa202aSchristos || __builtin_expect (size < sizeof (struct mo_file_header), 0))
313*a8fa202aSchristos {
314*a8fa202aSchristos /* Something went wrong. */
315*a8fa202aSchristos close (fd);
316*a8fa202aSchristos return;
317*a8fa202aSchristos }
318*a8fa202aSchristos
319*a8fa202aSchristos #ifdef HAVE_MMAP
320*a8fa202aSchristos /* Now we are ready to load the file. If mmap() is available we try
321*a8fa202aSchristos this first. If not available or it failed we try to load it. */
322*a8fa202aSchristos data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
323*a8fa202aSchristos MAP_PRIVATE, fd, 0);
324*a8fa202aSchristos
325*a8fa202aSchristos if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
326*a8fa202aSchristos {
327*a8fa202aSchristos /* mmap() call was successful. */
328*a8fa202aSchristos close (fd);
329*a8fa202aSchristos use_mmap = 1;
330*a8fa202aSchristos }
331*a8fa202aSchristos #endif
332*a8fa202aSchristos
333*a8fa202aSchristos /* If the data is not yet available (i.e. mmap'ed) we try to load
334*a8fa202aSchristos it manually. */
335*a8fa202aSchristos if (data == (struct mo_file_header *) -1)
336*a8fa202aSchristos {
337*a8fa202aSchristos size_t to_read;
338*a8fa202aSchristos char *read_ptr;
339*a8fa202aSchristos
340*a8fa202aSchristos data = (struct mo_file_header *) malloc (size);
341*a8fa202aSchristos if (data == NULL)
342*a8fa202aSchristos return;
343*a8fa202aSchristos
344*a8fa202aSchristos to_read = size;
345*a8fa202aSchristos read_ptr = (char *) data;
346*a8fa202aSchristos do
347*a8fa202aSchristos {
348*a8fa202aSchristos long int nb = (long int) read (fd, read_ptr, to_read);
349*a8fa202aSchristos if (nb <= 0)
350*a8fa202aSchristos {
351*a8fa202aSchristos #ifdef EINTR
352*a8fa202aSchristos if (nb == -1 && errno == EINTR)
353*a8fa202aSchristos continue;
354*a8fa202aSchristos #endif
355*a8fa202aSchristos close (fd);
356*a8fa202aSchristos return;
357*a8fa202aSchristos }
358*a8fa202aSchristos read_ptr += nb;
359*a8fa202aSchristos to_read -= nb;
360*a8fa202aSchristos }
361*a8fa202aSchristos while (to_read > 0);
362*a8fa202aSchristos
363*a8fa202aSchristos close (fd);
364*a8fa202aSchristos }
365*a8fa202aSchristos
366*a8fa202aSchristos /* Using the magic number we can test whether it really is a message
367*a8fa202aSchristos catalog file. */
368*a8fa202aSchristos if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
369*a8fa202aSchristos 0))
370*a8fa202aSchristos {
371*a8fa202aSchristos /* The magic number is wrong: not a message catalog file. */
372*a8fa202aSchristos #ifdef HAVE_MMAP
373*a8fa202aSchristos if (use_mmap)
374*a8fa202aSchristos munmap ((caddr_t) data, size);
375*a8fa202aSchristos else
376*a8fa202aSchristos #endif
377*a8fa202aSchristos free (data);
378*a8fa202aSchristos return;
379*a8fa202aSchristos }
380*a8fa202aSchristos
381*a8fa202aSchristos domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
382*a8fa202aSchristos if (domain == NULL)
383*a8fa202aSchristos return;
384*a8fa202aSchristos domain_file->data = domain;
385*a8fa202aSchristos
386*a8fa202aSchristos domain->data = (char *) data;
387*a8fa202aSchristos domain->use_mmap = use_mmap;
388*a8fa202aSchristos domain->mmap_size = size;
389*a8fa202aSchristos domain->must_swap = data->magic != _MAGIC;
390*a8fa202aSchristos
391*a8fa202aSchristos /* Fill in the information about the available tables. */
392*a8fa202aSchristos switch (W (domain->must_swap, data->revision))
393*a8fa202aSchristos {
394*a8fa202aSchristos case 0:
395*a8fa202aSchristos domain->nstrings = W (domain->must_swap, data->nstrings);
396*a8fa202aSchristos domain->orig_tab = (struct string_desc *)
397*a8fa202aSchristos ((char *) data + W (domain->must_swap, data->orig_tab_offset));
398*a8fa202aSchristos domain->trans_tab = (struct string_desc *)
399*a8fa202aSchristos ((char *) data + W (domain->must_swap, data->trans_tab_offset));
400*a8fa202aSchristos domain->hash_size = W (domain->must_swap, data->hash_tab_size);
401*a8fa202aSchristos domain->hash_tab = (nls_uint32 *)
402*a8fa202aSchristos ((char *) data + W (domain->must_swap, data->hash_tab_offset));
403*a8fa202aSchristos break;
404*a8fa202aSchristos default:
405*a8fa202aSchristos /* This is an invalid revision. */
406*a8fa202aSchristos #ifdef HAVE_MMAP
407*a8fa202aSchristos if (use_mmap)
408*a8fa202aSchristos munmap ((caddr_t) data, size);
409*a8fa202aSchristos else
410*a8fa202aSchristos #endif
411*a8fa202aSchristos free (data);
412*a8fa202aSchristos free (domain);
413*a8fa202aSchristos domain_file->data = NULL;
414*a8fa202aSchristos return;
415*a8fa202aSchristos }
416*a8fa202aSchristos
417*a8fa202aSchristos /* Now initialize the character set converter from the character set
418*a8fa202aSchristos the file is encoded with (found in the header entry) to the domain's
419*a8fa202aSchristos specified character set or the locale's character set. */
420*a8fa202aSchristos nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
421*a8fa202aSchristos
422*a8fa202aSchristos /* Also look for a plural specification. */
423*a8fa202aSchristos EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
424*a8fa202aSchristos }
425*a8fa202aSchristos
426*a8fa202aSchristos
427*a8fa202aSchristos #ifdef _LIBC
428*a8fa202aSchristos void
429*a8fa202aSchristos internal_function
_nl_unload_domain(domain)430*a8fa202aSchristos _nl_unload_domain (domain)
431*a8fa202aSchristos struct loaded_domain *domain;
432*a8fa202aSchristos {
433*a8fa202aSchristos if (domain->plural != &__gettext_germanic_plural)
434*a8fa202aSchristos __gettext_free_exp (domain->plural);
435*a8fa202aSchristos
436*a8fa202aSchristos _nl_free_domain_conv (domain);
437*a8fa202aSchristos
438*a8fa202aSchristos # ifdef _POSIX_MAPPED_FILES
439*a8fa202aSchristos if (domain->use_mmap)
440*a8fa202aSchristos munmap ((caddr_t) domain->data, domain->mmap_size);
441*a8fa202aSchristos else
442*a8fa202aSchristos # endif /* _POSIX_MAPPED_FILES */
443*a8fa202aSchristos free ((void *) domain->data);
444*a8fa202aSchristos
445*a8fa202aSchristos free (domain);
446*a8fa202aSchristos }
447*a8fa202aSchristos #endif
448