gettext.h revision 1.1.1.2 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