Statistics
| Revision:

root / intl / bindtextdom.c @ 1

History | View | Annotate | Download (9.58 KB)

1
/* Implementation of the bindtextdomain(3) function
2
   Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc.
3

4
   This program is free software; you can redistribute it and/or modify it
5
   under the terms of the GNU Library General Public License as published
6
   by the Free Software Foundation; either version 2, or (at your option)
7
   any later version.
8

9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
   Library General Public License for more details.
13

14
   You should have received a copy of the GNU Library General Public
15
   License along with this program; if not, write to the Free Software
16
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17
   USA.  */
18

    
19
#ifdef HAVE_CONFIG_H
20
# include <config.h>
21
#endif
22

    
23
#include <stddef.h>
24
#include <stdlib.h>
25
#include <string.h>
26

    
27
#ifdef _LIBC
28
# include <libintl.h>
29
#else
30
# include "libgnuintl.h"
31
#endif
32
#include "gettextP.h"
33

    
34
#ifdef _LIBC
35
/* We have to handle multi-threaded applications.  */
36
# include <bits/libc-lock.h>
37
#else
38
/* Provide dummy implementation if this is outside glibc.  */
39
# define __libc_rwlock_define(CLASS, NAME)
40
# define __libc_rwlock_wrlock(NAME)
41
# define __libc_rwlock_unlock(NAME)
42
#endif
43

    
44
/* The internal variables in the standalone libintl.a must have different
45
   names than the internal variables in GNU libc, otherwise programs
46
   using libintl.a cannot be linked statically.  */
47
#if !defined _LIBC
48
# define _nl_default_dirname libintl_nl_default_dirname
49
# define _nl_domain_bindings libintl_nl_domain_bindings
50
#endif
51

    
52
/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
53
#ifndef offsetof
54
# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
55
#endif
56

    
57
/* @@ end of prolog @@ */
58

    
59
/* Contains the default location of the message catalogs.  */
60
extern const char _nl_default_dirname[];
61
#ifdef _LIBC
62
extern const char _nl_default_dirname_internal[] attribute_hidden;
63
#else
64
# define INTUSE(name) name
65
#endif
66

    
67
/* List with bindings of specific domains.  */
68
extern struct binding *_nl_domain_bindings;
69

    
70
/* Lock variable to protect the global data in the gettext implementation.  */
71
__libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
72

    
73

    
74
/* Names for the libintl functions are a problem.  They must not clash
75
   with existing names and they should follow ANSI C.  But this source
76
   code is also used in GNU C Library where the names have a __
77
   prefix.  So we have to make a difference here.  */
78
#ifdef _LIBC
79
# define BINDTEXTDOMAIN __bindtextdomain
80
# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
81
# ifndef strdup
82
#  define strdup(str) __strdup (str)
83
# endif
84
#else
85
# define BINDTEXTDOMAIN libintl_bindtextdomain
86
# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
87
#endif
88

    
89
/* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
90
   to be used for the DOMAINNAME message catalog.
91
   If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
92
   modified, only the current value is returned.
93
   If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
94
   modified nor returned.  */
95
static void
96
set_binding_values (const char *domainname,
97
                    const char **dirnamep, const char **codesetp)
98
{
99
  struct binding *binding;
100
  int modified;
101

    
102
  /* Some sanity checks.  */
103
  if (domainname == NULL || domainname[0] == '\0')
104
    {
105
      if (dirnamep)
106
        *dirnamep = NULL;
107
      if (codesetp)
108
        *codesetp = NULL;
109
      return;
110
    }
111

    
112
  __libc_rwlock_wrlock (_nl_state_lock);
113

    
114
  modified = 0;
115

    
116
  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
117
    {
118
      int compare = strcmp (domainname, binding->domainname);
119
      if (compare == 0)
120
        /* We found it!  */
121
        break;
122
      if (compare < 0)
123
        {
124
          /* It is not in the list.  */
125
          binding = NULL;
126
          break;
127
        }
128
    }
129

    
130
  if (binding != NULL)
131
    {
132
      if (dirnamep)
133
        {
134
          const char *dirname = *dirnamep;
135

    
136
          if (dirname == NULL)
137
            /* The current binding has be to returned.  */
138
            *dirnamep = binding->dirname;
139
          else
140
            {
141
              /* The domain is already bound.  If the new value and the old
142
                 one are equal we simply do nothing.  Otherwise replace the
143
                 old binding.  */
144
              char *result = binding->dirname;
145
              if (strcmp (dirname, result) != 0)
146
                {
147
                  if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
148
                    result = (char *) INTUSE(_nl_default_dirname);
149
                  else
150
                    {
151
#if defined _LIBC || defined HAVE_STRDUP
152
                      result = strdup (dirname);
153
#else
154
                      size_t len = strlen (dirname) + 1;
155
                      result = (char *) malloc (len);
156
                      if (__builtin_expect (result != NULL, 1))
157
                        memcpy (result, dirname, len);
158
#endif
159
                    }
160

    
161
                  if (__builtin_expect (result != NULL, 1))
162
                    {
163
                      if (binding->dirname != INTUSE(_nl_default_dirname))
164
                        free (binding->dirname);
165

    
166
                      binding->dirname = result;
167
                      modified = 1;
168
                    }
169
                }
170
              *dirnamep = result;
171
            }
172
        }
173

    
174
      if (codesetp)
175
        {
176
          const char *codeset = *codesetp;
177

    
178
          if (codeset == NULL)
179
            /* The current binding has be to returned.  */
180
            *codesetp = binding->codeset;
181
          else
182
            {
183
              /* The domain is already bound.  If the new value and the old
184
                 one are equal we simply do nothing.  Otherwise replace the
185
                 old binding.  */
186
              char *result = binding->codeset;
187
              if (result == NULL || strcmp (codeset, result) != 0)
188
                {
189
#if defined _LIBC || defined HAVE_STRDUP
190
                  result = strdup (codeset);
191
#else
192
                  size_t len = strlen (codeset) + 1;
193
                  result = (char *) malloc (len);
194
                  if (__builtin_expect (result != NULL, 1))
195
                    memcpy (result, codeset, len);
196
#endif
197

    
198
                  if (__builtin_expect (result != NULL, 1))
199
                    {
200
                      if (binding->codeset != NULL)
201
                        free (binding->codeset);
202

    
203
                      binding->codeset = result;
204
                      binding->codeset_cntr++;
205
                      modified = 1;
206
                    }
207
                }
208
              *codesetp = result;
209
            }
210
        }
211
    }
212
  else if ((dirnamep == NULL || *dirnamep == NULL)
213
           && (codesetp == NULL || *codesetp == NULL))
214
    {
215
      /* Simply return the default values.  */
216
      if (dirnamep)
217
        *dirnamep = INTUSE(_nl_default_dirname);
218
      if (codesetp)
219
        *codesetp = NULL;
220
    }
221
  else
222
    {
223
      /* We have to create a new binding.  */
224
      size_t len = strlen (domainname) + 1;
225
      struct binding *new_binding =
226
        (struct binding *) malloc (offsetof (struct binding, domainname) + len);
227

    
228
      if (__builtin_expect (new_binding == NULL, 0))
229
        goto failed;
230

    
231
      memcpy (new_binding->domainname, domainname, len);
232

    
233
      if (dirnamep)
234
        {
235
          const char *dirname = *dirnamep;
236

    
237
          if (dirname == NULL)
238
            /* The default value.  */
239
            dirname = INTUSE(_nl_default_dirname);
240
          else
241
            {
242
              if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
243
                dirname = INTUSE(_nl_default_dirname);
244
              else
245
                {
246
                  char *result;
247
#if defined _LIBC || defined HAVE_STRDUP
248
                  result = strdup (dirname);
249
                  if (__builtin_expect (result == NULL, 0))
250
                    goto failed_dirname;
251
#else
252
                  size_t len = strlen (dirname) + 1;
253
                  result = (char *) malloc (len);
254
                  if (__builtin_expect (result == NULL, 0))
255
                    goto failed_dirname;
256
                  memcpy (result, dirname, len);
257
#endif
258
                  dirname = result;
259
                }
260
            }
261
          *dirnamep = dirname;
262
          new_binding->dirname = (char *) dirname;
263
        }
264
      else
265
        /* The default value.  */
266
        new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
267

    
268
      new_binding->codeset_cntr = 0;
269

    
270
      if (codesetp)
271
        {
272
          const char *codeset = *codesetp;
273

    
274
          if (codeset != NULL)
275
            {
276
              char *result;
277

    
278
#if defined _LIBC || defined HAVE_STRDUP
279
              result = strdup (codeset);
280
              if (__builtin_expect (result == NULL, 0))
281
                goto failed_codeset;
282
#else
283
              size_t len = strlen (codeset) + 1;
284
              result = (char *) malloc (len);
285
              if (__builtin_expect (result == NULL, 0))
286
                goto failed_codeset;
287
              memcpy (result, codeset, len);
288
#endif
289
              codeset = result;
290
              new_binding->codeset_cntr++;
291
            }
292
          *codesetp = codeset;
293
          new_binding->codeset = (char *) codeset;
294
        }
295
      else
296
        new_binding->codeset = NULL;
297

    
298
      /* Now enqueue it.  */
299
      if (_nl_domain_bindings == NULL
300
          || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
301
        {
302
          new_binding->next = _nl_domain_bindings;
303
          _nl_domain_bindings = new_binding;
304
        }
305
      else
306
        {
307
          binding = _nl_domain_bindings;
308
          while (binding->next != NULL
309
                 && strcmp (domainname, binding->next->domainname) > 0)
310
            binding = binding->next;
311

    
312
          new_binding->next = binding->next;
313
          binding->next = new_binding;
314
        }
315

    
316
      modified = 1;
317

    
318
      /* Here we deal with memory allocation failures.  */
319
      if (0)
320
        {
321
        failed_codeset:
322
          if (new_binding->dirname != INTUSE(_nl_default_dirname))
323
            free (new_binding->dirname);
324
        failed_dirname:
325
          free (new_binding);
326
        failed:
327
          if (dirnamep)
328
            *dirnamep = NULL;
329
          if (codesetp)
330
            *codesetp = NULL;
331
        }
332
    }
333

    
334
  /* If we modified any binding, we flush the caches.  */
335
  if (modified)
336
    ++_nl_msg_cat_cntr;
337

    
338
  __libc_rwlock_unlock (_nl_state_lock);
339
}
340

    
341
/* Specify that the DOMAINNAME message catalog will be found
342
   in DIRNAME rather than in the system locale data base.  */
343
char *
344
BINDTEXTDOMAIN (const char *domainname, const char *dirname)
345
{
346
  set_binding_values (domainname, &dirname, NULL);
347
  return (char *) dirname;
348
}
349

    
350
/* Specify the character encoding in which the messages from the
351
   DOMAINNAME message catalog will be returned.  */
352
char *
353
BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
354
{
355
  set_binding_values (domainname, NULL, &codeset);
356
  return (char *) codeset;
357
}
358

    
359
#ifdef _LIBC
360
/* Aliases for function names in GNU C Library.  */
361
weak_alias (__bindtextdomain, bindtextdomain);
362
weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
363
#endif