xlocale.c revision 227753
150276Speter/*- 262449Speter * Copyright (c) 2011 The FreeBSD Foundation 350276Speter * All rights reserved. 450276Speter * 550276Speter * This software was developed by David Chisnall under sponsorship from 650276Speter * the FreeBSD Foundation. 750276Speter * 850276Speter * Redistribution and use in source and binary forms, with or without 950276Speter * modification, are permitted provided that the following conditions * are met: 1050276Speter * 1. Redistributions of source code must retain the above copyright notice, 1150276Speter * this list of conditions and the following disclaimer. 1250276Speter * 2. Redistributions in binary form must reproduce the above copyright notice, 1350276Speter * this list of conditions and the following disclaimer in the documentation 1450276Speter * and/or other materials provided with the distribution. 1550276Speter * 1650276Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1750276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1850276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1950276Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2050276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2150276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2250276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2350276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2450276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2550276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2650276Speter * SUCH DAMAGE. 2750276Speter * 2850276Speter * $FreeBSD: head/lib/libc/locale/xlocale.c 227753 2011-11-20 14:45:42Z theraven $ 2950276Speter */ 3050276Speter 3150276Speter#include <pthread.h> 3250276Speter#include <stdio.h> 3397049Speter#include <string.h> 3450276Speter#include "libc_private.h" 3550276Speter#include "xlocale_private.h" 3650276Speter 3750276Speter/** 3850276Speter * Each locale loader declares a global component. This is used by setlocale() 3950276Speter * and also by xlocale with LC_GLOBAL_LOCALE.. 4050276Speter */ 4150276Speterextern struct xlocale_component __xlocale_global_collate; 4266963Speterextern struct xlocale_component __xlocale_global_ctype; 4350276Speterextern struct xlocale_component __xlocale_global_monetary; 4450276Speterextern struct xlocale_component __xlocale_global_numeric; 4550276Speterextern struct xlocale_component __xlocale_global_time; 4650276Speterextern struct xlocale_component __xlocale_global_messages; 4750276Speter/* 4850276Speter * And another version for the statically-allocated C locale. We only have 4950276Speter * components for the parts that are expected to be sensible. 5050276Speter */ 5150276Speterextern struct xlocale_component __xlocale_C_collate; 5250276Speterextern struct xlocale_component __xlocale_C_ctype; 5350276Speter/* 5450276Speter * Private functions in setlocale.c. 5550276Speter */ 5650276Speterconst char * 5750276Speter__get_locale_env(int category); 5850276Speterint 5950276Speter__detect_path_locale(void); 6050276Speter 6150276Speterstruct _xlocale __xlocale_global_locale = { 6250276Speter {0}, 6350276Speter { 6450276Speter &__xlocale_global_collate, 6550276Speter &__xlocale_global_ctype, 6650276Speter &__xlocale_global_monetary, 6750276Speter &__xlocale_global_numeric, 6850276Speter &__xlocale_global_time, 6950276Speter &__xlocale_global_messages 7050276Speter }, 7150276Speter 1, 7250276Speter 0, 7350276Speter 1, 7450276Speter 0 7550276Speter}; 7650276Speter 7750276Speterstruct _xlocale __xlocale_C_locale = { 7850276Speter {0}, 7950276Speter { 8050276Speter &__xlocale_C_collate, 8150276Speter &__xlocale_C_ctype, 8250276Speter 0, 0, 0, 0 8350276Speter }, 8450276Speter 1, 8550276Speter 0, 8650276Speter 1, 8750276Speter 0 8850276Speter}; 8950276Speter 9050276Speterstatic void*(*constructors[])(const char*, locale_t) = 9150276Speter{ 9250276Speter __collate_load, 9350276Speter __ctype_load, 9450276Speter __monetary_load, 9550276Speter __numeric_load, 9650276Speter __time_load, 9750276Speter __messages_load 9850276Speter}; 9950276Speter 10050276Speterstatic pthread_key_t locale_info_key; 10150276Speterstatic int fake_tls; 10250276Speterstatic locale_t thread_local_locale; 10350276Speter 10450276Speterstatic void init_key(void) 10550276Speter{ 10650276Speter pthread_key_create(&locale_info_key, xlocale_release); 10750276Speter pthread_setspecific(locale_info_key, (void*)42); 10850276Speter if (pthread_getspecific(locale_info_key) == (void*)42) { 10950276Speter pthread_setspecific(locale_info_key, 0); 11050276Speter } else { 11150276Speter fake_tls = 1; 11250276Speter } 11350276Speter __detect_path_locale(); 11450276Speter} 11550276Speter 11650276Speterstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 11750276Speter 11850276Speterstatic locale_t 11950276Speterget_thread_locale(void) 12050276Speter{ 12150276Speter _once(&once_control, init_key); 12250276Speter 12350276Speter return (fake_tls ? thread_local_locale : 12450276Speter pthread_getspecific(locale_info_key)); 12550276Speter} 12662449Speter 12762449Speterlocale_t 12862449Speter__get_locale(void) 12962449Speter{ 13062449Speter locale_t l = get_thread_locale(); 13162449Speter return (l ? l : &__xlocale_global_locale); 13262449Speter 13362449Speter} 13462449Speter 13562449Speterstatic void 13662449Speterset_thread_locale(locale_t loc) 13762449Speter{ 13850276Speter pthread_once(&once_control, init_key); 13950276Speter 14050276Speter if (NULL != loc) { 14150276Speter xlocale_retain((struct xlocale_refcounted*)loc); 14250276Speter } 14350276Speter locale_t old = pthread_getspecific(locale_info_key); 14450276Speter if ((NULL != old) && (loc != old)) { 14550276Speter xlocale_release((struct xlocale_refcounted*)old); 14650276Speter } 14750276Speter if (fake_tls) { 14850276Speter thread_local_locale = loc; 14950276Speter } else { 15050276Speter pthread_setspecific(locale_info_key, loc); 15150276Speter } 15250276Speter} 15350276Speter 15450276Speter/** 15550276Speter * Clean up a locale, once its reference count reaches zero. This function is 15650276Speter * called by xlocale_release(), it should not be called directly. 15750276Speter */ 15850276Speterstatic void 15950276Speterdestruct_locale(void *l) 16050276Speter{ 16150276Speter locale_t loc = l; 16250276Speter for (int type=0 ; type<XLC_LAST ; type++) { 16350276Speter if (loc->components[type]) { 16450276Speter xlocale_release(loc->components[type]); 16566963Speter } 16650276Speter } 16750276Speter if (loc->csym) { 16897049Speter free(loc->csym); 16950276Speter } 17050276Speter free(l); 17150276Speter} 17250276Speter 17366963Speter/** 17497049Speter * Allocates a new, uninitialised, locale. 17576726Speter */ 17666963Speterstatic locale_t 177alloc_locale(void) 178{ 179 locale_t new = calloc(sizeof(struct _xlocale), 1); 180 new->header.destructor = destruct_locale; 181 new->monetary_locale_changed = 1; 182 new->numeric_locale_changed = 1; 183 return (new); 184} 185static void 186copyflags(locale_t new, locale_t old) 187{ 188 new->using_monetary_locale = old->using_monetary_locale; 189 new->using_numeric_locale = old->using_numeric_locale; 190 new->using_time_locale = old->using_time_locale; 191 new->using_messages_locale = old->using_messages_locale; 192} 193 194static int dupcomponent(int type, locale_t base, locale_t new) 195{ 196 /* Always copy from the global locale, since it has mutable components. */ 197 struct xlocale_component *src = base->components[type]; 198 if (&__xlocale_global_locale == base) { 199 new->components[type] = constructors[type](src->locale, new); 200 if (new->components[type]) { 201 strncpy(new->components[type]->locale, src->locale, ENCODING_LEN); 202 } 203 } else { 204 new->components[type] = xlocale_retain(base->components[type]); 205 } 206 return (0 != new->components[type]); 207} 208 209/* 210 * Public interfaces. These are the five public functions described by the 211 * xlocale interface. 212 */ 213 214locale_t newlocale(int mask, const char *locale, locale_t base) 215{ 216 int type; 217 const char *realLocale = locale; 218 int useenv = 0; 219 int success = 1; 220 221 _once(&once_control, init_key); 222 223 locale_t new = alloc_locale(); 224 if (NULL == new) { 225 return (NULL); 226 } 227 228 FIX_LOCALE(base); 229 copyflags(new, base); 230 231 if (NULL == locale) { 232 realLocale = "C"; 233 } else if ('\0' == locale[0]) { 234 useenv = 1; 235 } 236 237 for (type=0 ; type<XLC_LAST ; type++) { 238 if (mask & 1) { 239 if (useenv) { 240 realLocale = __get_locale_env(type); 241 } 242 new->components[type] = constructors[type](realLocale, new); 243 if (new->components[type]) { 244 strncpy(new->components[type]->locale, realLocale, ENCODING_LEN); 245 } else { 246 success = 0; 247 break; 248 } 249 } else { 250 if (!dupcomponent(type, base, new)) { 251 success = 0; 252 break; 253 } 254 } 255 mask >>= 1; 256 } 257 if (0 == success) { 258 xlocale_release(new); 259 new = NULL; 260 } 261 262 return (new); 263} 264 265locale_t duplocale(locale_t base) 266{ 267 locale_t new = alloc_locale(); 268 int type; 269 270 _once(&once_control, init_key); 271 272 if (NULL == new) { 273 return (NULL); 274 } 275 276 FIX_LOCALE(base); 277 copyflags(new, base); 278 279 for (type=0 ; type<XLC_LAST ; type++) { 280 dupcomponent(type, base, new); 281 } 282 283 return (new); 284} 285 286/* 287 * Free a locale_t. This is quite a poorly named function. It actually 288 * disclaims a reference to a locale_t, rather than freeing it. 289 */ 290int 291freelocale(locale_t loc) 292{ 293 /* Fail if we're passed something that isn't a locale. */ 294 if ((NULL == loc) || (LC_GLOBAL_LOCALE == loc)) { 295 return (-1); 296 } 297 /* If we're passed the global locale, pretend that we freed it but don't 298 * actually do anything. */ 299 if (&__xlocale_global_locale == loc) { 300 return (0); 301 } 302 xlocale_release(loc); 303 return (0); 304} 305 306/* 307 * Returns the name of the locale for a particular component of a locale_t. 308 */ 309const char *querylocale(int mask, locale_t loc) 310{ 311 int type = ffs(mask) - 1; 312 FIX_LOCALE(loc); 313 if (type >= XLC_LAST) 314 return (NULL); 315 if (loc->components[type]) 316 return (loc->components[type]->locale); 317 return "C"; 318} 319 320/* 321 * Installs the specified locale_t as this thread's locale. 322 */ 323locale_t uselocale(locale_t loc) 324{ 325 locale_t old = get_thread_locale(); 326 if (NULL != loc) { 327 if (LC_GLOBAL_LOCALE == loc) { 328 loc = NULL; 329 } 330 set_thread_locale(loc); 331 } 332 return (old ? old : LC_GLOBAL_LOCALE); 333} 334 335