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