xref: /netbsd-src/external/gpl2/grep/dist/intl/loadmsgcat.c (revision a8fa202a6440953be7b92a8960a811bff58203f4)
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