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