bindtextdom.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /* Implementation of the bindtextdomain(3) function
  2. Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published
  5. by the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this program; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  14. USA. */
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #include <stddef.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "gettextP.h"
  22. #ifdef _LIBC
  23. # include <libintl.h>
  24. #else
  25. # include "libgnuintl.h"
  26. #endif
  27. /* Handle multi-threaded applications. */
  28. #ifdef _LIBC
  29. # include <bits/libc-lock.h>
  30. # define gl_rwlock_define __libc_rwlock_define
  31. # define gl_rwlock_wrlock __libc_rwlock_wrlock
  32. # define gl_rwlock_unlock __libc_rwlock_unlock
  33. #else
  34. # include "lock.h"
  35. #endif
  36. /* The internal variables in the standalone libintl.a must have different
  37. names than the internal variables in GNU libc, otherwise programs
  38. using libintl.a cannot be linked statically. */
  39. #if !defined _LIBC
  40. # define _nl_default_dirname libintl_nl_default_dirname
  41. # define _nl_domain_bindings libintl_nl_domain_bindings
  42. #endif
  43. /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
  44. #ifndef offsetof
  45. # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
  46. #endif
  47. /* @@ end of prolog @@ */
  48. /* Contains the default location of the message catalogs. */
  49. extern const char _nl_default_dirname[];
  50. #ifdef _LIBC
  51. libc_hidden_proto (_nl_default_dirname)
  52. #endif
  53. /* List with bindings of specific domains. */
  54. extern struct binding *_nl_domain_bindings;
  55. /* Lock variable to protect the global data in the gettext implementation. */
  56. gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
  57. /* Names for the libintl functions are a problem. They must not clash
  58. with existing names and they should follow ANSI C. But this source
  59. code is also used in GNU C Library where the names have a __
  60. prefix. So we have to make a difference here. */
  61. #ifdef _LIBC
  62. # define BINDTEXTDOMAIN __bindtextdomain
  63. # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
  64. # ifndef strdup
  65. # define strdup(str) __strdup (str)
  66. # endif
  67. #else
  68. # define BINDTEXTDOMAIN libintl_bindtextdomain
  69. # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
  70. #endif
  71. /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
  72. to be used for the DOMAINNAME message catalog.
  73. If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
  74. modified, only the current value is returned.
  75. If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
  76. modified nor returned. */
  77. static void
  78. set_binding_values (const char *domainname,
  79. const char **dirnamep, const char **codesetp)
  80. {
  81. struct binding *binding;
  82. int modified;
  83. /* Some sanity checks. */
  84. if (domainname == NULL || domainname[0] == '\0')
  85. {
  86. if (dirnamep)
  87. *dirnamep = NULL;
  88. if (codesetp)
  89. *codesetp = NULL;
  90. return;
  91. }
  92. gl_rwlock_wrlock (_nl_state_lock);
  93. modified = 0;
  94. for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
  95. {
  96. int compare = strcmp (domainname, binding->domainname);
  97. if (compare == 0)
  98. /* We found it! */
  99. break;
  100. if (compare < 0)
  101. {
  102. /* It is not in the list. */
  103. binding = NULL;
  104. break;
  105. }
  106. }
  107. if (binding != NULL)
  108. {
  109. if (dirnamep)
  110. {
  111. const char *dirname = *dirnamep;
  112. if (dirname == NULL)
  113. /* The current binding has be to returned. */
  114. *dirnamep = binding->dirname;
  115. else
  116. {
  117. /* The domain is already bound. If the new value and the old
  118. one are equal we simply do nothing. Otherwise replace the
  119. old binding. */
  120. char *result = binding->dirname;
  121. if (strcmp (dirname, result) != 0)
  122. {
  123. if (strcmp (dirname, _nl_default_dirname) == 0)
  124. result = (char *) _nl_default_dirname;
  125. else
  126. {
  127. #if defined _LIBC || defined HAVE_STRDUP
  128. result = strdup (dirname);
  129. #else
  130. size_t len = strlen (dirname) + 1;
  131. result = (char *) malloc (len);
  132. if (__builtin_expect (result != NULL, 1))
  133. memcpy (result, dirname, len);
  134. #endif
  135. }
  136. if (__builtin_expect (result != NULL, 1))
  137. {
  138. if (binding->dirname != _nl_default_dirname)
  139. free (binding->dirname);
  140. binding->dirname = result;
  141. modified = 1;
  142. }
  143. }
  144. *dirnamep = result;
  145. }
  146. }
  147. if (codesetp)
  148. {
  149. const char *codeset = *codesetp;
  150. if (codeset == NULL)
  151. /* The current binding has be to returned. */
  152. *codesetp = binding->codeset;
  153. else
  154. {
  155. /* The domain is already bound. If the new value and the old
  156. one are equal we simply do nothing. Otherwise replace the
  157. old binding. */
  158. char *result = binding->codeset;
  159. if (result == NULL || strcmp (codeset, result) != 0)
  160. {
  161. #if defined _LIBC || defined HAVE_STRDUP
  162. result = strdup (codeset);
  163. #else
  164. size_t len = strlen (codeset) + 1;
  165. result = (char *) malloc (len);
  166. if (__builtin_expect (result != NULL, 1))
  167. memcpy (result, codeset, len);
  168. #endif
  169. if (__builtin_expect (result != NULL, 1))
  170. {
  171. if (binding->codeset != NULL)
  172. free (binding->codeset);
  173. binding->codeset = result;
  174. modified = 1;
  175. }
  176. }
  177. *codesetp = result;
  178. }
  179. }
  180. }
  181. else if ((dirnamep == NULL || *dirnamep == NULL)
  182. && (codesetp == NULL || *codesetp == NULL))
  183. {
  184. /* Simply return the default values. */
  185. if (dirnamep)
  186. *dirnamep = _nl_default_dirname;
  187. if (codesetp)
  188. *codesetp = NULL;
  189. }
  190. else
  191. {
  192. /* We have to create a new binding. */
  193. size_t len = strlen (domainname) + 1;
  194. struct binding *new_binding =
  195. (struct binding *) malloc (offsetof (struct binding, domainname) + len);
  196. if (__builtin_expect (new_binding == NULL, 0))
  197. goto failed;
  198. memcpy (new_binding->domainname, domainname, len);
  199. if (dirnamep)
  200. {
  201. const char *dirname = *dirnamep;
  202. if (dirname == NULL)
  203. /* The default value. */
  204. dirname = _nl_default_dirname;
  205. else
  206. {
  207. if (strcmp (dirname, _nl_default_dirname) == 0)
  208. dirname = _nl_default_dirname;
  209. else
  210. {
  211. char *result;
  212. #if defined _LIBC || defined HAVE_STRDUP
  213. result = strdup (dirname);
  214. if (__builtin_expect (result == NULL, 0))
  215. goto failed_dirname;
  216. #else
  217. size_t len = strlen (dirname) + 1;
  218. result = (char *) malloc (len);
  219. if (__builtin_expect (result == NULL, 0))
  220. goto failed_dirname;
  221. memcpy (result, dirname, len);
  222. #endif
  223. dirname = result;
  224. }
  225. }
  226. *dirnamep = dirname;
  227. new_binding->dirname = (char *) dirname;
  228. }
  229. else
  230. /* The default value. */
  231. new_binding->dirname = (char *) _nl_default_dirname;
  232. if (codesetp)
  233. {
  234. const char *codeset = *codesetp;
  235. if (codeset != NULL)
  236. {
  237. char *result;
  238. #if defined _LIBC || defined HAVE_STRDUP
  239. result = strdup (codeset);
  240. if (__builtin_expect (result == NULL, 0))
  241. goto failed_codeset;
  242. #else
  243. size_t len = strlen (codeset) + 1;
  244. result = (char *) malloc (len);
  245. if (__builtin_expect (result == NULL, 0))
  246. goto failed_codeset;
  247. memcpy (result, codeset, len);
  248. #endif
  249. codeset = result;
  250. }
  251. *codesetp = codeset;
  252. new_binding->codeset = (char *) codeset;
  253. }
  254. else
  255. new_binding->codeset = NULL;
  256. /* Now enqueue it. */
  257. if (_nl_domain_bindings == NULL
  258. || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
  259. {
  260. new_binding->next = _nl_domain_bindings;
  261. _nl_domain_bindings = new_binding;
  262. }
  263. else
  264. {
  265. binding = _nl_domain_bindings;
  266. while (binding->next != NULL
  267. && strcmp (domainname, binding->next->domainname) > 0)
  268. binding = binding->next;
  269. new_binding->next = binding->next;
  270. binding->next = new_binding;
  271. }
  272. modified = 1;
  273. /* Here we deal with memory allocation failures. */
  274. if (0)
  275. {
  276. failed_codeset:
  277. if (new_binding->dirname != _nl_default_dirname)
  278. free (new_binding->dirname);
  279. failed_dirname:
  280. free (new_binding);
  281. failed:
  282. if (dirnamep)
  283. *dirnamep = NULL;
  284. if (codesetp)
  285. *codesetp = NULL;
  286. }
  287. }
  288. /* If we modified any binding, we flush the caches. */
  289. if (modified)
  290. ++_nl_msg_cat_cntr;
  291. gl_rwlock_unlock (_nl_state_lock);
  292. }
  293. /* Specify that the DOMAINNAME message catalog will be found
  294. in DIRNAME rather than in the system locale data base. */
  295. char *
  296. BINDTEXTDOMAIN (const char *domainname, const char *dirname)
  297. {
  298. set_binding_values (domainname, &dirname, NULL);
  299. return (char *) dirname;
  300. }
  301. /* Specify the character encoding in which the messages from the
  302. DOMAINNAME message catalog will be returned. */
  303. char *
  304. BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
  305. {
  306. set_binding_values (domainname, NULL, &codeset);
  307. return (char *) codeset;
  308. }
  309. #ifdef _LIBC
  310. /* Aliases for function names in GNU C Library. */
  311. weak_alias (__bindtextdomain, bindtextdomain);
  312. weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
  313. #endif