Home | History | Annotate | Download | only in Locale
      1 /** @file
      2   Worker functions for the setlocale function.
      3 
      4   Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials are licensed and made available under
      6   the terms and conditions of the BSD License that accompanies this distribution.
      7   The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13  * Copyright (c) 1991, 1993
     14  *  The Regents of the University of California.  All rights reserved.
     15  *
     16  * This code is derived from software contributed to Berkeley by
     17  * Paul Borman at Krystal Technologies.
     18  *
     19  * Redistribution and use in source and binary forms, with or without
     20  * modification, are permitted provided that the following conditions
     21  * are met:
     22  * 1. Redistributions of source code must retain the above copyright
     23  *    notice, this list of conditions and the following disclaimer.
     24  * 2. Redistributions in binary form must reproduce the above copyright
     25  *    notice, this list of conditions and the following disclaimer in the
     26  *    documentation and/or other materials provided with the distribution.
     27  * 3. Neither the name of the University nor the names of its contributors
     28  *    may be used to endorse or promote products derived from this software
     29  *    without specific prior written permission.
     30  *
     31  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     32  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     34  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     35  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     39  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     40  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     41  * SUCH DAMAGE.
     42 
     43     setlocale.c 8.1 (Berkeley) 7/4/93
     44  *  NetBSD: setlocale.c,v 1.50 2006/02/16 19:19:49 tnozaki Exp
     45 **/
     46 #include  <LibConfig.h>
     47 #include  <sys/EfiCdefs.h>
     48 
     49 #if defined(_MSC_VER)
     50   // Disable warnings about assignment within conditional expressions.
     51   #pragma warning ( disable : 4706 )
     52 #endif
     53 
     54 #define _CTYPE_PRIVATE
     55 
     56 #include  "namespace.h"
     57 #include  <sys/localedef.h>
     58 #include  <sys/types.h>
     59 #include  <sys/stat.h>
     60 #include  <assert.h>
     61 #include  <limits.h>
     62 #include  <ctype.h>
     63 #define __SETLOCALE_SOURCE__
     64 #include  <locale.h>
     65 #include  <paths.h>
     66 #include  <stdio.h>
     67 #include  <stdlib.h>
     68 #include  <string.h>
     69 #include  <unistd.h>
     70 #include  "rune.h"
     71 #ifdef WITH_RUNE
     72   #include "rune_local.h"
     73 #else
     74   #include "ctypeio.h"
     75 #endif
     76 
     77 #ifdef CITRUS
     78   #include <citrus/citrus_namespace.h>
     79   #include <citrus/citrus_region.h>
     80   #include <citrus/citrus_lookup.h>
     81   #include <citrus/citrus_bcs.h>
     82 #else
     83   #include "aliasname_local.h"
     84   #define _lookup_alias(p, a, b, s, c)  __unaliasname((p), (a), (b), (s))
     85   #define _bcs_strcasecmp(a, b)   strcasecmp((a), (b))
     86 #endif
     87 
     88 #define _LOCALE_SYM_FORCE "/force"
     89 
     90 #ifndef WITH_RUNE
     91   const char *_PathLocale = NULL;
     92 #endif
     93 
     94 /** Category names for getenv(). **/
     95 static const char *const categories[_LC_LAST] = {
     96     "LC_ALL",
     97     "LC_COLLATE",
     98     "LC_CTYPE",
     99     "LC_MONETARY",
    100     "LC_NUMERIC",
    101     "LC_TIME",
    102     "LC_MESSAGES"
    103 };
    104 
    105 /** Current locales for each category.  **/
    106 static char current_categories[_LC_LAST][32] = {
    107     "C",
    108     "C",
    109     "C",
    110     "C",
    111     "C",
    112     "C",
    113     "C"
    114 };
    115 
    116 /*
    117  * The locales we are going to try and load
    118  */
    119 static char new_categories[_LC_LAST][32];
    120 
    121 static char current_locale_string[_LC_LAST * 33];
    122 
    123 static char *currentlocale(void);
    124 static void revert_to_default(int);
    125 static int force_locale_enable(int);
    126 static int load_locale_sub(int, const char *, int);
    127 static char *loadlocale(int);
    128 static const char *__get_locale_env(int);
    129 
    130 char *
    131 __setlocale(int category, const char *locale)
    132 {
    133   int i, loadlocale_success;
    134   size_t len;
    135   const char *env, *r;
    136 
    137   //if (issetugid() ||
    138   //    (!_PathLocale && !(_PathLocale = getenv("PATH_LOCALE"))))
    139   //  _PathLocale = _PATH_LOCALE;
    140 
    141   if (category < 0 || category >= _LC_LAST)
    142     return (NULL);
    143 
    144   if (!locale)
    145     return (category ?
    146         current_categories[category] : currentlocale());
    147 
    148   /*
    149    * Default to the current locale for everything.
    150    */
    151   for (i = 1; i < _LC_LAST; ++i)
    152     (void)strncpyX(new_categories[i], current_categories[i],
    153         sizeof(new_categories[i]));
    154 
    155   /*
    156    * Now go fill up new_categories from the locale argument
    157    */
    158   if (!*locale) {
    159     if (category == LC_ALL) {
    160       for (i = 1; i < _LC_LAST; ++i) {
    161         env = __get_locale_env(i);
    162         (void)strncpyX(new_categories[i], env,
    163             sizeof(new_categories[i]));
    164       }
    165     }
    166     else {
    167       env = __get_locale_env(category);
    168       (void)strncpyX(new_categories[category], env,
    169         sizeof(new_categories[category]));
    170     }
    171   } else if (category) {
    172     (void)strncpyX(new_categories[category], locale,
    173         sizeof(new_categories[category]));
    174   } else {
    175     if ((r = strchr(locale, '/')) == 0) {
    176       for (i = 1; i < _LC_LAST; ++i) {
    177         (void)strncpyX(new_categories[i], locale,
    178             sizeof(new_categories[i]));
    179       }
    180     } else {
    181       for (i = 1;;) {
    182         _DIAGASSERT(*r == '/' || *r == 0);
    183         _DIAGASSERT(*locale != 0);
    184         if (*locale == '/')
    185           return (NULL);  /* invalid format. */
    186         len = r - locale;
    187         if (len + 1 > sizeof(new_categories[i]))
    188           return (NULL);  /* too long */
    189         (void)memcpy(new_categories[i], locale, len);
    190         new_categories[i][len] = '\0';
    191         if (*r == 0)
    192           break;
    193         _DIAGASSERT(*r == '/');
    194         if (*(locale = ++r) == 0)
    195           /* slash followed by NUL */
    196           return (NULL);
    197         /* skip until NUL or '/' */
    198         while (*r && *r != '/')
    199           r++;
    200         if (++i == _LC_LAST)
    201           return (NULL);  /* too many slashes. */
    202       }
    203       if (i + 1 != _LC_LAST)
    204         return (NULL);  /* too few slashes. */
    205     }
    206   }
    207 
    208   if (category)
    209     return (loadlocale(category));
    210 
    211   loadlocale_success = 0;
    212   for (i = 1; i < _LC_LAST; ++i) {
    213     if (loadlocale(i) != NULL)
    214       loadlocale_success = 1;
    215   }
    216 
    217   /*
    218    * If all categories failed, return NULL; we don't need to back
    219    * changes off, since none happened.
    220    */
    221   if (!loadlocale_success)
    222     return NULL;
    223 
    224   return (currentlocale());
    225 }
    226 
    227 static char *
    228 currentlocale()
    229 {
    230   int i;
    231 
    232   (void)strncpyX(current_locale_string, current_categories[1],
    233       sizeof(current_locale_string));
    234 
    235   for (i = 2; i < _LC_LAST; ++i)
    236     if (strcmp(current_categories[1], current_categories[i])) {
    237       (void)snprintf(current_locale_string,
    238           sizeof(current_locale_string), "%s/%s/%s/%s/%s/%s",
    239           current_categories[1], current_categories[2],
    240           current_categories[3], current_categories[4],
    241           current_categories[5], current_categories[6]);
    242       break;
    243     }
    244   return (current_locale_string);
    245 }
    246 
    247 static void
    248 revert_to_default(int category)
    249 {
    250   switch (category) {
    251   case LC_CTYPE:
    252 #ifdef WITH_RUNE
    253     (void)_xpg4_setrunelocale("C");
    254     (void)__runetable_to_netbsd_ctype("C");
    255 #else
    256     if (_cClass != _C_CharClassTable) {
    257       /* LINTED const castaway */
    258       free((void *)_cClass);
    259       _cClass = _C_CharClassTable;
    260     }
    261     if (_uConvT != _C_ToUpperTable) {
    262       /* LINTED const castaway */
    263       free((void *)_uConvT);
    264       _uConvT = _C_ToUpperTable;
    265     }
    266     if (_lConvT != _C_ToLowerTable) {
    267       /* LINTED const castaway */
    268       free((void *)_lConvT);
    269       _lConvT = _C_ToLowerTable;
    270     }
    271 #endif
    272     break;
    273   case LC_MESSAGES:
    274   case LC_COLLATE:
    275   case LC_MONETARY:
    276   case LC_NUMERIC:
    277   case LC_TIME:
    278     break;
    279   }
    280 }
    281 
    282 static int
    283 force_locale_enable(int category)
    284 {
    285   revert_to_default(category);
    286 
    287   return 0;
    288 }
    289 
    290 static int
    291 load_locale_sub(
    292   int category,
    293   const char *locname,
    294   int isspecial
    295   )
    296 {
    297   char name[PATH_MAX];
    298 
    299   /* check for the default locales */
    300   if (!strcmp(new_categories[category], "C") ||
    301       !strcmp(new_categories[category], "POSIX")) {
    302     revert_to_default(category);
    303     return 0;
    304   }
    305 
    306   /* check whether special symbol */
    307   if (isspecial && _bcs_strcasecmp(locname, _LOCALE_SYM_FORCE) == 0)
    308     return force_locale_enable(category);
    309 
    310   /* sanity check */
    311   if (strchr(locname, '/') != NULL)
    312     return -1;
    313 
    314   (void)snprintf(name, sizeof(name), "%s/%s/%s",
    315            _PathLocale, locname, categories[category]);
    316 
    317   switch (category) {
    318   case LC_CTYPE:
    319 #ifdef WITH_RUNE
    320     if (_xpg4_setrunelocale(__UNCONST(locname)))
    321       return -1;
    322     if (__runetable_to_netbsd_ctype(locname)) {
    323       /* very unfortunate, but need to go to "C" locale */
    324       revert_to_default(category);
    325       return -1;
    326     }
    327 #else
    328     if (!__loadctype(name))
    329       return -1;
    330 #endif
    331     break;
    332 
    333   case LC_MESSAGES:
    334     /*
    335      * XXX we don't have LC_MESSAGES support yet,
    336      * but catopen may use the value of LC_MESSAGES category.
    337      * so return successfully if locale directory is present.
    338      */
    339     (void)snprintf(name, sizeof(name), "%s/%s",
    340       _PathLocale, locname);
    341     /* local */
    342     {
    343       struct stat st;
    344       if (stat(name, &st) < 0)
    345         return -1;
    346       if (!S_ISDIR(st.st_mode))
    347         return -1;
    348     }
    349     break;
    350 
    351   case LC_COLLATE:
    352   case LC_MONETARY:
    353   case LC_NUMERIC:
    354   case LC_TIME:
    355     return -1;
    356   }
    357 
    358   return 0;
    359 }
    360 
    361 static char *
    362 loadlocale(int category)
    363 {
    364   //char aliaspath[PATH_MAX], loccat[PATH_MAX], buf[PATH_MAX];
    365   //const char *alias;
    366 
    367   _DIAGASSERT(0 < category && category < _LC_LAST);
    368 
    369   if (strcmp(new_categories[category], current_categories[category]) == 0)
    370     return (current_categories[category]);
    371 
    372   /* (1) non-aliased file */
    373   if (!load_locale_sub(category, new_categories[category], 0))
    374     goto success;
    375 
    376   ///* (2) lookup locname/catname type alias */
    377   //(void)snprintf(aliaspath, sizeof(aliaspath),
    378   //         "%s/" _LOCALE_ALIAS_NAME, _PathLocale);
    379   //(void)snprintf(loccat, sizeof(loccat), "%s/%s",
    380   //         new_categories[category], categories[category]);
    381   //alias = _lookup_alias(aliaspath, loccat, buf, sizeof(buf),
    382   //          _LOOKUP_CASE_SENSITIVE);
    383   //if (!load_locale_sub(category, alias, 1))
    384   //  goto success;
    385 
    386   ///* (3) lookup locname type alias */
    387   //alias = _lookup_alias(aliaspath, new_categories[category],
    388   //          buf, sizeof(buf), _LOOKUP_CASE_SENSITIVE);
    389   //if (!load_locale_sub(category, alias, 1))
    390   //  goto success;
    391 
    392   return NULL;
    393 
    394 success:
    395   (void)strncpyX(current_categories[category],
    396     new_categories[category],
    397     sizeof(current_categories[category]));
    398   return current_categories[category];
    399 }
    400 
    401 static const char *
    402 __get_locale_env(int category)
    403 {
    404   const char *env;
    405 
    406   //_DIAGASSERT(category != LC_ALL);
    407 
    408   ///* 1. check LC_ALL. */
    409   //env = getenv(categories[0]);
    410 
    411   ///* 2. check LC_* */
    412   //if (!env || !*env)
    413   //  env = getenv(categories[category]);
    414 
    415   ///* 3. check LANG */
    416   //if (!env || !*env)
    417   //  env = getenv("LANG");
    418 
    419   ///* 4. if none is set, fall to "C" */
    420   //if (!env || !*env || strchr(env, '/'))
    421     env = "C";
    422 
    423   return env;
    424 }
    425