bindtextdom.c 8.6 KB

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