1275970Scy/* Convenience header for conditional use of GNU <libintl.h>.
2285169Scy   Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2015 Free Software
3275970Scy   Foundation, Inc.
4275970Scy
5275970Scy   This program is free software; you can redistribute it and/or modify
6275970Scy   it under the terms of the GNU Lesser General Public License as published by
7275970Scy   the Free Software Foundation; either version 2.1, or (at your option)
8275970Scy   any later version.
9275970Scy
10275970Scy   This program is distributed in the hope that it will be useful,
11275970Scy   but WITHOUT ANY WARRANTY; without even the implied warranty of
12275970Scy   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13275970Scy   GNU Lesser General Public License for more details.
14275970Scy
15275970Scy   You should have received a copy of the GNU Lesser General Public License along
16275970Scy   with this program; if not, see <http://www.gnu.org/licenses/>.  */
17275970Scy
18275970Scy#ifndef _LIBGETTEXT_H
19275970Scy#define _LIBGETTEXT_H 1
20275970Scy
21275970Scy/* NLS can be disabled through the configure --disable-nls option.  */
22275970Scy#if ENABLE_NLS
23275970Scy
24275970Scy/* Get declarations of GNU message catalog functions.  */
25275970Scy# include <libintl.h>
26275970Scy
27275970Scy/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
28275970Scy   the gettext() and ngettext() macros.  This is an alternative to calling
29275970Scy   textdomain(), and is useful for libraries.  */
30275970Scy# ifdef DEFAULT_TEXT_DOMAIN
31275970Scy#  undef gettext
32275970Scy#  define gettext(Msgid) \
33275970Scy     dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
34275970Scy#  undef ngettext
35275970Scy#  define ngettext(Msgid1, Msgid2, N) \
36275970Scy     dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
37275970Scy# endif
38275970Scy
39275970Scy#else
40275970Scy
41275970Scy/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
42275970Scy   chokes if dcgettext is defined as a macro.  So include it now, to make
43275970Scy   later inclusions of <locale.h> a NOP.  We don't include <libintl.h>
44275970Scy   as well because people using "gettext.h" will not include <libintl.h>,
45275970Scy   and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
46275970Scy   is OK.  */
47275970Scy#if defined(__sun)
48275970Scy# include <locale.h>
49275970Scy#endif
50275970Scy
51275970Scy/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
52275970Scy   <libintl.h>, which chokes if dcgettext is defined as a macro.  So include
53275970Scy   it now, to make later inclusions of <libintl.h> a NOP.  */
54275970Scy#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
55275970Scy# include <cstdlib>
56275970Scy# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H
57275970Scy#  include <libintl.h>
58275970Scy# endif
59275970Scy#endif
60275970Scy
61275970Scy/* Disabled NLS.
62275970Scy   The casts to 'const char *' serve the purpose of producing warnings
63275970Scy   for invalid uses of the value returned from these functions.
64275970Scy   On pre-ANSI systems without 'const', the config.h file is supposed to
65275970Scy   contain "#define const".  */
66275970Scy# undef gettext
67275970Scy# define gettext(Msgid) ((const char *) (Msgid))
68275970Scy# undef dgettext
69275970Scy# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
70275970Scy# undef dcgettext
71275970Scy# define dcgettext(Domainname, Msgid, Category) \
72275970Scy    ((void) (Category), dgettext (Domainname, Msgid))
73275970Scy# undef ngettext
74275970Scy# define ngettext(Msgid1, Msgid2, N) \
75275970Scy    ((N) == 1 \
76275970Scy     ? ((void) (Msgid2), (const char *) (Msgid1)) \
77275970Scy     : ((void) (Msgid1), (const char *) (Msgid2)))
78275970Scy# undef dngettext
79275970Scy# define dngettext(Domainname, Msgid1, Msgid2, N) \
80275970Scy    ((void) (Domainname), ngettext (Msgid1, Msgid2, N))
81275970Scy# undef dcngettext
82275970Scy# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
83275970Scy    ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N))
84275970Scy# undef textdomain
85275970Scy# define textdomain(Domainname) ((const char *) (Domainname))
86275970Scy# undef bindtextdomain
87275970Scy# define bindtextdomain(Domainname, Dirname) \
88275970Scy    ((void) (Domainname), (const char *) (Dirname))
89275970Scy# undef bind_textdomain_codeset
90275970Scy# define bind_textdomain_codeset(Domainname, Codeset) \
91275970Scy    ((void) (Domainname), (const char *) (Codeset))
92275970Scy
93275970Scy#endif
94275970Scy
95275970Scy/* Prefer gnulib's setlocale override over libintl's setlocale override.  */
96275970Scy#ifdef GNULIB_defined_setlocale
97275970Scy# undef setlocale
98275970Scy# define setlocale rpl_setlocale
99275970Scy#endif
100275970Scy
101275970Scy/* A pseudo function call that serves as a marker for the automated
102275970Scy   extraction of messages, but does not call gettext().  The run-time
103275970Scy   translation is done at a different place in the code.
104275970Scy   The argument, String, should be a literal string.  Concatenated strings
105275970Scy   and other string expressions won't work.
106275970Scy   The macro's expansion is not parenthesized, so that it is suitable as
107275970Scy   initializer for static 'char[]' or 'const char[]' variables.  */
108275970Scy#define gettext_noop(String) String
109275970Scy
110275970Scy/* The separator between msgctxt and msgid in a .mo file.  */
111275970Scy#define GETTEXT_CONTEXT_GLUE "\004"
112275970Scy
113275970Scy/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
114275970Scy   MSGID.  MSGCTXT and MSGID must be string literals.  MSGCTXT should be
115275970Scy   short and rarely need to change.
116275970Scy   The letter 'p' stands for 'particular' or 'special'.  */
117275970Scy#ifdef DEFAULT_TEXT_DOMAIN
118275970Scy# define pgettext(Msgctxt, Msgid) \
119275970Scy   pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
120275970Scy#else
121275970Scy# define pgettext(Msgctxt, Msgid) \
122275970Scy   pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
123275970Scy#endif
124275970Scy#define dpgettext(Domainname, Msgctxt, Msgid) \
125275970Scy  pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
126275970Scy#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
127275970Scy  pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
128275970Scy#ifdef DEFAULT_TEXT_DOMAIN
129275970Scy# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
130275970Scy   npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
131275970Scy#else
132275970Scy# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
133275970Scy   npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
134275970Scy#endif
135275970Scy#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
136275970Scy  npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
137275970Scy#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
138275970Scy  npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
139275970Scy
140275970Scy#ifdef __GNUC__
141275970Scy__inline
142275970Scy#else
143275970Scy#ifdef __cplusplus
144275970Scyinline
145275970Scy#endif
146275970Scy#endif
147275970Scystatic const char *
148275970Scypgettext_aux (const char *domain,
149275970Scy              const char *msg_ctxt_id, const char *msgid,
150275970Scy              int category)
151275970Scy{
152275970Scy  const char *translation = dcgettext (domain, msg_ctxt_id, category);
153275970Scy  if (translation == msg_ctxt_id)
154275970Scy    return msgid;
155275970Scy  else
156275970Scy    return translation;
157275970Scy}
158275970Scy
159275970Scy#ifdef __GNUC__
160275970Scy__inline
161275970Scy#else
162275970Scy#ifdef __cplusplus
163275970Scyinline
164275970Scy#endif
165275970Scy#endif
166275970Scystatic const char *
167275970Scynpgettext_aux (const char *domain,
168275970Scy               const char *msg_ctxt_id, const char *msgid,
169275970Scy               const char *msgid_plural, unsigned long int n,
170275970Scy               int category)
171275970Scy{
172275970Scy  const char *translation =
173275970Scy    dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
174275970Scy  if (translation == msg_ctxt_id || translation == msgid_plural)
175275970Scy    return (n == 1 ? msgid : msgid_plural);
176275970Scy  else
177275970Scy    return translation;
178275970Scy}
179275970Scy
180275970Scy/* The same thing extended for non-constant arguments.  Here MSGCTXT and MSGID
181275970Scy   can be arbitrary expressions.  But for string literals these macros are
182275970Scy   less efficient than those above.  */
183275970Scy
184275970Scy#include <string.h>
185275970Scy
186275970Scy#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
187275970Scy     /* || __STDC_VERSION__ >= 199901L */ )
188275970Scy# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
189275970Scy#else
190275970Scy# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
191275970Scy#endif
192275970Scy
193275970Scy#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
194275970Scy#include <stdlib.h>
195275970Scy#endif
196275970Scy
197275970Scy#define pgettext_expr(Msgctxt, Msgid) \
198275970Scy  dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
199275970Scy#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
200275970Scy  dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
201275970Scy
202275970Scy#ifdef __GNUC__
203275970Scy__inline
204275970Scy#else
205275970Scy#ifdef __cplusplus
206275970Scyinline
207275970Scy#endif
208275970Scy#endif
209275970Scystatic const char *
210275970Scydcpgettext_expr (const char *domain,
211275970Scy                 const char *msgctxt, const char *msgid,
212275970Scy                 int category)
213275970Scy{
214275970Scy  size_t msgctxt_len = strlen (msgctxt) + 1;
215275970Scy  size_t msgid_len = strlen (msgid) + 1;
216275970Scy  const char *translation;
217275970Scy#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
218275970Scy  char msg_ctxt_id[msgctxt_len + msgid_len];
219275970Scy#else
220275970Scy  char buf[1024];
221275970Scy  char *msg_ctxt_id =
222275970Scy    (msgctxt_len + msgid_len <= sizeof (buf)
223275970Scy     ? buf
224275970Scy     : (char *) malloc (msgctxt_len + msgid_len));
225275970Scy  if (msg_ctxt_id != NULL)
226275970Scy#endif
227275970Scy    {
228275970Scy      memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
229275970Scy      msg_ctxt_id[msgctxt_len - 1] = '\004';
230275970Scy      memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
231275970Scy      translation = dcgettext (domain, msg_ctxt_id, category);
232275970Scy#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
233275970Scy      if (msg_ctxt_id != buf)
234275970Scy        free (msg_ctxt_id);
235275970Scy#endif
236275970Scy      if (translation != msg_ctxt_id)
237275970Scy        return translation;
238275970Scy    }
239275970Scy  return msgid;
240275970Scy}
241275970Scy
242275970Scy#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
243275970Scy  dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
244275970Scy#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
245275970Scy  dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
246275970Scy
247275970Scy#ifdef __GNUC__
248275970Scy__inline
249275970Scy#else
250275970Scy#ifdef __cplusplus
251275970Scyinline
252275970Scy#endif
253275970Scy#endif
254275970Scystatic const char *
255275970Scydcnpgettext_expr (const char *domain,
256275970Scy                  const char *msgctxt, const char *msgid,
257275970Scy                  const char *msgid_plural, unsigned long int n,
258275970Scy                  int category)
259275970Scy{
260275970Scy  size_t msgctxt_len = strlen (msgctxt) + 1;
261275970Scy  size_t msgid_len = strlen (msgid) + 1;
262275970Scy  const char *translation;
263275970Scy#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
264275970Scy  char msg_ctxt_id[msgctxt_len + msgid_len];
265275970Scy#else
266275970Scy  char buf[1024];
267275970Scy  char *msg_ctxt_id =
268275970Scy    (msgctxt_len + msgid_len <= sizeof (buf)
269275970Scy     ? buf
270275970Scy     : (char *) malloc (msgctxt_len + msgid_len));
271275970Scy  if (msg_ctxt_id != NULL)
272275970Scy#endif
273275970Scy    {
274275970Scy      memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
275275970Scy      msg_ctxt_id[msgctxt_len - 1] = '\004';
276275970Scy      memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
277275970Scy      translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
278275970Scy#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
279275970Scy      if (msg_ctxt_id != buf)
280275970Scy        free (msg_ctxt_id);
281275970Scy#endif
282275970Scy      if (!(translation == msg_ctxt_id || translation == msgid_plural))
283275970Scy        return translation;
284275970Scy    }
285275970Scy  return (n == 1 ? msgid : msgid_plural);
286275970Scy}
287275970Scy
288275970Scy#endif /* _LIBGETTEXT_H */
289