xref: /illumos-gate/usr/src/lib/libc/port/i18n/wdresolve.c (revision 1a2d662a91cee3bf82f41cd47c7ae6f3825d9db2)
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 int
168 wdbindf(wchar_t wc1, wchar_t wc2, int type)
169 {
170 	int i;
171 
172 	callout_lock_enter();
173 	if (!initialized)
174 		(void) _wdinitialize();
175 	if (!iswprint(wc1) || !iswprint(wc2)) {
176 		callout_lock_exit();
177 		return (-1);
178 	}
179 	i = (*wdbdg)(wc1, wc2, type);
180 	callout_lock_exit();
181 	return (i);
182 }
183 
184 static int
185 wdbindf_C(wchar_t wc1, wchar_t wc2, int type __unused)
186 {
187 	if (csetlen(wc1) > 1 && csetlen(wc2) > 1)
188 		return (4);
189 	return (6);
190 }
191 
192 /*
193  * wddelim() returns a pointer to a null-terminated word delimiter
194  * string in wchar_t type that is thought most appropriate to join
195  * a text line ending with the first argument and a line beginning
196  * with the second argument, with.  When either of the two character
197  * is not printable it returns a pointer to a null wide character.
198  */
199 wchar_t *
200 wddelim(wchar_t wc1, wchar_t wc2, int type)
201 {
202 	wchar_t *i;
203 
204 	callout_lock_enter();
205 	if (!initialized)
206 		(void) _wdinitialize();
207 	if (!iswprint(wc1) || !iswprint(wc2)) {
208 		callout_lock_exit();
209 		return ((wchar_t *)L"");
210 	}
211 	i = (*wddlm)(wc1, wc2, type);
212 	callout_lock_exit();
213 	return (i);
214 }
215 
216 static wchar_t *
217 wddelim_C(wchar_t wc1 __unused, wchar_t wc2 __unused, int type __unused)
218 {
219 	return ((wchar_t *)L" ");
220 }
221 
222 /*
223  * mcfiller returns a printable ASCII character suggested for use in
224  * filling space resulted by a multicolumn character at the right margin.
225  */
226 wchar_t
227 mcfiller(void)
228 {
229 	wchar_t fillerchar;
230 
231 	callout_lock_enter();
232 	if (!initialized)
233 		(void) _wdinitialize();
234 	if (mcfllr) {
235 		fillerchar = (*mcfllr)();
236 		if (!fillerchar)
237 			fillerchar = (wchar_t)'~';
238 		if (iswprint(fillerchar)) {
239 			callout_lock_exit();
240 			return (fillerchar);
241 		}
242 	}
243 	callout_lock_exit();
244 	return ((wchar_t)'~');
245 }
246 
247 /*
248  * mcwrap returns an integral value indicating if a multicolumn character
249  * on the right margin should be wrapped around on a terminal screen.
250  */
251 /* XXX: mcwrap() is not exported from libc.  Should it be? */
252 int
253 mcwrap(void)
254 {
255 	callout_lock_enter();
256 	if (!initialized)
257 		(void) _wdinitialize();
258 	if (mcwrp)
259 		if ((*mcwrp)() == 0) {
260 			callout_lock_exit();
261 			return (0);
262 		}
263 	callout_lock_exit();
264 	return (1);
265 }
266