bindtextdom.c 9.6 KB

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