setrunelocale.c revision 227753
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 * Copyright (c) 2011 The FreeBSD Foundation
9 * All rights reserved.
10 * Portions of this software were developed by David Chisnall
11 * under sponsorship from the FreeBSD Foundation.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: head/lib/libc/locale/setrunelocale.c 227753 2011-11-20 14:45:42Z theraven $");
40
41#include <runetype.h>
42#include <errno.h>
43#include <limits.h>
44#include <string.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <unistd.h>
48#include <wchar.h>
49#include "ldpart.h"
50#include "mblocal.h"
51#include "setlocale.h"
52
53extern int __mb_sb_limit;
54
55extern _RuneLocale	*_Read_RuneMagi(FILE *);
56
57static int		__setrunelocale(struct xlocale_ctype *l, const char *);
58
59#define __collate_load_error (table->__collate_load_error)
60#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial)
61#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
62#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
63#define __collate_chain_pri_table (table->__collate_chain_pri_table)
64
65
66static void destruct_ctype(void *v)
67{
68	struct xlocale_ctype *l = v;
69	if (strcmp(l->runes->__encoding, "EUC") == 0)
70		free(l->runes->__variable);
71	if (&_DefaultRuneLocale != l->runes)
72		free(l->runes);
73	free(l);
74}
75_RuneLocale *__getCurrentRuneLocale(void)
76{
77	return XLOCALE_CTYPE(__get_locale())->runes;
78}
79
80static int
81__setrunelocale(struct xlocale_ctype *l, const char *encoding)
82{
83	FILE *fp;
84	char name[PATH_MAX];
85	_RuneLocale *rl;
86	int saverr, ret;
87	struct xlocale_ctype saved = *l;
88
89	/*
90	 * The "C" and "POSIX" locale are always here.
91	 */
92	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
93		(void) _none_init(l, (_RuneLocale*)&_DefaultRuneLocale);
94		return (0);
95	}
96
97	/* Range checking not needed, encoding length already checked before */
98	(void) strcpy(name, _PathLocale);
99	(void) strcat(name, "/");
100	(void) strcat(name, encoding);
101	(void) strcat(name, "/LC_CTYPE");
102
103	if ((fp = fopen(name, "r")) == NULL)
104		return (errno == 0 ? ENOENT : errno);
105
106	if ((rl = _Read_RuneMagi(fp)) == NULL) {
107		saverr = (errno == 0 ? EFTYPE : errno);
108		(void)fclose(fp);
109		return (saverr);
110	}
111	(void)fclose(fp);
112
113	l->__mbrtowc = NULL;
114	l->__mbsinit = NULL;
115	l->__mbsnrtowcs = __mbsnrtowcs_std;
116	l->__wcrtomb = NULL;
117	l->__wcsnrtombs = __wcsnrtombs_std;
118
119	rl->__sputrune = NULL;
120	rl->__sgetrune = NULL;
121	if (strcmp(rl->__encoding, "NONE") == 0)
122		ret = _none_init(l, rl);
123	else if (strcmp(rl->__encoding, "ASCII") == 0)
124		ret = _ascii_init(l, rl);
125	else if (strcmp(rl->__encoding, "UTF-8") == 0)
126		ret = _UTF8_init(l, rl);
127	else if (strcmp(rl->__encoding, "EUC") == 0)
128		ret = _EUC_init(l, rl);
129	else if (strcmp(rl->__encoding, "GB18030") == 0)
130 		ret = _GB18030_init(l, rl);
131	else if (strcmp(rl->__encoding, "GB2312") == 0)
132		ret = _GB2312_init(l, rl);
133	else if (strcmp(rl->__encoding, "GBK") == 0)
134		ret = _GBK_init(l, rl);
135	else if (strcmp(rl->__encoding, "BIG5") == 0)
136		ret = _BIG5_init(l, rl);
137	else if (strcmp(rl->__encoding, "MSKanji") == 0)
138		ret = _MSKanji_init(l, rl);
139	else
140		ret = EFTYPE;
141
142	if (ret == 0) {
143		/* Free the old runes if it exists. */
144		/* FIXME: The "EUC" check here is a hideous abstraction violation. */
145		if ((saved.runes != &_DefaultRuneLocale) && (saved.runes)) {
146			if (strcmp(saved.runes->__encoding, "EUC") == 0) {
147				free(saved.runes->__variable);
148			}
149			free(saved.runes);
150		}
151	} else {
152		/* Restore the saved version if this failed. */
153		memcpy(l, &saved, sizeof(struct xlocale_ctype));
154		free(rl);
155	}
156
157	return (ret);
158}
159
160int
161__wrap_setrunelocale(const char *locale)
162{
163	int ret = __setrunelocale(&__xlocale_global_ctype, locale);
164
165	if (ret != 0) {
166		errno = ret;
167		return (_LDP_ERROR);
168	}
169	__mb_cur_max = __xlocale_global_ctype.__mb_cur_max;
170	__mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit;
171	return (_LDP_LOADED);
172}
173void *__ctype_load(const char *locale, locale_t unused)
174{
175	struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1);
176	l->header.header.destructor = destruct_ctype;
177	if (__setrunelocale(l, locale))
178	{
179		free(l);
180		return NULL;
181	}
182	return l;
183}
184