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