1 /* $NetBSD: nb_lc_template.h,v 1.9 2022/04/19 20:32:15 rillig 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 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 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 (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 * 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