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