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 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "lint.h"
30 #include "mtlib.h"
31 #include <sys/types.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <euc.h>
36 #include <widec.h>
37 #include <wctype.h>
38 #include <limits.h>
39 #include <synch.h>
40 #include <thread.h>
41 #include <libintl.h>
42 #include "libc.h"
43
44 #include <locale.h>
45 #include <dlfcn.h>
46 #include "_loc_path.h"
47
48 static int wdchkind_C(wchar_t);
49 static int (*wdchknd)(wchar_t) = wdchkind_C;
50 static int wdbindf_C(wchar_t, wchar_t, int);
51 static int (*wdbdg)(wchar_t, wchar_t, int) = wdbindf_C;
52 static wchar_t *wddelim_C(wchar_t, wchar_t, int);
53 static wchar_t *(*wddlm)(wchar_t, wchar_t, int) = wddelim_C;
54 static wchar_t (*mcfllr)(void) = NULL;
55 static int (*mcwrp)(void) = NULL;
56 static void *modhandle = NULL;
57 static int initialized = 0;
58
59 static int
_wdinitialize(void)60 _wdinitialize(void)
61 {
62 #define _DFLTLOCPATH_LEN (sizeof (_DFLT_LOC_PATH) - 1)
63 #define _WDMODPATH_LEN (sizeof (_WDMOD_PATH) - 1)
64 char wdmodpath[PATH_MAX];
65 char *loc;
66 size_t loclen;
67
68 initialized = 1;
69
70 if (modhandle)
71 (void) dlclose(modhandle);
72
73 loc = setlocale(LC_CTYPE, NULL); /* this never return NULL */
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 /*ARGSUSED*/
168 int
wdbindf(wchar_t wc1,wchar_t wc2,int type)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
wdbindf_C(wchar_t wc1,wchar_t wc2,int type)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 *
wddelim(wchar_t wc1,wchar_t wc2,int type)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 *
wddelim_C(wchar_t wc1,wchar_t wc2,int type)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
mcfiller(void)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
mcwrap(void)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