xref: /illumos-gate/usr/src/lib/libc/port/i18n/wdresolve.c (revision b599bd937c305a895426e8c412ca920ce7824850)
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 #include "lint.h"
28 #include "mtlib.h"
29 #include <sys/types.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <euc.h>
34 #include <widec.h>
35 #include <wctype.h>
36 #include <limits.h>
37 #include <synch.h>
38 #include <thread.h>
39 #include <libintl.h>
40 #include "libc.h"
41 
42 #include <locale.h>
43 #include <dlfcn.h>
44 #include "_loc_path.h"
45 
46 static int	wdchkind_C(wchar_t);
47 static int	(*wdchknd)(wchar_t) = wdchkind_C;
48 static int	wdbindf_C(wchar_t, wchar_t, int);
49 static int	(*wdbdg)(wchar_t, wchar_t, int) = wdbindf_C;
50 static wchar_t	*wddelim_C(wchar_t, wchar_t, int);
51 static wchar_t	*(*wddlm)(wchar_t, wchar_t, int) = wddelim_C;
52 static wchar_t	(*mcfllr)(void) = NULL;
53 static int	(*mcwrp)(void) = NULL;
54 static void	*modhandle = NULL;
55 static int	initialized = 0;
56 
57 static int
58 _wdinitialize(void)
59 {
60 #define	_DFLTLOCPATH_LEN	(sizeof (_DFLT_LOC_PATH) - 1)
61 #define	_WDMODPATH_LEN		(sizeof (_WDMOD_PATH) - 1)
62 	char	wdmodpath[PATH_MAX];
63 	char	*loc;
64 	size_t	loclen;
65 	locale_t	curloc;
66 
67 	initialized = 1;
68 
69 	if (modhandle)
70 		(void) dlclose(modhandle);
71 
72 	curloc = uselocale(NULL);
73 	loc = current_locale(curloc, LC_CTYPE);
74 	loclen = strlen(loc);
75 	if (_DFLTLOCPATH_LEN + loclen + _WDMODPATH_LEN >= sizeof (wdmodpath)) {
76 		/* pathname too long */
77 		modhandle = NULL;
78 		goto C_fallback;
79 	}
80 
81 	(void) strcpy(wdmodpath, _DFLT_LOC_PATH);
82 	(void) strcpy(wdmodpath + _DFLTLOCPATH_LEN, loc);
83 	(void) strcpy(wdmodpath + _DFLTLOCPATH_LEN + loclen, _WDMOD_PATH);
84 
85 	if ((modhandle = dlopen(wdmodpath, RTLD_LAZY)) != NULL) {
86 		wdchknd = (int(*)(wchar_t))dlsym(modhandle, "_wdchkind_");
87 		if (wdchknd == NULL)
88 			wdchknd = wdchkind_C;
89 		wdbdg = (int(*)(wchar_t, wchar_t, int))dlsym(modhandle,
90 		    "_wdbindf_");
91 		if (wdbdg == NULL)
92 			wdbdg = wdbindf_C;
93 		wddlm = (wchar_t *(*)(wchar_t, wchar_t, int))
94 		    dlsym(modhandle, "_wddelim_");
95 		if (wddlm == NULL)
96 			wddlm = wddelim_C;
97 		mcfllr = (wchar_t(*)(void))dlsym(modhandle, "_mcfiller_");
98 		mcwrp = (int(*)(void))dlsym(modhandle, "_mcwrap_");
99 		return ((mcfllr && mcwrp) ? 0 : -1);
100 	}
101 
102 C_fallback:
103 	wdchknd = wdchkind_C;
104 	wdbdg = wdbindf_C;
105 	wddlm = wddelim_C;
106 	mcfllr = NULL;
107 	mcwrp = NULL;
108 	return (-1);
109 }
110 
111 /*
112  * wdinit() initializes other word-analyzing routines according to the
113  * current locale.  Programmers are supposed to call this routine every
114  * time the locale for the LC_CTYPE category is changed.  It returns 0
115  * when every initialization completes successfully, or -1 otherwise.
116  */
117 /* XXX: wdinit() is not exported from libc.  Should it be? */
118 int
119 wdinit()
120 {
121 	int res;
122 
123 	callout_lock_enter();
124 	res = _wdinitialize();
125 	callout_lock_exit();
126 	return (res);
127 }
128 
129 /*
130  * wdchkind() returns a non-negative integral value unique to the kind
131  * of the character represented by given argument.
132  */
133 int
134 wdchkind(wchar_t wc)
135 {
136 	int i;
137 
138 	callout_lock_enter();
139 	if (!initialized)
140 		(void) _wdinitialize();
141 	i = (*wdchknd)(wc);
142 	callout_lock_exit();
143 	return (i);
144 }
145 static int
146 wdchkind_C(wchar_t wc)
147 {
148 	switch (wcsetno(wc)) {
149 	case 1:
150 		return (2);
151 	case 2:
152 		return (3);
153 	case 3:
154 		return (4);
155 	case 0:
156 		return (isascii(wc) &&
157 		    (isalpha(wc) || isdigit(wc) || wc == ' '));
158 	}
159 	return (0);
160 }
161 
162 /*
163  * wdbindf() returns an integral value (0 - 7) indicating binding
164  *  strength of two characters represented by the first two arguments.
165  * It returns -1 when either of the two character is not printable.
166  */
167 /*ARGSUSED*/
168 int
169 wdbindf(wchar_t wc1, wchar_t wc2, int type)
170 {
171 	int i;
172 
173 	callout_lock_enter();
174 	if (!initialized)
175 		(void) _wdinitialize();
176 	if (!iswprint(wc1) || !iswprint(wc2)) {
177 		callout_lock_exit();
178 		return (-1);
179 	}
180 	i = (*wdbdg)(wc1, wc2, type);
181 	callout_lock_exit();
182 	return (i);
183 }
184 /*ARGSUSED*/
185 static int
186 wdbindf_C(wchar_t wc1, wchar_t wc2, int type)
187 {
188 	if (csetlen(wc1) > 1 && csetlen(wc2) > 1)
189 		return (4);
190 	return (6);
191 }
192 
193 /*
194  * wddelim() returns a pointer to a null-terminated word delimiter
195  * string in wchar_t type that is thought most appropriate to join
196  * a text line ending with the first argument and a line beginning
197  * with the second argument, with.  When either of the two character
198  * is not printable it returns a pointer to a null wide character.
199  */
200 /*ARGSUSED*/
201 wchar_t *
202 wddelim(wchar_t wc1, wchar_t wc2, int type)
203 {
204 	wchar_t *i;
205 
206 	callout_lock_enter();
207 	if (!initialized)
208 		(void) _wdinitialize();
209 	if (!iswprint(wc1) || !iswprint(wc2)) {
210 		callout_lock_exit();
211 		return ((wchar_t *)L"");
212 	}
213 	i = (*wddlm)(wc1, wc2, type);
214 	callout_lock_exit();
215 	return (i);
216 }
217 /*ARGSUSED*/
218 static wchar_t *
219 wddelim_C(wchar_t wc1, wchar_t wc2, int type)
220 {
221 	return ((wchar_t *)L" ");
222 }
223 
224 /*
225  * mcfiller returns a printable ASCII character suggested for use in
226  * filling space resulted by a multicolumn character at the right margin.
227  */
228 wchar_t
229 mcfiller(void)
230 {
231 	wchar_t fillerchar;
232 
233 	callout_lock_enter();
234 	if (!initialized)
235 		(void) _wdinitialize();
236 	if (mcfllr) {
237 		fillerchar = (*mcfllr)();
238 		if (!fillerchar)
239 			fillerchar = (wchar_t)'~';
240 		if (iswprint(fillerchar)) {
241 			callout_lock_exit();
242 			return (fillerchar);
243 		}
244 	}
245 	callout_lock_exit();
246 	return ((wchar_t)'~');
247 }
248 
249 /*
250  * mcwrap returns an integral value indicating if a multicolumn character
251  * on the right margin should be wrapped around on a terminal screen.
252  */
253 /* XXX: mcwrap() is not exported from libc.  Should it be? */
254 int
255 mcwrap(void)
256 {
257 	callout_lock_enter();
258 	if (!initialized)
259 		(void) _wdinitialize();
260 	if (mcwrp)
261 		if ((*mcwrp)() == 0) {
262 			callout_lock_exit();
263 			return (0);
264 		}
265 	callout_lock_exit();
266 	return (1);
267 }
268