Update.
[glibc.git] / locale / newlocale.c
blob4a2f14513f32eb68ba93bed9415c90798c542ebb
1 /* Return a reference to locale information record.
2 Copyright (C) 1996, 1997, 1999 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 == LC_ALL)
54 category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
56 /* Sanity check for CATEGORY argument. */
57 if ((category_mask & ~((1 << LC_ALL) - 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)
67 if (base != NULL)
68 return base;
70 result = *base;
72 else
74 /* Fill with pointers to C locale data to . */
75 for (cnt = 0; cnt < __LC_LAST; ++cnt)
76 if (cnt != LC_ALL)
77 result.__locales[cnt] = _nl_C[cnt];
79 /* If no category is to be set we return BASE if available or a
80 dataset using the C locale data. */
81 if (category_mask == 0)
83 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
84 *result_ptr = result;
86 goto update;
90 /* We perhaps really have to load some data. So we determine the
91 path in which to look for the data now. The environment variable
92 `LOCPATH' must only be used when the binary has no SUID or SGID
93 bit set. */
94 locale_path = NULL;
95 locale_path_len = 0;
97 locpath_var = __secure_getenv ("LOCPATH");
98 if (locpath_var != NULL && locpath_var[0] != '\0')
99 if (__argz_create_sep (locpath_var, ':',
100 &locale_path, &locale_path_len) != 0)
101 return NULL;
103 if (__argz_append (&locale_path, &locale_path_len,
104 LOCALE_PATH, sizeof (LOCALE_PATH)) != 0)
105 return NULL;
107 /* Get the names for the locales we are interested in. We either
108 allow a composite name or a single name. */
109 for (cnt = 0; cnt < __LC_LAST; ++cnt)
110 if (cnt != LC_ALL)
111 newnames[cnt] = locale;
112 if (strchr (locale, ';') != NULL)
114 /* This is a composite name. Make a copy and split it up. */
115 char *np = strdupa (locale);
116 char *cp;
118 while ((cp = strchr (np, '=')) != NULL)
120 for (cnt = 0; cnt < __LC_LAST; ++cnt)
121 if (cnt != LC_ALL
122 && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
123 && memcmp (np, _nl_category_names[cnt], cp - np) == 0)
124 break;
126 if (cnt == __LC_LAST)
127 /* Bogus category name. */
128 ERROR_RETURN;
130 /* Found the category this clause sets. */
131 newnames[cnt] = ++cp;
132 cp = strchr (cp, ';');
133 if (cp != NULL)
135 /* Examine the next clause. */
136 *cp = '\0';
137 np = cp + 1;
139 else
140 /* This was the last clause. We are done. */
141 break;
144 for (cnt = 0; cnt < __LC_LAST; ++cnt)
145 if (cnt != LC_ALL
146 && (category_mask & 1 << cnt) != 0 && newnames[cnt] == locale)
147 /* The composite name did not specify the category we need. */
148 ERROR_RETURN;
151 /* Now process all categories we are interested in. */
152 for (cnt = 0; cnt < __LC_LAST; ++cnt)
153 if (cnt != LC_ALL && (category_mask & 1 << cnt) != 0)
155 result.__locales[cnt] = _nl_find_locale (locale_path, locale_path_len,
156 cnt, &newnames[cnt]);
157 if (result.__locales[cnt] == NULL)
158 return NULL;
161 /* We successfully loaded all required data. */
162 if (base == NULL)
164 /* Allocate new structure. */
165 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
166 if (result_ptr == NULL)
167 return NULL;
169 *result_ptr = result;
171 else
172 *(result_ptr = base) = result;
174 /* Update the special members. */
175 update:
177 union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
178 result_ptr->__ctype_b = (const unsigned short int *)
179 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)] .string);
180 result_ptr->__ctype_tolower = (const int *)
181 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string);
182 result_ptr->__ctype_toupper = (const int *)
183 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string);
186 return result_ptr;