Update.
[glibc.git] / locale / newlocale.c
blob1f5b745bb003e02dff8a0b19e0fa437043bc346d
1 /* Return a reference to locale information record.
2 Copyright (C) 1996, 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <argz.h>
22 #include <errno.h>
23 #include <locale.h>
24 #include <stdlib.h>
26 #include "localeinfo.h"
29 /* Constant data defined in setlocale.c. */
30 extern struct locale_data *const _nl_C[];
32 /* Use this when we come along an error. */
33 #define ERROR_RETURN \
34 do { \
35 __set_errno (EINVAL); \
36 return NULL; \
37 } while (0)
40 __locale_t
41 __newlocale (int category_mask, const char *locale, __locale_t base)
43 /* Intermediate memory for result. */
44 const char *newnames[__LC_LAST];
45 struct __locale_struct result;
46 __locale_t result_ptr;
47 char *locale_path;
48 size_t locale_path_len;
49 const char *locpath_var;
50 int cnt;
52 /* We treat LC_ALL in the same way as if all bits were set. */
53 if (category_mask == 1 << LC_ALL)
54 category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
56 /* Sanity check for CATEGORY argument. */
57 if ((category_mask & ~((1 << __LC_LAST) - 1 - (1 << LC_ALL))) != 0)
58 ERROR_RETURN;
60 /* `newlocale' does not support asking for the locale name. */
61 if (locale == NULL)
62 ERROR_RETURN;
64 /* Allocate memory for the result. */
65 if (base != NULL)
66 result = *base;
67 else
69 /* Fill with pointers to C locale data. */
70 for (cnt = 0; cnt < __LC_LAST; ++cnt)
71 if (cnt != LC_ALL)
72 result.__locales[cnt] = _nl_C[cnt];
75 /* If no category is to be set we return BASE if available or a
76 dataset using the C locale data. */
77 if (category_mask == 0)
79 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
80 if (result_ptr == NULL)
81 return NULL;
82 *result_ptr = result;
84 goto update;
87 /* We perhaps really have to load some data. So we determine the
88 path in which to look for the data now. The environment variable
89 `LOCPATH' must only be used when the binary has no SUID or SGID
90 bit set. */
91 locale_path = NULL;
92 locale_path_len = 0;
94 locpath_var = getenv ("LOCPATH");
95 if (locpath_var != NULL && locpath_var[0] != '\0')
96 if (__argz_create_sep (locpath_var, ':',
97 &locale_path, &locale_path_len) != 0)
98 return NULL;
100 if (__argz_append (&locale_path, &locale_path_len,
101 LOCALEDIR, sizeof (LOCALEDIR)) != 0)
102 return NULL;
104 /* Get the names for the locales we are interested in. We either
105 allow a composite name or a single name. */
106 for (cnt = 0; cnt < __LC_LAST; ++cnt)
107 if (cnt != LC_ALL)
108 newnames[cnt] = locale;
109 if (strchr (locale, ';') != NULL)
111 /* This is a composite name. Make a copy and split it up. */
112 char *np = strdupa (locale);
113 char *cp;
115 while ((cp = strchr (np, '=')) != NULL)
117 for (cnt = 0; cnt < __LC_LAST; ++cnt)
118 if (cnt != LC_ALL
119 && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
120 && memcmp (np, _nl_category_names[cnt], cp - np) == 0)
121 break;
123 if (cnt == __LC_LAST)
124 /* Bogus category name. */
125 ERROR_RETURN;
127 /* Found the category this clause sets. */
128 newnames[cnt] = ++cp;
129 cp = strchr (cp, ';');
130 if (cp != NULL)
132 /* Examine the next clause. */
133 *cp = '\0';
134 np = cp + 1;
136 else
137 /* This was the last clause. We are done. */
138 break;
141 for (cnt = 0; cnt < __LC_LAST; ++cnt)
142 if (cnt != LC_ALL
143 && (category_mask & 1 << cnt) != 0 && newnames[cnt] == locale)
144 /* The composite name did not specify the category we need. */
145 ERROR_RETURN;
148 /* Now process all categories we are interested in. */
149 for (cnt = 0; cnt < __LC_LAST; ++cnt)
150 if (cnt != LC_ALL && (category_mask & 1 << cnt) != 0)
152 result.__locales[cnt] = _nl_find_locale (locale_path, locale_path_len,
153 cnt, &newnames[cnt]);
154 if (result.__locales[cnt] == NULL)
155 return NULL;
158 /* We successfully loaded all required data. */
159 if (base == NULL)
161 /* Allocate new structure. */
162 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
163 if (result_ptr == NULL)
164 return NULL;
166 *result_ptr = result;
168 else
169 *(result_ptr = base) = result;
171 /* Update the special members. */
172 update:
174 union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
175 result_ptr->__ctype_b = (const unsigned short int *)
176 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string);
177 result_ptr->__ctype_tolower = (const int *)
178 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string);
179 result_ptr->__ctype_toupper = (const int *)
180 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string);
183 return result_ptr;