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 #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
wdinit()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
wdchkind(wchar_t wc)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
wdchkind_C(wchar_t wc)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
wdbindf(wchar_t wc1,wchar_t wc2,int type)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
wdbindf_C(wchar_t wc1,wchar_t wc2,int type __unused)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 *
wddelim(wchar_t wc1,wchar_t wc2,int type)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 *
wddelim_C(wchar_t wc1 __unused,wchar_t wc2 __unused,int type __unused)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
mcfiller(void)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
mcwrap(void)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