1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26/*
27 * Copyright 2015 Joyent, Inc.
28 */
29
30#pragma weak _bindtextdomain = bindtextdomain
31#pragma weak _textdomain = textdomain
32#pragma weak _gettext = gettext
33#pragma weak _dgettext = dgettext
34#pragma weak _dcgettext = dcgettext
35#pragma weak _ngettext = ngettext
36#pragma weak _dngettext = dngettext
37#pragma weak _dcngettext = dcngettext
38#pragma weak _bind_textdomain_codeset = bind_textdomain_codeset
39
40#include "lint.h"
41#include "mtlib.h"
42#include <errno.h>
43#include <ctype.h>
44#include <locale.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <sys/types.h>
48#include <sys/param.h>
49#include <libintl.h>
50#include <thread.h>
51#include <synch.h>
52#include "libc.h"
53#include "_loc_path.h"
54#include "msgfmt.h"
55#include "gettext.h"
56
57#define	INIT_GT(def) \
58	if (!global_gt) { \
59		global_gt = (Gettext_t *)calloc(1, sizeof (Gettext_t)); \
60		if (global_gt) \
61			global_gt->cur_domain = (char *)default_domain; \
62		else { \
63			callout_lock_exit(); \
64			return ((def)); \
65		} \
66	}
67
68const char	*defaultbind = DEFAULT_BINDING;
69const char	default_domain[] = DEFAULT_DOMAIN;
70Gettext_t	*global_gt = NULL;
71
72char *
73bindtextdomain(const char *domain, const char *binding)
74{
75	char	*res;
76
77	callout_lock_enter();
78	INIT_GT(NULL);
79	res = _real_bindtextdomain_u(domain, binding, TP_BINDING);
80	callout_lock_exit();
81	return (res);
82}
83
84char *
85bind_textdomain_codeset(const char *domain, const char *codeset)
86{
87	char	*res;
88
89	callout_lock_enter();
90	INIT_GT(NULL);
91	res = _real_bindtextdomain_u(domain, codeset, TP_CODESET);
92	callout_lock_exit();
93	return (res);
94}
95
96/*
97 * textdomain() sets or queries the name of the current domain of
98 * the active LC_MESSAGES locale category.
99 */
100char *
101textdomain(const char *domain)
102{
103	char	*res;
104	char	tmp_domain[TEXTDOMAINMAX + 1];
105
106	callout_lock_enter();
107	INIT_GT(NULL);
108	res = _textdomain_u(domain, tmp_domain);
109	if (res == NULL) {
110		callout_lock_exit();
111		return (NULL);
112	}
113	callout_lock_exit();
114	return (CURRENT_DOMAIN(global_gt));
115}
116
117/*
118 * gettext() is a pass-thru to _real_gettext_u() with a NULL pointer passed
119 * for domain and LC_MESSAGES passed for category.
120 */
121char *
122gettext(const char *msg_id)
123{
124	char	*res;
125	int	errno_save = errno;
126
127	callout_lock_enter();
128	INIT_GT((char *)msg_id);
129	res = _real_gettext_u(NULL, msg_id, NULL, 0, LC_MESSAGES, 0, NULL);
130	callout_lock_exit();
131	errno = errno_save;
132	return (res);
133}
134
135
136/*
137 * In dcgettext() call, domain is valid only for this call.
138 */
139char *
140dgettext(const char *domain, const char *msg_id)
141{
142	char	*res;
143	int	errno_save = errno;
144
145	callout_lock_enter();
146	INIT_GT((char *)msg_id);
147	res = _real_gettext_u(domain, msg_id, NULL, 0, LC_MESSAGES, 0, NULL);
148	callout_lock_exit();
149	errno = errno_save;
150	return (res);
151}
152
153char *
154dgettext_l(const char *domain, const char *msg_id, locale_t loc)
155{
156	char	*res;
157	int	errno_save = errno;
158
159	callout_lock_enter();
160	INIT_GT((char *)msg_id);
161	res = _real_gettext_u(domain, msg_id, NULL, 0, LC_MESSAGES, 0, loc);
162	callout_lock_exit();
163	errno = errno_save;
164	return (res);
165}
166
167char *
168dcgettext(const char *domain, const char *msg_id, const int category)
169{
170	char	*res;
171	int	errno_save = errno;
172
173	callout_lock_enter();
174	INIT_GT((char *)msg_id);
175	res = _real_gettext_u(domain, msg_id, NULL, 0, category, 0, NULL);
176	callout_lock_exit();
177	errno = errno_save;
178	return (res);
179}
180
181char *
182ngettext(const char *msgid1, const char *msgid2, unsigned long int n)
183{
184	char	*res;
185	int	errno_save = errno;
186
187	callout_lock_enter();
188	INIT_GT((char *)msgid1);
189	res = _real_gettext_u(NULL, msgid1, msgid2, n, LC_MESSAGES, 1, NULL);
190	callout_lock_exit();
191	errno = errno_save;
192	return (res);
193}
194
195char *
196dngettext(const char *domain, const char *msgid1, const char *msgid2,
197	unsigned long int n)
198{
199	char	*res;
200	int	errno_save = errno;
201
202	callout_lock_enter();
203	INIT_GT((char *)msgid1);
204	res = _real_gettext_u(domain, msgid1, msgid2, n, LC_MESSAGES, 1, NULL);
205	callout_lock_exit();
206	errno = errno_save;
207	return (res);
208}
209
210char *
211dcngettext(const char *domain, const char *msgid1, const char *msgid2,
212	unsigned long int n, int category)
213{
214	char	*res;
215	int	errno_save = errno;
216
217	callout_lock_enter();
218	INIT_GT((char *)msgid1);
219	res = _real_gettext_u(domain, msgid1, msgid2, n, category, 1, NULL);
220	callout_lock_exit();
221	errno = errno_save;
222	return (res);
223}
224