1 /* $NetBSD: nb_lc_template.h,v 1.8 2013/09/13 13:13:32 joerg Exp $ */
2 
3 /*-
4  * Copyright (c)1999, 2008 Citrus Project,
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*-
30  * Copyright (c) 1998 The NetBSD Foundation, Inc.
31  * All rights reserved.
32  *
33  * This code is derived from software contributed to The NetBSD Foundation
34  * by Paul Kranenburg.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55  * POSSIBILITY OF SUCH DAMAGE.
56  */
57 
58 /*-
59  * Copyright (c) 1993
60  *	The Regents of the University of California.  All rights reserved.
61  *
62  * This code is derived from software contributed to Berkeley by
63  * Paul Borman at Krystal Technologies.
64  *
65  * Redistribution and use in source and binary forms, with or without
66  * modification, are permitted provided that the following conditions
67  * are met:
68  * 1. Redistributions of source code must retain the above copyright
69  *    notice, this list of conditions and the following disclaimer.
70  * 2. Redistributions in binary form must reproduce the above copyright
71  *    notice, this list of conditions and the following disclaimer in the
72  *    documentation and/or other materials provided with the distribution.
73  * 3. Neither the name of the University nor the names of its contributors
74  *    may be used to endorse or promote products derived from this software
75  *    without specific prior written permission.
76  *
77  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
78  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
79  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
80  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
81  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
83  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
84  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
85  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
86  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87  * SUCH DAMAGE.
88  */
89 
90 #ifndef _NB_LC_TEMPLATE_H_
91 #define _NB_LC_TEMPLATE_H_
92 
93 #define _nb_part_t		_PREFIX(part_t)
94 #define _nb_part_cache		_PREFIX(part_cache)
95 #define _nb_mutex		_PREFIX(mutex)
96 
97 typedef struct _nb_part_t {
98 	char name[_LOCALENAME_LEN_MAX];
99 	_CATEGORY_TYPE *impl;
100 	SIMPLEQ_ENTRY(_nb_part_t) entry;
101 } _nb_part_t;
102 
103 static SIMPLEQ_HEAD(, _nb_part_t) _nb_part_cache =
104     SIMPLEQ_HEAD_INITIALIZER(_nb_part_cache);
105 
106 #ifdef _REENTRANT
107 static mutex_t _nb_mutex = MUTEX_INITIALIZER;
108 #endif
109 
110 static int
_PREFIX(load_sub)111 _PREFIX(load_sub)(const char * __restrict name, const char * __restrict real,
112     const char ** __restrict out_name, _CATEGORY_TYPE ** __restrict out_impl,
113     int force)
114 {
115 	const char *cached_name;
116 	_CATEGORY_TYPE *cached_impl;
117 	_nb_part_t *p;
118 	int ret;
119 
120 	_DIAGASSERT(name != NULL);
121 	_DIAGASSERT(out_name != NULL);
122 	_DIAGASSERT(out_impl != NULL);
123 
124 	if (!strcmp(_C_LOCALE, name)) {
125 		cached_name = _lc_C_locale.part_name[_CATEGORY_ID];
126 		cached_impl = _lc_C_locale.part_impl[_CATEGORY_ID];
127 	} else if (!strcmp(_POSIX_LOCALE, name)) {
128 		cached_name = _POSIX_LOCALE;
129 		cached_impl = _lc_C_locale.part_impl[_CATEGORY_ID];
130 	} else {
131 		SIMPLEQ_FOREACH(p, &_nb_part_cache, entry) {
132 			if (!strcmp((const char *)&p->name[0], name)) {
133 				cached_name = p->name;
134 				cached_impl = p->impl;
135 				goto found;
136 			}
137 		}
138 		p = malloc(sizeof(*p));
139 		if (p == NULL)
140 			return ENOMEM;
141 		if (force) {
142 			p->impl = _lc_C_locale.part_impl[_CATEGORY_ID];
143 		} else {
144 			_DIAGASSERT(_PathLocale != NULL);
145 			ret = _PREFIX(create_impl)((const char *)_PathLocale,
146 			    name, &p->impl);
147 			if (ret) {
148 				free(p);
149 				return ret;
150 			}
151 		}
152 		strlcpy(&p->name[0], name, sizeof(p->name));
153 		SIMPLEQ_INSERT_TAIL(&_nb_part_cache, p, entry);
154 		cached_name = p->name;
155 		cached_impl = p->impl;
156 	}
157 found:
158 	if (real != NULL) {
159 		p = malloc(sizeof(*p));
160 		if (p == NULL)
161 			return ENOMEM;
162 		strlcpy(&p->name[0], real, sizeof(p->name));
163 		cached_name = p->name;
164 		p->impl = cached_impl;
165 		SIMPLEQ_INSERT_TAIL(&_nb_part_cache, p, entry);
166 	}
167 	*out_name = cached_name;
168 	*out_impl = cached_impl;
169 	return 0;
170 }
171 
172 static __inline int
_PREFIX(load)173 _PREFIX(load)(const char * __restrict name,
174     const char ** __restrict out_name, _CATEGORY_TYPE ** __restrict out_impl)
175 {
176 	int ret, force;
177 	char path[PATH_MAX + 1], loccat[PATH_MAX + 1], buf[PATH_MAX + 1];
178 	const char *aliaspath, *alias;
179 
180 #define _LOAD_SUB_ALIAS(key)						\
181 do {									\
182 	alias = __unaliasname(aliaspath, key, &buf[0], sizeof(buf));	\
183 	if (alias != NULL) {						\
184 		ret = (force = !__isforcemapping(alias))		\
185 		    ? _PREFIX(load_sub)(name, NULL, out_name, out_impl, \
186 				        force)	\
187 		    : _PREFIX(load_sub)(alias, name, out_name, out_impl, \
188 				        force);	\
189 		_DIAGASSERT(!ret || !force);				\
190 		goto done;						\
191 	}								\
192 } while (/*CONSTCOND*/0)
193 
194 	/* (1) non-aliased file */
195 	mutex_lock(&_nb_mutex);
196 	ret = _PREFIX(load_sub)(name, NULL, out_name, out_impl, 0);
197 	if (ret != ENOENT)
198 		goto done;
199 
200 	/* (2) lookup locname/catname type alias */
201 	_DIAGASSERT(_PathLocale != NULL);
202 	snprintf(&path[0], sizeof(path),
203 	    "%s/" _LOCALE_ALIAS_NAME, _PathLocale);
204 	aliaspath = (const char *)&path[0];
205 	snprintf(&loccat[0], sizeof(loccat),
206 	    "%s/" _CATEGORY_NAME, name);
207 	_LOAD_SUB_ALIAS((const char *)&loccat[0]);
208 
209 	/* (3) lookup locname type alias */
210 	_LOAD_SUB_ALIAS(name);
211 
212 done:
213 	mutex_unlock(&_nb_mutex);
214 	return ret;
215 }
216 
217 const char *
_PREFIX(setlocale)218 _PREFIX(setlocale)(const char * __restrict name,
219     struct _locale * __restrict locale)
220 {
221 	const char *loaded_name;
222 	_CATEGORY_TYPE *loaded_impl;
223 
224 	/* name may be NULL */
225 	_DIAGASSERT(locale != NULL);
226 
227 	if (name != NULL) {
228 		if (*name == '\0')
229 			name = _get_locale_env(_CATEGORY_NAME);
230 		_DIAGASSERT(name != NULL);
231 		_DIAGASSERT(locale->part_name[(size_t)_CATEGORY_ID] != NULL);
232 		if (strcmp(name, locale->part_name[(size_t)_CATEGORY_ID])) {
233 			if (_PREFIX(load)(name, &loaded_name, &loaded_impl))
234 				return NULL;
235 			locale->part_name[(size_t)_CATEGORY_ID] = loaded_name;
236 			locale->part_impl[(size_t)_CATEGORY_ID] = loaded_impl;
237 			if (locale == &_lc_global_locale)
238 				_PREFIX(update_global)(loaded_impl);
239 		}
240 	}
241 	return locale->part_name[(size_t)_CATEGORY_ID];
242 }
243 
244 #endif /*_NB_LC_TEMPLATE_H_*/
245