gettext.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /* Convenience header for conditional use of GNU <libintl.h>.
  2. Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2022 Free Software
  3. Foundation, Inc.
  4. This file is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation; either version 2.1 of the
  7. License, or (at your option) any later version.
  8. This file is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  14. #ifndef _LIBGETTEXT_H
  15. #define _LIBGETTEXT_H 1
  16. /* NLS can be disabled through the configure --disable-nls option
  17. or through "#define ENABLE NLS 0" before including this file. */
  18. #if defined ENABLE_NLS && ENABLE_NLS
  19. /* Get declarations of GNU message catalog functions. */
  20. # include <libintl.h>
  21. /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
  22. the gettext() and ngettext() macros. This is an alternative to calling
  23. textdomain(), and is useful for libraries. */
  24. # ifdef DEFAULT_TEXT_DOMAIN
  25. # undef gettext
  26. # define gettext(Msgid) \
  27. dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
  28. # undef ngettext
  29. # define ngettext(Msgid1, Msgid2, N) \
  30. dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
  31. # endif
  32. #else
  33. /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
  34. chokes if dcgettext is defined as a macro. So include it now, to make
  35. later inclusions of <locale.h> a NOP. We don't include <libintl.h>
  36. as well because people using "gettext.h" will not include <libintl.h>,
  37. and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
  38. is OK. */
  39. #if defined(__sun)
  40. # include <locale.h>
  41. #endif
  42. /* Many header files from the libstdc++ coming with g++ 3.3 or newer include
  43. <libintl.h>, which chokes if dcgettext is defined as a macro. So include
  44. it now, to make later inclusions of <libintl.h> a NOP. */
  45. #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
  46. # include <cstdlib>
  47. # if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H
  48. # include <libintl.h>
  49. # endif
  50. #endif
  51. /* Disabled NLS.
  52. The casts to 'const char *' serve the purpose of producing warnings
  53. for invalid uses of the value returned from these functions.
  54. On pre-ANSI systems without 'const', the config.h file is supposed to
  55. contain "#define const". */
  56. # undef gettext
  57. # define gettext(Msgid) ((const char *) (Msgid))
  58. # undef dgettext
  59. # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
  60. # undef dcgettext
  61. # define dcgettext(Domainname, Msgid, Category) \
  62. ((void) (Category), dgettext (Domainname, Msgid))
  63. # undef ngettext
  64. # define ngettext(Msgid1, Msgid2, N) \
  65. ((N) == 1 \
  66. ? ((void) (Msgid2), (const char *) (Msgid1)) \
  67. : ((void) (Msgid1), (const char *) (Msgid2)))
  68. # undef dngettext
  69. # define dngettext(Domainname, Msgid1, Msgid2, N) \
  70. ((void) (Domainname), ngettext (Msgid1, Msgid2, N))
  71. # undef dcngettext
  72. # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
  73. ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N))
  74. # undef textdomain
  75. # define textdomain(Domainname) ((const char *) (Domainname))
  76. # undef bindtextdomain
  77. # define bindtextdomain(Domainname, Dirname) \
  78. ((void) (Domainname), (const char *) (Dirname))
  79. # undef bind_textdomain_codeset
  80. # define bind_textdomain_codeset(Domainname, Codeset) \
  81. ((void) (Domainname), (const char *) (Codeset))
  82. #endif
  83. /* Prefer gnulib's setlocale override over libintl's setlocale override. */
  84. #ifdef GNULIB_defined_setlocale
  85. # undef setlocale
  86. # define setlocale rpl_setlocale
  87. #endif
  88. /* A pseudo function call that serves as a marker for the automated
  89. extraction of messages, but does not call gettext(). The run-time
  90. translation is done at a different place in the code.
  91. The argument, String, should be a literal string. Concatenated strings
  92. and other string expressions won't work.
  93. The macro's expansion is not parenthesized, so that it is suitable as
  94. initializer for static 'char[]' or 'const char[]' variables. */
  95. #define gettext_noop(String) String
  96. /* The separator between msgctxt and msgid in a .mo file. */
  97. #define GETTEXT_CONTEXT_GLUE "\004"
  98. /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
  99. MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
  100. short and rarely need to change.
  101. The letter 'p' stands for 'particular' or 'special'. */
  102. #ifdef DEFAULT_TEXT_DOMAIN
  103. # define pgettext(Msgctxt, Msgid) \
  104. pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
  105. #else
  106. # define pgettext(Msgctxt, Msgid) \
  107. pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
  108. #endif
  109. #define dpgettext(Domainname, Msgctxt, Msgid) \
  110. pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
  111. #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
  112. pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
  113. #ifdef DEFAULT_TEXT_DOMAIN
  114. # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
  115. npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
  116. #else
  117. # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
  118. npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
  119. #endif
  120. #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
  121. npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
  122. #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
  123. npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
  124. #if defined __GNUC__ || defined __clang__
  125. __inline
  126. #else
  127. #ifdef __cplusplus
  128. inline
  129. #endif
  130. #endif
  131. static const char *
  132. pgettext_aux (const char *domain,
  133. const char *msg_ctxt_id, const char *msgid,
  134. int category)
  135. {
  136. const char *translation = dcgettext (domain, msg_ctxt_id, category);
  137. if (translation == msg_ctxt_id)
  138. return msgid;
  139. else
  140. return translation;
  141. }
  142. #if defined __GNUC__ || defined __clang__
  143. __inline
  144. #else
  145. #ifdef __cplusplus
  146. inline
  147. #endif
  148. #endif
  149. static const char *
  150. npgettext_aux (const char *domain,
  151. const char *msg_ctxt_id, const char *msgid,
  152. const char *msgid_plural, unsigned long int n,
  153. int category)
  154. {
  155. const char *translation =
  156. dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
  157. if (translation == msg_ctxt_id || translation == msgid_plural)
  158. return (n == 1 ? msgid : msgid_plural);
  159. else
  160. return translation;
  161. }
  162. /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
  163. can be arbitrary expressions. But for string literals these macros are
  164. less efficient than those above. */
  165. #include <string.h>
  166. /* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported.
  167. This relates to the -Wvla and -Wvla-larger-than warnings, enabled in
  168. the default GCC many warnings set. This allows programs to disable use
  169. of VLAs, which may be unintended, or may be awkward to support portably,
  170. or may have security implications due to non-deterministic stack usage. */
  171. #if (!defined GNULIB_NO_VLA \
  172. && defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__ \
  173. && !defined __STDC_NO_VLA__)
  174. # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
  175. #else
  176. # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
  177. #endif
  178. #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
  179. #include <stdlib.h>
  180. #endif
  181. #define pgettext_expr(Msgctxt, Msgid) \
  182. dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
  183. #define dpgettext_expr(Domainname, Msgctxt, Msgid) \
  184. dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
  185. #if defined __GNUC__ || defined __clang__
  186. __inline
  187. #else
  188. #ifdef __cplusplus
  189. inline
  190. #endif
  191. #endif
  192. static const char *
  193. dcpgettext_expr (const char *domain,
  194. const char *msgctxt, const char *msgid,
  195. int category)
  196. {
  197. size_t msgctxt_len = strlen (msgctxt) + 1;
  198. size_t msgid_len = strlen (msgid) + 1;
  199. const char *translation;
  200. #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
  201. char msg_ctxt_id[msgctxt_len + msgid_len];
  202. #else
  203. char buf[1024];
  204. char *msg_ctxt_id =
  205. (msgctxt_len + msgid_len <= sizeof (buf)
  206. ? buf
  207. : (char *) malloc (msgctxt_len + msgid_len));
  208. if (msg_ctxt_id != NULL)
  209. #endif
  210. {
  211. int found_translation;
  212. memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
  213. msg_ctxt_id[msgctxt_len - 1] = '\004';
  214. memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
  215. translation = dcgettext (domain, msg_ctxt_id, category);
  216. found_translation = (translation != msg_ctxt_id);
  217. #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
  218. if (msg_ctxt_id != buf)
  219. free (msg_ctxt_id);
  220. #endif
  221. if (found_translation)
  222. return translation;
  223. }
  224. return msgid;
  225. }
  226. #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
  227. dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
  228. #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
  229. dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
  230. #if defined __GNUC__ || defined __clang__
  231. __inline
  232. #else
  233. #ifdef __cplusplus
  234. inline
  235. #endif
  236. #endif
  237. static const char *
  238. dcnpgettext_expr (const char *domain,
  239. const char *msgctxt, const char *msgid,
  240. const char *msgid_plural, unsigned long int n,
  241. int category)
  242. {
  243. size_t msgctxt_len = strlen (msgctxt) + 1;
  244. size_t msgid_len = strlen (msgid) + 1;
  245. const char *translation;
  246. #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
  247. char msg_ctxt_id[msgctxt_len + msgid_len];
  248. #else
  249. char buf[1024];
  250. char *msg_ctxt_id =
  251. (msgctxt_len + msgid_len <= sizeof (buf)
  252. ? buf
  253. : (char *) malloc (msgctxt_len + msgid_len));
  254. if (msg_ctxt_id != NULL)
  255. #endif
  256. {
  257. int found_translation;
  258. memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
  259. msg_ctxt_id[msgctxt_len - 1] = '\004';
  260. memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
  261. translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
  262. found_translation = !(translation == msg_ctxt_id || translation == msgid_plural);
  263. #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
  264. if (msg_ctxt_id != buf)
  265. free (msg_ctxt_id);
  266. #endif
  267. if (found_translation)
  268. return translation;
  269. }
  270. return (n == 1 ? msgid : msgid_plural);
  271. }
  272. #endif /* _LIBGETTEXT_H */