]> git.saurik.com Git - bison.git/blob - intl/bindtextdom.c
* src/print_graph.c (print_actions): CPP out useless code.
[bison.git] / intl / bindtextdom.c
1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc.
3
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.
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
12 GNU General Public License for more details.
13
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. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #ifdef _LIBC
27 # include <libintl.h>
28 #else
29 # include "libgnuintl.h"
30 #endif
31 #include "gettextP.h"
32
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
42
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
50
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
55
56 /* @@ end of prolog @@ */
57
58 /* Contains the default location of the message catalogs. */
59 extern const char _nl_default_dirname[];
60
61 /* List with bindings of specific domains. */
62 extern struct binding *_nl_domain_bindings;
63
64 /* Lock variable to protect the global data in the gettext implementation. */
65 __libc_rwlock_define (extern, _nl_state_lock)
66
67
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
82
83 /* Prototypes for local functions. */
84 static void set_binding_values PARAMS ((const char *domainname,
85 const char **dirnamep,
86 const char **codesetp));
87
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;
99 {
100 struct binding *binding;
101 int modified;
102
103 /* Some sanity checks. */
104 if (domainname == NULL || domainname[0] == '\0')
105 {
106 if (dirnamep)
107 *dirnamep = NULL;
108 if (codesetp)
109 *codesetp = NULL;
110 return;
111 }
112
113 __libc_rwlock_wrlock (_nl_state_lock);
114
115 modified = 0;
116
117 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
118 {
119 int compare = strcmp (domainname, binding->domainname);
120 if (compare == 0)
121 /* We found it! */
122 break;
123 if (compare < 0)
124 {
125 /* It is not in the list. */
126 binding = NULL;
127 break;
128 }
129 }
130
131 if (binding != NULL)
132 {
133 if (dirnamep)
134 {
135 const char *dirname = *dirnamep;
136
137 if (dirname == NULL)
138 /* The current binding has be to returned. */
139 *dirnamep = binding->dirname;
140 else
141 {
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)
147 {
148 if (strcmp (dirname, _nl_default_dirname) == 0)
149 result = (char *) _nl_default_dirname;
150 else
151 {
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
160 }
161
162 if (__builtin_expect (result != NULL, 1))
163 {
164 if (binding->dirname != _nl_default_dirname)
165 free (binding->dirname);
166
167 binding->dirname = result;
168 modified = 1;
169 }
170 }
171 *dirnamep = result;
172 }
173 }
174
175 if (codesetp)
176 {
177 const char *codeset = *codesetp;
178
179 if (codeset == NULL)
180 /* The current binding has be to returned. */
181 *codesetp = binding->codeset;
182 else
183 {
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)
189 {
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
198
199 if (__builtin_expect (result != NULL, 1))
200 {
201 if (binding->codeset != NULL)
202 free (binding->codeset);
203
204 binding->codeset = result;
205 binding->codeset_cntr++;
206 modified = 1;
207 }
208 }
209 *codesetp = result;
210 }
211 }
212 }
213 else if ((dirnamep == NULL || *dirnamep == NULL)
214 && (codesetp == NULL || *codesetp == NULL))
215 {
216 /* Simply return the default values. */
217 if (dirnamep)
218 *dirnamep = _nl_default_dirname;
219 if (codesetp)
220 *codesetp = NULL;
221 }
222 else
223 {
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);
228
229 if (__builtin_expect (new_binding == NULL, 0))
230 goto failed;
231
232 memcpy (new_binding->domainname, domainname, len);
233
234 if (dirnamep)
235 {
236 const char *dirname = *dirnamep;
237
238 if (dirname == NULL)
239 /* The default value. */
240 dirname = _nl_default_dirname;
241 else
242 {
243 if (strcmp (dirname, _nl_default_dirname) == 0)
244 dirname = _nl_default_dirname;
245 else
246 {
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;
260 }
261 }
262 *dirnamep = dirname;
263 new_binding->dirname = (char *) dirname;
264 }
265 else
266 /* The default value. */
267 new_binding->dirname = (char *) _nl_default_dirname;
268
269 new_binding->codeset_cntr = 0;
270
271 if (codesetp)
272 {
273 const char *codeset = *codesetp;
274
275 if (codeset != NULL)
276 {
277 char *result;
278
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++;
292 }
293 *codesetp = codeset;
294 new_binding->codeset = (char *) codeset;
295 }
296 else
297 new_binding->codeset = NULL;
298
299 /* Now enqueue it. */
300 if (_nl_domain_bindings == NULL
301 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
302 {
303 new_binding->next = _nl_domain_bindings;
304 _nl_domain_bindings = new_binding;
305 }
306 else
307 {
308 binding = _nl_domain_bindings;
309 while (binding->next != NULL
310 && strcmp (domainname, binding->next->domainname) > 0)
311 binding = binding->next;
312
313 new_binding->next = binding->next;
314 binding->next = new_binding;
315 }
316
317 modified = 1;
318
319 /* Here we deal with memory allocation failures. */
320 if (0)
321 {
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;
332 }
333 }
334
335 /* If we modified any binding, we flush the caches. */
336 if (modified)
337 ++_nl_msg_cat_cntr;
338
339 __libc_rwlock_unlock (_nl_state_lock);
340 }
341
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;
348 {
349 set_binding_values (domainname, &dirname, NULL);
350 return (char *) dirname;
351 }
352
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;
359 {
360 set_binding_values (domainname, NULL, &codeset);
361 return (char *) codeset;
362 }
363
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