initial message templates support
[claws.git] / intl / bindtextdom.c
blob7e5a74a43bf2ae94182246249274291269a30f0e
1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
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
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #ifdef _LIBC
27 # include <libintl.h>
28 #else
29 # include "libgnuintl.h"
30 #endif
31 #include "gettextP.h"
33 #ifdef _LIBC
34 /* We have to handle multi-threaded applications. */
35 # include <bits/libc-lock.h>
36 #else
37 /* Provide dummy implementation if this is outside glibc. */
38 # define __libc_rwlock_define(CLASS, NAME)
39 # define __libc_rwlock_wrlock(NAME)
40 # define __libc_rwlock_unlock(NAME)
41 #endif
43 /* The internal variables in the standalone libintl.a must have different
44 names than the internal variables in GNU libc, otherwise programs
45 using libintl.a cannot be linked statically. */
46 #if !defined _LIBC
47 # define _nl_default_dirname _nl_default_dirname__
48 # define _nl_domain_bindings _nl_domain_bindings__
49 #endif
51 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
52 #ifndef offsetof
53 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
54 #endif
56 /* @@ end of prolog @@ */
58 /* Contains the default location of the message catalogs. */
59 extern const char _nl_default_dirname[];
61 /* List with bindings of specific domains. */
62 extern struct binding *_nl_domain_bindings;
64 /* Lock variable to protect the global data in the gettext implementation. */
65 __libc_rwlock_define (extern, _nl_state_lock)
68 /* Names for the libintl functions are a problem. They must not clash
69 with existing names and they should follow ANSI C. But this source
70 code is also used in GNU C Library where the names have a __
71 prefix. So we have to make a difference here. */
72 #ifdef _LIBC
73 # define BINDTEXTDOMAIN __bindtextdomain
74 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
75 # ifndef strdup
76 # define strdup(str) __strdup (str)
77 # endif
78 #else
79 # define BINDTEXTDOMAIN bindtextdomain__
80 # define BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset__
81 #endif
83 /* Prototypes for local functions. */
84 static void set_binding_values PARAMS ((const char *domainname,
85 const char **dirnamep,
86 const char **codesetp));
88 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
89 to be used for the DOMAINNAME message catalog.
90 If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
91 modified, only the current value is returned.
92 If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
93 modified nor returned. */
94 static void
95 set_binding_values (domainname, dirnamep, codesetp)
96 const char *domainname;
97 const char **dirnamep;
98 const char **codesetp;
100 struct binding *binding;
101 int modified;
103 /* Some sanity checks. */
104 if (domainname == NULL || domainname[0] == '\0')
106 if (dirnamep)
107 *dirnamep = NULL;
108 if (codesetp)
109 *codesetp = NULL;
110 return;
113 __libc_rwlock_wrlock (_nl_state_lock);
115 modified = 0;
117 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
119 int compare = strcmp (domainname, binding->domainname);
120 if (compare == 0)
121 /* We found it! */
122 break;
123 if (compare < 0)
125 /* It is not in the list. */
126 binding = NULL;
127 break;
131 if (binding != NULL)
133 if (dirnamep)
135 const char *dirname = *dirnamep;
137 if (dirname == NULL)
138 /* The current binding has be to returned. */
139 *dirnamep = binding->dirname;
140 else
142 /* The domain is already bound. If the new value and the old
143 one are equal we simply do nothing. Otherwise replace the
144 old binding. */
145 char *result = binding->dirname;
146 if (strcmp (dirname, result) != 0)
148 if (strcmp (dirname, _nl_default_dirname) == 0)
149 result = (char *) _nl_default_dirname;
150 else
152 #if defined _LIBC || defined HAVE_STRDUP
153 result = strdup (dirname);
154 #else
155 size_t len = strlen (dirname) + 1;
156 result = (char *) malloc (len);
157 if (__builtin_expect (result != NULL, 1))
158 memcpy (result, dirname, len);
159 #endif
162 if (__builtin_expect (result != NULL, 1))
164 if (binding->dirname != _nl_default_dirname)
165 free (binding->dirname);
167 binding->dirname = result;
168 modified = 1;
171 *dirnamep = result;
175 if (codesetp)
177 const char *codeset = *codesetp;
179 if (codeset == NULL)
180 /* The current binding has be to returned. */
181 *codesetp = binding->codeset;
182 else
184 /* The domain is already bound. If the new value and the old
185 one are equal we simply do nothing. Otherwise replace the
186 old binding. */
187 char *result = binding->codeset;
188 if (result == NULL || strcmp (codeset, result) != 0)
190 #if defined _LIBC || defined HAVE_STRDUP
191 result = strdup (codeset);
192 #else
193 size_t len = strlen (codeset) + 1;
194 result = (char *) malloc (len);
195 if (__builtin_expect (result != NULL, 1))
196 memcpy (result, codeset, len);
197 #endif
199 if (__builtin_expect (result != NULL, 1))
201 if (binding->codeset != NULL)
202 free (binding->codeset);
204 binding->codeset = result;
205 binding->codeset_cntr++;
206 modified = 1;
209 *codesetp = result;
213 else if ((dirnamep == NULL || *dirnamep == NULL)
214 && (codesetp == NULL || *codesetp == NULL))
216 /* Simply return the default values. */
217 if (dirnamep)
218 *dirnamep = _nl_default_dirname;
219 if (codesetp)
220 *codesetp = NULL;
222 else
224 /* We have to create a new binding. */
225 size_t len = strlen (domainname) + 1;
226 struct binding *new_binding =
227 (struct binding *) malloc (offsetof (struct binding, domainname) + len);
229 if (__builtin_expect (new_binding == NULL, 0))
230 goto failed;
232 memcpy (new_binding->domainname, domainname, len);
234 if (dirnamep)
236 const char *dirname = *dirnamep;
238 if (dirname == NULL)
239 /* The default value. */
240 dirname = _nl_default_dirname;
241 else
243 if (strcmp (dirname, _nl_default_dirname) == 0)
244 dirname = _nl_default_dirname;
245 else
247 char *result;
248 #if defined _LIBC || defined HAVE_STRDUP
249 result = strdup (dirname);
250 if (__builtin_expect (result == NULL, 0))
251 goto failed_dirname;
252 #else
253 size_t len = strlen (dirname) + 1;
254 result = (char *) malloc (len);
255 if (__builtin_expect (result == NULL, 0))
256 goto failed_dirname;
257 memcpy (result, dirname, len);
258 #endif
259 dirname = result;
262 *dirnamep = dirname;
263 new_binding->dirname = (char *) dirname;
265 else
266 /* The default value. */
267 new_binding->dirname = (char *) _nl_default_dirname;
269 new_binding->codeset_cntr = 0;
271 if (codesetp)
273 const char *codeset = *codesetp;
275 if (codeset != NULL)
277 char *result;
279 #if defined _LIBC || defined HAVE_STRDUP
280 result = strdup (codeset);
281 if (__builtin_expect (result == NULL, 0))
282 goto failed_codeset;
283 #else
284 size_t len = strlen (codeset) + 1;
285 result = (char *) malloc (len);
286 if (__builtin_expect (result == NULL, 0))
287 goto failed_codeset;
288 memcpy (result, codeset, len);
289 #endif
290 codeset = result;
291 new_binding->codeset_cntr++;
293 *codesetp = codeset;
294 new_binding->codeset = (char *) codeset;
296 else
297 new_binding->codeset = NULL;
299 /* Now enqueue it. */
300 if (_nl_domain_bindings == NULL
301 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
303 new_binding->next = _nl_domain_bindings;
304 _nl_domain_bindings = new_binding;
306 else
308 binding = _nl_domain_bindings;
309 while (binding->next != NULL
310 && strcmp (domainname, binding->next->domainname) > 0)
311 binding = binding->next;
313 new_binding->next = binding->next;
314 binding->next = new_binding;
317 modified = 1;
319 /* Here we deal with memory allocation failures. */
320 if (0)
322 failed_codeset:
323 if (new_binding->dirname != _nl_default_dirname)
324 free (new_binding->dirname);
325 failed_dirname:
326 free (new_binding);
327 failed:
328 if (dirnamep)
329 *dirnamep = NULL;
330 if (codesetp)
331 *codesetp = NULL;
335 /* If we modified any binding, we flush the caches. */
336 if (modified)
337 ++_nl_msg_cat_cntr;
339 __libc_rwlock_unlock (_nl_state_lock);
342 /* Specify that the DOMAINNAME message catalog will be found
343 in DIRNAME rather than in the system locale data base. */
344 char *
345 BINDTEXTDOMAIN (domainname, dirname)
346 const char *domainname;
347 const char *dirname;
349 set_binding_values (domainname, &dirname, NULL);
350 return (char *) dirname;
353 /* Specify the character encoding in which the messages from the
354 DOMAINNAME message catalog will be returned. */
355 char *
356 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
357 const char *domainname;
358 const char *codeset;
360 set_binding_values (domainname, NULL, &codeset);
361 return (char *) codeset;
364 #ifdef _LIBC
365 /* Aliases for function names in GNU C Library. */
366 weak_alias (__bindtextdomain, bindtextdomain);
367 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
368 #endif