source: trunk/libs/newlib/src/newlib/libc/locale/newlocale.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 7.4 KB
Line 
1/*
2FUNCTION
3        <<newlocale>>---create or modify a locale object
4
5INDEX
6        newlocale
7
8INDEX
9        _newlocale_r
10
11SYNOPSIS
12        #include <locale.h>
13        locale_t newlocale(int <[category_mask]>, const char *<[locale]>,
14                           locale_t <[locobj]>);
15
16        locale_t _newlocale_r(void *<[reent]>, int <[category_mask]>,
17                              const char *<[locale]>, locale_t <[locobj]>);
18
19DESCRIPTION
20The <<newlocale>> function shall create a new locale object or modify an
21existing one.  If the base argument is (locale_t) <<0>>, a new locale
22object shall be created. It is unspecified whether the locale object
23pointed to by base shall be modified, or freed and a new locale object
24created.
25
26The category_mask argument specifies the locale categories to be set or
27modified.  Values for category_mask shall be constructed by a
28bitwise-inclusive OR of the symbolic constants LC_CTYPE_MASK,
29LC_NUMERIC_MASK, LC_TIME_MASK, LC_COLLATE_MASK, LC_MONETARY_MASK, and
30LC_MESSAGES_MASK, or any of the other implementation-defined LC_*_MASK
31values defined in <locale.h>.
32
33For each category with the corresponding bit set in category_mask the
34data from the locale named by locale shall be used. In the case of
35modifying an existing locale object, the data from the locale named by
36locale shall replace the existing data within the locale object. If a
37completely new locale object is created, the data for all sections not
38requested by category_mask shall be taken from the default locale.
39
40The following preset values of locale are defined for all settings of
41category_mask:
42
43"POSIX" Specifies the minimal environment for C-language translation
44called the POSIX locale.
45
46"C"     Equivalent to "POSIX".
47
48""      Specifies an implementation-defined native environment.  This
49        corresponds to the value of the associated environment variables,
50        LC_* and LANG; see the Base Definitions volume of POSIX.1‐2008,
51        Chapter 7, Locale and Chapter 8, Environment Variables.
52
53If the base argument is not (locale_t) <<0>> and the <<newlocale>>
54function call succeeds, the contents of base are unspecified.
55Applications shall ensure that they stop using base as a locale object
56before calling <<newlocale>>.  If the function call fails and the base
57argument is not (locale_t) <<0>>, the contents of base shall remain
58valid and unchanged.
59
60The behavior is undefined if the base argument is the special locale
61object LC_GLOBAL_LOCALE, or is not a valid locale object handle and is
62not (locale_t) <<0>>.
63
64RETURNS
65Upon successful completion, the <<newlocale>> function shall return a
66handle which the caller may use on subsequent calls to <<duplocale>>,
67<<freelocale>>, and other functions taking a locale_t argument.
68
69Upon failure, the <<newlocale>> function shall return (locale_t) <<0>>
70and set errno to indicate the error.
71
72PORTABILITY
73<<newlocale>> is POSIX-1.2008.
74*/
75
76#include <newlib.h>
77#include <errno.h>
78#include <reent.h>
79#include <stdlib.h>
80#include "setlocale.h"
81
82#define LC_VALID_MASK   (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MONETARY_MASK \
83                         | LC_NUMERIC_MASK | LC_TIME_MASK | LC_MESSAGES_MASK)
84
85struct __locale_t *
86_newlocale_r (struct _reent *p, int category_mask, const char *locale,
87              struct __locale_t *base)
88{
89#ifndef _MB_CAPABLE
90  return __get_C_locale ();
91#else /* _MB_CAPABLE */
92  char new_categories[_LC_LAST][ENCODING_LEN + 1];
93  struct __locale_t tmp_locale, *new_locale;
94  int i;
95
96  /* Convert LC_ALL_MASK to a mask containing all valid MASK values.
97     This simplifies the code below. */
98  if (category_mask & LC_ALL_MASK)
99    {
100      category_mask &= ~LC_ALL_MASK;
101      category_mask |= LC_VALID_MASK;
102    }
103  /* Check for invalid mask values and valid locale ptr. */
104  if ((category_mask & ~LC_VALID_MASK) || !locale)
105    {
106      p->_errno = EINVAL;
107      return NULL;
108    }
109  /* If the new locale is supposed to be all default locale, just return
110     a pointer to the default locale. */
111  if ((!base && category_mask == 0)
112      || (category_mask == LC_VALID_MASK
113          && (!strcmp (locale, "C") || !strcmp (locale, "POSIX"))))
114    return __get_C_locale ();
115  /* Start with setting all values to the default locale values. */
116  tmp_locale = *__get_C_locale ();
117  /* Fill out new category strings. */
118  for (i = 1; i < _LC_LAST; ++i)
119    {
120      if (((1 << i) & category_mask) != 0)
121        {
122          /* If locale is "", fetch from environment.  Otherwise use locale
123             name verbatim. */
124          const char *cat = (locale[0] == '\0') ? __get_locale_env (p, i)
125                                                : locale;
126          if (strlen (cat) > ENCODING_LEN)
127            {
128              p->_errno = EINVAL;
129              return NULL;
130            }
131          strcpy (new_categories[i], cat);
132        }
133      else
134        strcpy (new_categories[i], base ? base->categories[i] : "C");
135    }
136  /* Now go over all categories and set them. */
137  for (i = 1; i < _LC_LAST; ++i)
138    {
139      /* If we have a base locale, and the category is not in category_mask
140         or the new category is the base categroy, just copy over. */
141      if (base && (((1 << i) & category_mask) == 0
142                   || !strcmp (base->categories[i], new_categories[i])))
143        {
144          strcpy (tmp_locale.categories[i], new_categories[i]);
145          if (i == LC_CTYPE)
146            {
147              tmp_locale.wctomb = base->wctomb;
148              tmp_locale.mbtowc = base->mbtowc;
149              tmp_locale.cjk_lang = base->cjk_lang;
150              tmp_locale.ctype_ptr - base->ctype_ptr;
151            }
152#ifdef __HAVE_LOCALE_INFO__
153          /* Mark the values as "has still to be copied".  We do this in
154             two steps to simplify freeing new locale types in case of a
155             subsequent error. */
156          tmp_locale.lc_cat[i].ptr = base->lc_cat[i].ptr;
157          tmp_locale.lc_cat[i].buf = (void *) -1;
158#else /* !__HAVE_LOCALE_INFO__ */
159          if (i == LC_CTYPE)
160            strcpy (tmp_locale.ctype_codeset, base->ctype_codeset);
161          else if (i == LC_MESSAGES)
162            strcpy (tmp_locale.message_codeset, base->message_codeset);
163#endif /* !__HAVE_LOCALE_INFO__ */
164        }
165      /* Otherwise, if the category is in category_mask, create entry. */
166      else if (((1 << i) & category_mask) != 0)
167        {
168          /* Nothing to do for "C"/"POSIX" locale. */
169          if (!strcmp (new_categories[i], "C")
170              || !strcmp (new_categories[i], "POSIX"))
171            continue;
172          /* Otherwise load locale data. */
173          else if (!__loadlocale (&tmp_locale, i, new_categories[i]))
174            goto error;
175        }
176    }
177  /* Allocate new locale_t. */
178  new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale);
179  if (!new_locale)
180    goto error;
181  if (base)
182    {
183#ifdef __HAVE_LOCALE_INFO__
184      /* Step 2 of copying over..  Make sure to invalidate the copied buffer
185         pointers in base, so the subsequent _freelocale_r (base) doesn't free
186         the buffers now used in the new locale. */
187      for (i = 1; i < _LC_LAST; ++i)
188        if (tmp_locale.lc_cat[i].buf == (const void *) -1)
189          {
190            tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf;
191            base->lc_cat[i].ptr = base->lc_cat[i].buf = NULL;
192          }
193#endif /* __HAVE_LOCALE_INFO__ */
194      _freelocale_r (p, base);
195    }
196
197  *new_locale = tmp_locale;
198  return new_locale;
199
200error:
201  /* An error occured while we had already (potentially) allocated memory.
202     Free memory and return NULL.  errno is supposed to be set already. */
203#ifdef __HAVE_LOCALE_INFO__
204  for (i = 1; i < _LC_LAST; ++i)
205    if (((1 << i) & category_mask) != 0
206        && tmp_locale.lc_cat[i].buf
207        && tmp_locale.lc_cat[i].buf != (const void *) -1)
208      {
209        _free_r (p, (void *) tmp_locale.lc_cat[i].ptr);
210        _free_r (p, tmp_locale.lc_cat[i].buf);
211      }
212#endif /* __HAVE_LOCALE_INFO__ */
213
214  return NULL;
215#endif /* _MB_CAPABLE */
216}
217
218struct __locale_t *
219newlocale (int category_mask, const char *locale, struct __locale_t *base)
220{
221  return _newlocale_r (_REENT, category_mask, locale, base);
222}
Note: See TracBrowser for help on using the repository browser.