nls.c revision 87866
1/*
2 * Copyright (c) 2000-2001, Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *    This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: nls.c,v 1.8 2001/04/16 12:46:46 bp Exp $
33 */
34
35#include <sys/types.h>
36#include <sys/iconv.h>
37#include <sys/sysctl.h>
38#include <ctype.h>
39#include <dlfcn.h>
40#include <errno.h>
41#include <stdio.h>
42#include <strings.h>
43#include <stdlib.h>
44#include <locale.h>
45#include <err.h>
46#include <netsmb/smb_lib.h>
47
48/*
49 * prototype iconv* functions
50 */
51typedef void *iconv_t;
52
53static iconv_t (*my_iconv_open)(const char *, const char *);
54static size_t(*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
55static int(*my_iconv_close)(iconv_t);
56
57u_char nls_lower[256];
58u_char nls_upper[256];
59
60static iconv_t nls_toext, nls_toloc;
61static int iconv_loaded;
62static void *iconv_lib;
63
64int
65nls_setlocale(const char *name)
66{
67	int i;
68
69	if (setlocale(LC_CTYPE, name) == NULL) {
70		warnx("can't set locale '%s'\n", name);
71		return EINVAL;
72	}
73	for (i = 0; i < 256; i++) {
74		nls_lower[i] = tolower(i);
75		nls_upper[i] = toupper(i);
76	}
77	return 0;
78}
79
80int
81nls_setrecode(const char *local, const char *external)
82{
83	iconv_t icd;
84
85	if (iconv_loaded == 2)
86		return ENOENT;
87	else if (iconv_loaded == 0) {
88		iconv_loaded++;
89		iconv_lib = dlopen("libiconv.so", RTLD_LAZY | RTLD_GLOBAL);
90		if (iconv_lib == NULL) {
91			warn("Unable to load iconv library: %s\n", dlerror());
92			iconv_loaded++;
93			return ENOENT;
94		}
95		my_iconv_open = dlsym(iconv_lib, "iconv_open");
96		my_iconv = dlsym(iconv_lib, "iconv");
97		my_iconv_close = dlsym(iconv_lib, "iconv_close");
98	}
99	if (nls_toext)
100		my_iconv_close(nls_toext);
101	if (nls_toloc)
102		my_iconv_close(nls_toloc);
103	nls_toext = nls_toloc = (iconv_t)0;
104	icd = my_iconv_open(external, local);
105	if (icd == (iconv_t)-1)
106		return errno;
107	nls_toext = icd;
108	icd = my_iconv_open(local, external);
109	if (icd == (iconv_t)-1) {
110		my_iconv_close(nls_toext);
111		nls_toext = (iconv_t)0;
112		return errno;
113	}
114	nls_toloc = icd;
115	return 0;
116}
117
118char *
119nls_str_toloc(char *dst, const char *src)
120{
121	char *p = dst;
122	int inlen, outlen;
123
124	if (!iconv_loaded)
125		return strcpy(dst, src);
126
127	if (nls_toloc == (iconv_t)0)
128		return strcpy(dst, src);
129	inlen = outlen = strlen(src);
130	my_iconv(nls_toloc, NULL, NULL, &p, &outlen);
131	my_iconv(nls_toloc, &src, &inlen, &p, &outlen);
132	*p = 0;
133	return dst;
134}
135
136char *
137nls_str_toext(char *dst, const char *src)
138{
139	char *p = dst;
140	int inlen, outlen;
141
142	if (!iconv_loaded)
143		return strcpy(dst, src);
144
145	if (nls_toext == (iconv_t)0)
146		return strcpy(dst, src);
147	inlen = outlen = strlen(src);
148	my_iconv(nls_toext, NULL, NULL, &p, &outlen);
149	my_iconv(nls_toext, &src, &inlen, &p, &outlen);
150	*p = 0;
151	return dst;
152}
153
154void *
155nls_mem_toloc(void *dst, const void *src, int size)
156{
157	char *p = dst;
158	const char *s = src;
159	int inlen, outlen;
160
161	if (!iconv_loaded)
162		return memcpy(dst, src, size);
163
164	if (size == 0)
165		return NULL;
166
167	if (nls_toloc == (iconv_t)0)
168		return memcpy(dst, src, size);
169	inlen = outlen = size;
170	my_iconv(nls_toloc, NULL, NULL, &p, &outlen);
171	my_iconv(nls_toloc, &s, &inlen, &p, &outlen);
172	return dst;
173}
174
175void *
176nls_mem_toext(void *dst, const void *src, int size)
177{
178	char *p = dst;
179	const char *s = src;
180	int inlen, outlen;
181
182	if (size == 0)
183		return NULL;
184
185	if (!iconv_loaded || nls_toext == (iconv_t)0)
186		return memcpy(dst, src, size);
187
188	inlen = outlen = size;
189	my_iconv(nls_toext, NULL, NULL, &p, &outlen);
190	my_iconv(nls_toext, &s, &inlen, &p, &outlen);
191	return dst;
192}
193
194char *
195nls_str_upper(char *dst, const char *src)
196{
197	char *p = dst;
198
199	while (*src)
200		*dst++ = toupper(*src++);
201	*dst = 0;
202	return p;
203}
204
205char *
206nls_str_lower(char *dst, const char *src)
207{
208	char *p = dst;
209
210	while (*src)
211		*dst++ = tolower(*src++);
212	*dst = 0;
213	return p;
214}
215