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