141 "LC_ALL",
142 };
143
144 /*
145 * Prototypes.
146 */
147 static const char *get_locale_env(int);
148 static struct locdata *locdata_get(int, const const char *);
149 static struct locdata *locdata_get_cache(int, const char *);
150 static locale_t mklocname(locale_t);
151
152 /*
153 * Some utility routines.
154 */
155
156 struct locdata *
157 __locdata_alloc(const char *name, size_t memsz)
158 {
159 struct locdata *ldata;
160
161 if ((ldata = calloc(1, sizeof (*ldata))) == NULL) {
162 return (NULL);
163 }
164 if ((ldata->l_data[0] = calloc(1, memsz)) == NULL) {
165 free(ldata);
166 errno = ENOMEM;
167 return (NULL);
168 }
169 (void) strlcpy(ldata->l_lname, name, sizeof (ldata->l_lname));
170
171 return (ldata);
172 }
173
174 /*
175 * Normally we never free locale data truly, but if we failed to load it
176 * for some reason, this routine is used to cleanup the partial mess.
177 */
178 void
179 __locdata_free(struct locdata *ldata)
180 {
181 for (int i = 0; i < NLOCDATA; i++)
182 free(ldata->l_data[i]);
183 if (ldata->l_map != NULL && ldata->l_map_len)
184 (void) munmap(ldata->l_map, ldata->l_map_len);
185 free(ldata);
186 }
187
188 /*
189 * It turns out that for performance reasons we would really like to
190 * cache the most recently referenced locale data to avoid wasteful
191 * loading from files.
192 */
193
194 static struct locdata *cache_data[LC_ALL];
195 static struct locdata *cat_data[LC_ALL];
196 static mutex_t cache_lock = DEFAULTMUTEX;
197
198 /*
199 * Returns the cached data if the locale name is the same. If not,
200 * returns NULL (cache miss). The locdata is returned with a hold on
201 * it, taken on behalf of the caller. The caller should drop the hold
202 * when it is finished.
203 */
204 static struct locdata *
205 locdata_get_cache(int category, const char *locname)
233 * Finally, if we still don't have one, try loading the locale
234 * data from the actual on-disk data.
235 *
236 * We drop the lock (libc wants to ensure no internal locks
237 * are held when we call other routines required to read from
238 * files, allocate memory, etc.) There is a small race here,
239 * but the consequences of the race are benign -- if multiple
240 * threads hit this at precisely the same point, we could
241 * wind up with duplicates of the locale data in the cache.
242 *
243 * This wastes the memory for an extra copy of the locale
244 * data, but there is no further harm beyond that. Its not
245 * worth the effort to recode this to something "safe"
246 * (which would require rescanning the list, etc.), given
247 * that this race will probably never actually occur.
248 */
249 if (loc == NULL) {
250 lmutex_unlock(&cache_lock);
251 loc = (*loaders[category])(locname);
252 lmutex_lock(&cache_lock);
253 (void) strlcpy(loc->l_lname, locname, sizeof (loc->l_lname));
254 }
255
256 /*
257 * Assuming we got one, update the cache, and stick us on the list
258 * of loaded locale data. We insert into the head (more recent
259 * use is likely to win.)
260 */
261 if (loc != NULL) {
262 cache_data[category] = loc;
263 if (loc->l_next == NULL) {
264 loc->l_next = cat_data[category];
265 cat_data[category] = loc;
266 }
267 }
268
269 lmutex_unlock(&cache_lock);
270 return (loc);
271 }
272
273 /*
274 * Routine to get the locdata for a given category and locale.
275 * This includes retrieving it from cache, retrieving it from
276 * a file, etc.
277 */
278 static struct locdata *
279 locdata_get(int category, const char *locname)
280 {
281 char scratch[ENCODING_LEN + 1];
282 char *slash;
283 int cnt;
357 {
358 return (loc->ctype->lc_max_mblen);
359 }
360
361 unsigned char
362 __mb_cur_max(void)
363 {
364 return (__mb_cur_max_l(uselocale(NULL)));
365 }
366
367 /*
368 * Public interfaces.
369 */
370
371 locale_t
372 duplocale(locale_t src)
373 {
374 locale_t loc;
375 int i;
376
377 loc = calloc(1, sizeof (*loc));
378 if (loc == NULL) {
379 return (NULL);
380 }
381 if (src == NULL) {
382 /* illumos extension: POSIX says LC_GLOBAL_LOCALE here */
383 src = ___global_locale;
384 }
385 for (i = 0; i < LC_ALL; i++) {
386 loc->locdata[i] = src->locdata[i];
387 loc->loaded[i] = 0;
388 }
389 loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
390 loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
391 loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
392 loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
393 loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
394 loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
395 loc->time = loc->locdata[LC_TIME]->l_data[0];
396 return (loc);
397 }
398
399 void
400 freelocale(locale_t loc)
401 {
402 /*
403 * We take extra care never to free a saved locale created by
404 * setlocale(). This shouldn't be strictly necessary, but a little
405 * extra safety doesn't hurt here.
406 */
407 if ((loc != &posix_locale) && (!loc->on_list))
408 free(loc);
409 }
410
411 locale_t
412 newlocale(int catmask, const char *locname, locale_t base)
413 {
414 locale_t loc;
415 int i, e;
416
417 if (catmask & ~(LC_ALL_MASK)) {
418 errno = EINVAL;
419 return (NULL);
420 }
421
422 /*
423 * Technically passing LC_GLOBAL_LOCALE here is illegal,
424 * but we allow it.
425 */
426 if (base == NULL || base == ___global_locale) {
427 loc = duplocale(___global_locale);
428 } else {
429 loc = base;
430 }
431 if (loc == NULL) {
432 return (NULL);
433 }
434
435 for (i = 0; i < LC_ALL; i++) {
436 struct locdata *ldata;
437 loc->loaded[i] = 0;
438 if (((1 << i) & catmask) == 0) {
439 /* Default to base locale if not overriding */
440 continue;
441 }
442 ldata = locdata_get(i, locname);
443 if (ldata == NULL) {
444 e = errno;
445 freelocale(loc);
446 errno = e;
447 return (NULL);
448 }
449 loc->locdata[i] = ldata;
450 }
451 loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
452 loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
453 loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
454 loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
455 loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
456 loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
457 loc->time = loc->locdata[LC_TIME]->l_data[0];
458 return (mklocname(loc));
459 }
460
461 locale_t
462 uselocale(locale_t loc)
463 {
464 locale_t lastloc = ___global_locale;
465 locale_t *locptr;
466
467 locptr = tsdalloc(_T_SETLOCALE, sizeof (locale_t), freelocptr);
468 /* Should never occur */
469 if (locptr == NULL) {
470 errno = EINVAL;
471 return (NULL);
472 }
473
474 if (*locptr != NULL)
475 lastloc = *locptr;
476
477 /* Argument loc is NULL if we are just querying. */
|
141 "LC_ALL",
142 };
143
144 /*
145 * Prototypes.
146 */
147 static const char *get_locale_env(int);
148 static struct locdata *locdata_get(int, const const char *);
149 static struct locdata *locdata_get_cache(int, const char *);
150 static locale_t mklocname(locale_t);
151
152 /*
153 * Some utility routines.
154 */
155
156 struct locdata *
157 __locdata_alloc(const char *name, size_t memsz)
158 {
159 struct locdata *ldata;
160
161 if ((ldata = lmalloc(sizeof (*ldata))) == NULL) {
162 return (NULL);
163 }
164 if ((ldata->l_data[0] = libc_malloc(memsz)) == NULL) {
165 lfree(ldata, sizeof (*ldata));
166 errno = ENOMEM;
167 return (NULL);
168 }
169 (void) strlcpy(ldata->l_lname, name, sizeof (ldata->l_lname));
170
171 return (ldata);
172 }
173
174 /*
175 * Normally we never free locale data truly, but if we failed to load it
176 * for some reason, this routine is used to cleanup the partial mess.
177 */
178 void
179 __locdata_free(struct locdata *ldata)
180 {
181 for (int i = 0; i < NLOCDATA; i++)
182 libc_free(ldata->l_data[i]);
183 if (ldata->l_map != NULL && ldata->l_map_len)
184 (void) munmap(ldata->l_map, ldata->l_map_len);
185 lfree(ldata, sizeof (*ldata));
186 }
187
188 /*
189 * It turns out that for performance reasons we would really like to
190 * cache the most recently referenced locale data to avoid wasteful
191 * loading from files.
192 */
193
194 static struct locdata *cache_data[LC_ALL];
195 static struct locdata *cat_data[LC_ALL];
196 static mutex_t cache_lock = DEFAULTMUTEX;
197
198 /*
199 * Returns the cached data if the locale name is the same. If not,
200 * returns NULL (cache miss). The locdata is returned with a hold on
201 * it, taken on behalf of the caller. The caller should drop the hold
202 * when it is finished.
203 */
204 static struct locdata *
205 locdata_get_cache(int category, const char *locname)
233 * Finally, if we still don't have one, try loading the locale
234 * data from the actual on-disk data.
235 *
236 * We drop the lock (libc wants to ensure no internal locks
237 * are held when we call other routines required to read from
238 * files, allocate memory, etc.) There is a small race here,
239 * but the consequences of the race are benign -- if multiple
240 * threads hit this at precisely the same point, we could
241 * wind up with duplicates of the locale data in the cache.
242 *
243 * This wastes the memory for an extra copy of the locale
244 * data, but there is no further harm beyond that. Its not
245 * worth the effort to recode this to something "safe"
246 * (which would require rescanning the list, etc.), given
247 * that this race will probably never actually occur.
248 */
249 if (loc == NULL) {
250 lmutex_unlock(&cache_lock);
251 loc = (*loaders[category])(locname);
252 lmutex_lock(&cache_lock);
253 if (loc != NULL)
254 (void) strlcpy(loc->l_lname, locname,
255 sizeof (loc->l_lname));
256 }
257
258 /*
259 * Assuming we got one, update the cache, and stick us on the list
260 * of loaded locale data. We insert into the head (more recent
261 * use is likely to win.)
262 */
263 if (loc != NULL) {
264 cache_data[category] = loc;
265 if (!loc->l_cached) {
266 loc->l_cached = 1;
267 loc->l_next = cat_data[category];
268 cat_data[category] = loc;
269 }
270 }
271
272 lmutex_unlock(&cache_lock);
273 return (loc);
274 }
275
276 /*
277 * Routine to get the locdata for a given category and locale.
278 * This includes retrieving it from cache, retrieving it from
279 * a file, etc.
280 */
281 static struct locdata *
282 locdata_get(int category, const char *locname)
283 {
284 char scratch[ENCODING_LEN + 1];
285 char *slash;
286 int cnt;
360 {
361 return (loc->ctype->lc_max_mblen);
362 }
363
364 unsigned char
365 __mb_cur_max(void)
366 {
367 return (__mb_cur_max_l(uselocale(NULL)));
368 }
369
370 /*
371 * Public interfaces.
372 */
373
374 locale_t
375 duplocale(locale_t src)
376 {
377 locale_t loc;
378 int i;
379
380 loc = lmalloc(sizeof (*loc));
381 if (loc == NULL) {
382 return (NULL);
383 }
384 if (src == NULL) {
385 /* illumos extension: POSIX says LC_GLOBAL_LOCALE here */
386 src = ___global_locale;
387 }
388 for (i = 0; i < LC_ALL; i++) {
389 loc->locdata[i] = src->locdata[i];
390 loc->loaded[i] = 0;
391 }
392 loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
393 loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
394 loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
395 loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
396 loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
397 loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
398 loc->time = loc->locdata[LC_TIME]->l_data[0];
399 return (loc);
400 }
401
402 void
403 freelocale(locale_t loc)
404 {
405 /*
406 * We take extra care never to free a saved locale created by
407 * setlocale(). This shouldn't be strictly necessary, but a little
408 * extra safety doesn't hurt here.
409 */
410 if ((loc != NULL) && (loc != &posix_locale) && (!loc->on_list))
411 lfree(loc, sizeof (*loc));
412 }
413
414 locale_t
415 newlocale(int catmask, const char *locname, locale_t base)
416 {
417 locale_t loc;
418 int i, e;
419
420 if (catmask & ~(LC_ALL_MASK)) {
421 errno = EINVAL;
422 return (NULL);
423 }
424
425 /*
426 * Technically passing LC_GLOBAL_LOCALE here is illegal,
427 * but we allow it.
428 */
429 if (base == NULL || base == ___global_locale) {
430 loc = duplocale(___global_locale);
431 } else {
432 loc = duplocale(base);
433 }
434 if (loc == NULL) {
435 return (NULL);
436 }
437
438 for (i = 0; i < LC_ALL; i++) {
439 struct locdata *ldata;
440 loc->loaded[i] = 0;
441 if (((1 << i) & catmask) == 0) {
442 /* Default to base locale if not overriding */
443 continue;
444 }
445 ldata = locdata_get(i, locname);
446 if (ldata == NULL) {
447 e = errno;
448 freelocale(loc);
449 errno = e;
450 return (NULL);
451 }
452 loc->locdata[i] = ldata;
453 }
454 loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
455 loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
456 loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
457 loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
458 loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
459 loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
460 loc->time = loc->locdata[LC_TIME]->l_data[0];
461 freelocale(base);
462
463 return (mklocname(loc));
464 }
465
466 locale_t
467 uselocale(locale_t loc)
468 {
469 locale_t lastloc = ___global_locale;
470 locale_t *locptr;
471
472 locptr = tsdalloc(_T_SETLOCALE, sizeof (locale_t), freelocptr);
473 /* Should never occur */
474 if (locptr == NULL) {
475 errno = EINVAL;
476 return (NULL);
477 }
478
479 if (*locptr != NULL)
480 lastloc = *locptr;
481
482 /* Argument loc is NULL if we are just querying. */
|