1/*-
2 * Copyright (c) 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Paul Borman at Krystal Technologies.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its 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 REGENTS 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 REGENTS 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
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: src/lib/libc/locale/setrunelocale.c,v 1.51 2008/01/23 03:05:35 ache Exp $");
35
36#include "xlocale_private.h"
37
38#include <runetype.h>
39#include <errno.h>
40#include <limits.h>
41#include <string.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <wchar.h>
46#include "ldpart.h"
47#include "mblocal.h"
48#include "setlocale.h"
49
50extern struct __xlocale_st_runelocale	*_Read_RuneMagi(FILE *);
51
52#ifdef UNIFDEF_LEGACY_RUNE_APIS
53/* depreciated interfaces */
54rune_t	sgetrune(const char *, size_t, char const **);
55int	sputrune(rune_t, char *, size_t, char **);
56#endif /* UNIFDEF_LEGACY_RUNE_APIS */
57
58__private_extern__ int
59__setrunelocale(const char *encoding, locale_t loc)
60{
61	FILE *fp;
62	char name[PATH_MAX];
63	struct __xlocale_st_runelocale *xrl;
64	_RuneLocale *rl;
65	int saverr, ret;
66	static struct __xlocale_st_runelocale *CachedRuneLocale;
67	extern int __mb_cur_max;
68	extern int __mb_sb_limit;
69	static pthread_lock_t cache_lock = LOCK_INITIALIZER;
70
71	/*
72	 * The "C" and "POSIX" locale are always here.
73	 */
74	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
75		XL_RELEASE(loc->__lc_ctype);
76		loc->__lc_ctype = &_DefaultRuneXLocale;
77		/* no need to retain _DefaultRuneXLocale */
78		if (loc == &__global_locale) {
79			_CurrentRuneLocale = &loc->__lc_ctype->_CurrentRuneLocale;
80			__mb_cur_max = loc->__lc_ctype->__mb_cur_max;
81			__mb_sb_limit = loc->__lc_ctype->__mb_sb_limit;
82		}
83		return (0);
84	}
85
86	/*
87	 * If the locale name is the same as our cache, use the cache.
88	 */
89	LOCK(cache_lock);
90	if (CachedRuneLocale != NULL &&
91	    strcmp(encoding, CachedRuneLocale->__ctype_encoding) == 0) {
92		XL_RELEASE(loc->__lc_ctype);
93		loc->__lc_ctype = CachedRuneLocale;
94		XL_RETAIN(loc->__lc_ctype);
95		if (loc == &__global_locale) {
96			_CurrentRuneLocale = &loc->__lc_ctype->_CurrentRuneLocale;
97			__mb_cur_max = loc->__lc_ctype->__mb_cur_max;
98			__mb_sb_limit = loc->__lc_ctype->__mb_sb_limit;
99		}
100		UNLOCK(cache_lock);
101		return (0);
102	}
103	UNLOCK(cache_lock);
104
105	/*
106	 * Slurp the locale file into the cache.
107	 */
108
109	/* Range checking not needed, encoding length already checked before */
110	(void) strcpy(name, _PathLocale);
111	(void) strcat(name, "/");
112	(void) strcat(name, encoding);
113	(void) strcat(name, "/LC_CTYPE");
114
115	if ((fp = fopen(name, "r")) == NULL)
116		return (errno == 0 ? ENOENT : errno);
117
118	if ((xrl = _Read_RuneMagi(fp)) == NULL) {
119		saverr = (errno == 0 ? EFTYPE : errno);
120		(void)fclose(fp);
121		return (saverr);
122	}
123	(void)fclose(fp);
124
125	xrl->__mbrtowc = NULL;
126	xrl->__mbsinit = NULL;
127	xrl->__mbsnrtowcs = __mbsnrtowcs_std;
128	xrl->__wcrtomb = NULL;
129	xrl->__wcsnrtombs = __wcsnrtombs_std;
130
131	rl = &xrl->_CurrentRuneLocale;
132
133#ifdef UNIFDEF_LEGACY_RUNE_APIS
134	/* provide backwards compatibility (depreciated interface) */
135	rl->__sputrune = sputrune;
136	rl->__sgetrune = sgetrune;
137#else /* UNIFDEF_LEGACY_RUNE_APIS */
138	rl->__sputrune = NULL;
139	rl->__sgetrune = NULL;
140#endif /* UNIFDEF_LEGACY_RUNE_APIS */
141
142	if (strcmp(rl->__encoding, "NONE") == 0)
143		ret = _none_init(xrl);
144	else if (strcmp(rl->__encoding, "ASCII") == 0)
145		ret = _ascii_init(xrl);
146	else if (strcmp(rl->__encoding, "UTF-8") == 0)
147		ret = _UTF8_init(xrl);
148	else if (strcmp(rl->__encoding, "EUC") == 0)
149		ret = _EUC_init(xrl);
150	else if (strcmp(rl->__encoding, "GB18030") == 0)
151 		ret = _GB18030_init(xrl);
152	else if (strcmp(rl->__encoding, "GB2312") == 0)
153		ret = _GB2312_init(xrl);
154	else if (strcmp(rl->__encoding, "GBK") == 0)
155		ret = _GBK_init(xrl);
156	else if (strcmp(rl->__encoding, "BIG5") == 0)
157		ret = _BIG5_init(xrl);
158	else if (strcmp(rl->__encoding, "MSKanji") == 0)
159		ret = _MSKanji_init(xrl);
160	else if (strcmp(rl->__encoding, "UTF2") == 0)
161		ret = _UTF2_init(xrl);
162	else
163		ret = EFTYPE;
164
165	if (ret == 0) {
166		(void)strcpy(xrl->__ctype_encoding, encoding);
167		XL_RELEASE(loc->__lc_ctype);
168		loc->__lc_ctype = xrl;
169		if (loc == &__global_locale) {
170			_CurrentRuneLocale = &loc->__lc_ctype->_CurrentRuneLocale;
171			__mb_cur_max = loc->__lc_ctype->__mb_cur_max;
172			__mb_sb_limit = loc->__lc_ctype->__mb_sb_limit;
173		}
174		LOCK(cache_lock);
175		XL_RELEASE(CachedRuneLocale);
176		CachedRuneLocale = xrl;
177		XL_RETAIN(CachedRuneLocale);
178		UNLOCK(cache_lock);
179	} else
180		XL_RELEASE(xrl);
181
182	return (ret);
183}
184
185#ifdef UNIFDEF_LEGACY_RUNE_APIS
186int
187setrunelocale(const char *encoding)
188{
189	int ret;
190
191	XL_LOCK(&__global_locale);
192	ret = __setrunelocale(encoding, &__global_locale);
193	XL_UNLOCK(&__global_locale);
194	return ret;
195}
196#endif /* UNIFDEF_LEGACY_RUNE_APIS */
197
198__private_extern__ int
199__wrap_setrunelocale(const char *locale, locale_t loc)
200{
201	int ret = __setrunelocale(locale, loc);
202
203	if (ret != 0) {
204		errno = ret;
205		return (_LDP_ERROR);
206	}
207	return (_LDP_LOADED);
208}
209
210