setrunelocale.c revision 232498
111695Sache/*-
211695Sache * Copyright (c) 1993
311695Sache *	The Regents of the University of California.  All rights reserved.
411695Sache *
511695Sache * This code is derived from software contributed to Berkeley by
611695Sache * Paul Borman at Krystal Technologies.
711695Sache *
8227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation
9227753Stheraven * All rights reserved.
10227753Stheraven * Portions of this software were developed by David Chisnall
11227753Stheraven * under sponsorship from the FreeBSD Foundation.
12227753Stheraven *
1311695Sache * Redistribution and use in source and binary forms, with or without
1411695Sache * modification, are permitted provided that the following conditions
1511695Sache * are met:
1611695Sache * 1. Redistributions of source code must retain the above copyright
1711695Sache *    notice, this list of conditions and the following disclaimer.
1811695Sache * 2. Redistributions in binary form must reproduce the above copyright
1911695Sache *    notice, this list of conditions and the following disclaimer in the
2011695Sache *    documentation and/or other materials provided with the distribution.
2111695Sache * 4. Neither the name of the University nor the names of its contributors
2211695Sache *    may be used to endorse or promote products derived from this software
2311695Sache *    without specific prior written permission.
2411695Sache *
2511695Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2611695Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2711695Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2811695Sache * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2911695Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3011695Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3111695Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3211695Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3311695Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3411695Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3511695Sache * SUCH DAMAGE.
3611695Sache */
3711695Sache
3892986Sobrien#include <sys/cdefs.h>
3992986Sobrien__FBSDID("$FreeBSD: head/lib/libc/locale/setrunelocale.c 232498 2012-03-04 15:31:13Z theraven $");
4092986Sobrien
41232498Stheraven#define __RUNETYPE_INTERNAL 1
42232498Stheraven
43136609Stjr#include <runetype.h>
4411695Sache#include <errno.h>
4511695Sache#include <limits.h>
4611695Sache#include <string.h>
4711695Sache#include <stdio.h>
4811695Sache#include <stdlib.h>
4924694Sache#include <unistd.h>
50121845Stjr#include <wchar.h>
51117270Sache#include "ldpart.h"
52129153Stjr#include "mblocal.h"
5322330Sache#include "setlocale.h"
5411695Sache
55232498Stheraven#undef _CurrentRuneLocale
56232498Stheravenextern _RuneLocale const *_CurrentRuneLocale;
57232498Stheraven#ifndef __NO_TLS
58232498Stheraven/*
59232498Stheraven * A cached version of the runes for this thread.  Used by ctype.h
60232498Stheraven */
61232498Stheraven_Thread_local const _RuneLocale *_ThreadRuneLocale;
62232498Stheraven#endif
63232498Stheraven
64172619Sacheextern int __mb_sb_limit;
65172619Sache
66115626Sacheextern _RuneLocale	*_Read_RuneMagi(FILE *);
6711695Sache
68227753Stheravenstatic int		__setrunelocale(struct xlocale_ctype *l, const char *);
69117270Sache
70227753Stheraven#define __collate_load_error (table->__collate_load_error)
71227753Stheraven#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial)
72227753Stheraven#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
73227753Stheraven#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
74227753Stheraven#define __collate_chain_pri_table (table->__collate_chain_pri_table)
75227753Stheraven
76227753Stheraven
77227753Stheravenstatic void destruct_ctype(void *v)
78227753Stheraven{
79227753Stheraven	struct xlocale_ctype *l = v;
80227753Stheraven	if (strcmp(l->runes->__encoding, "EUC") == 0)
81227753Stheraven		free(l->runes->__variable);
82227753Stheraven	if (&_DefaultRuneLocale != l->runes)
83227753Stheraven		free(l->runes);
84227753Stheraven	free(l);
85227753Stheraven}
86232498Stheraven
87232498Stheravenconst _RuneLocale *__getCurrentRuneLocale(void)
88227753Stheraven{
89227753Stheraven	return XLOCALE_CTYPE(__get_locale())->runes;
90227753Stheraven}
91227753Stheraven
92117270Sachestatic int
93227753Stheraven__setrunelocale(struct xlocale_ctype *l, const char *encoding)
94117270Sache{
9511695Sache	FILE *fp;
9611695Sache	char name[PATH_MAX];
9711695Sache	_RuneLocale *rl;
98101498Sache	int saverr, ret;
99227753Stheraven	struct xlocale_ctype saved = *l;
10011695Sache
10111695Sache	/*
10211695Sache	 * The "C" and "POSIX" locale are always here.
10311695Sache	 */
104101498Sache	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
105227753Stheraven		(void) _none_init(l, (_RuneLocale*)&_DefaultRuneLocale);
106101263Sache		return (0);
10711695Sache	}
10811695Sache
109117270Sache	/* Range checking not needed, encoding length already checked before */
11020810Sjoerg	(void) strcpy(name, _PathLocale);
11120810Sjoerg	(void) strcat(name, "/");
11220810Sjoerg	(void) strcat(name, encoding);
11320810Sjoerg	(void) strcat(name, "/LC_CTYPE");
11411695Sache
11511695Sache	if ((fp = fopen(name, "r")) == NULL)
116101566Sache		return (errno == 0 ? ENOENT : errno);
11711695Sache
118101498Sache	if ((rl = _Read_RuneMagi(fp)) == NULL) {
119101566Sache		saverr = (errno == 0 ? EFTYPE : errno);
120101498Sache		(void)fclose(fp);
121101498Sache		return (saverr);
12211695Sache	}
123101498Sache	(void)fclose(fp);
12411695Sache
125227753Stheraven	l->__mbrtowc = NULL;
126227753Stheraven	l->__mbsinit = NULL;
127227753Stheraven	l->__mbsnrtowcs = __mbsnrtowcs_std;
128227753Stheraven	l->__wcrtomb = NULL;
129227753Stheraven	l->__wcsnrtombs = __wcsnrtombs_std;
130175586Sache
131136609Stjr	rl->__sputrune = NULL;
132136609Stjr	rl->__sgetrune = NULL;
133175586Sache	if (strcmp(rl->__encoding, "NONE") == 0)
134227753Stheraven		ret = _none_init(l, rl);
135175586Sache	else if (strcmp(rl->__encoding, "ASCII") == 0)
136227753Stheraven		ret = _ascii_init(l, rl);
137175586Sache	else if (strcmp(rl->__encoding, "UTF-8") == 0)
138227753Stheraven		ret = _UTF8_init(l, rl);
139175586Sache	else if (strcmp(rl->__encoding, "EUC") == 0)
140227753Stheraven		ret = _EUC_init(l, rl);
141175586Sache	else if (strcmp(rl->__encoding, "GB18030") == 0)
142227753Stheraven 		ret = _GB18030_init(l, rl);
143175586Sache	else if (strcmp(rl->__encoding, "GB2312") == 0)
144227753Stheraven		ret = _GB2312_init(l, rl);
145175586Sache	else if (strcmp(rl->__encoding, "GBK") == 0)
146227753Stheraven		ret = _GBK_init(l, rl);
147175586Sache	else if (strcmp(rl->__encoding, "BIG5") == 0)
148227753Stheraven		ret = _BIG5_init(l, rl);
149175586Sache	else if (strcmp(rl->__encoding, "MSKanji") == 0)
150227753Stheraven		ret = _MSKanji_init(l, rl);
151175586Sache	else
152101498Sache		ret = EFTYPE;
153175585Sache
154101498Sache	if (ret == 0) {
155227753Stheraven		/* Free the old runes if it exists. */
156227753Stheraven		/* FIXME: The "EUC" check here is a hideous abstraction violation. */
157227753Stheraven		if ((saved.runes != &_DefaultRuneLocale) && (saved.runes)) {
158227753Stheraven			if (strcmp(saved.runes->__encoding, "EUC") == 0) {
159227753Stheraven				free(saved.runes->__variable);
160227753Stheraven			}
161227753Stheraven			free(saved.runes);
162101498Sache		}
163175586Sache	} else {
164227753Stheraven		/* Restore the saved version if this failed. */
165227753Stheraven		memcpy(l, &saved, sizeof(struct xlocale_ctype));
166101498Sache		free(rl);
167175586Sache	}
168101498Sache
169101498Sache	return (ret);
17011695Sache}
17111695Sache
172117270Sacheint
173117270Sache__wrap_setrunelocale(const char *locale)
174117270Sache{
175227753Stheraven	int ret = __setrunelocale(&__xlocale_global_ctype, locale);
176117270Sache
177117270Sache	if (ret != 0) {
178117270Sache		errno = ret;
179117270Sache		return (_LDP_ERROR);
180117270Sache	}
181227753Stheraven	__mb_cur_max = __xlocale_global_ctype.__mb_cur_max;
182227753Stheraven	__mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit;
183232498Stheraven	_CurrentRuneLocale = __xlocale_global_ctype.runes;
184117270Sache	return (_LDP_LOADED);
185117270Sache}
186232498Stheraven
187232498Stheraven#ifndef __NO_TLS
188232498Stheravenvoid
189232498Stheraven__set_thread_rune_locale(locale_t loc) {
190232498Stheraven
191232498Stheraven	if (loc == NULL) {
192232498Stheraven		_ThreadRuneLocale = &_DefaultRuneLocale;
193232498Stheraven	} else {
194232498Stheraven		_ThreadRuneLocale = XLOCALE_CTYPE(loc)->runes;
195232498Stheraven	}
196232498Stheraven}
197232498Stheraven#endif
198232498Stheraven
199232498Stheravenvoid *
200232498Stheraven__ctype_load(const char *locale, locale_t unused)
201227753Stheraven{
202227753Stheraven	struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1);
203227753Stheraven	l->header.header.destructor = destruct_ctype;
204227753Stheraven	if (__setrunelocale(l, locale))
205227753Stheraven	{
206227753Stheraven		free(l);
207227753Stheraven		return NULL;
208227753Stheraven	}
209227753Stheraven	return l;
210227753Stheraven}
211