]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/newlocale.c
Update.
[thirdparty/glibc.git] / locale / newlocale.c
CommitLineData
c84142e8 1/* Return a reference to locale information record.
4b10dd6c 2 Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
c84142e8
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
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.
10
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.
15
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. */
20
21#include <argz.h>
22#include <errno.h>
23#include <locale.h>
24#include <stdlib.h>
25
26#include "localeinfo.h"
27
28
29/* Constant data defined in setlocale.c. */
30extern struct locale_data *const _nl_C[];
31
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)
38
39
40__locale_t
41__newlocale (int category_mask, const char *locale, __locale_t base)
42{
43 /* Intermediate memory for result. */
4b10dd6c 44 const char *newnames[__LC_LAST];
4cca6b86 45 struct __locale_struct result;
c84142e8
UD
46 __locale_t result_ptr;
47 char *locale_path;
48 size_t locale_path_len;
49 const char *locpath_var;
50 int cnt;
51
52 /* We treat LC_ALL in the same way as if all bits were set. */
53 if (category_mask == LC_ALL)
4b10dd6c 54 category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
c84142e8
UD
55
56 /* Sanity check for CATEGORY argument. */
4b10dd6c 57 if ((category_mask & ~((1 << LC_ALL) - 1 - (1 << LC_ALL))) != 0)
c84142e8
UD
58 ERROR_RETURN;
59
60 /* `newlocale' does not support asking for the locale name. */
61 if (locale == NULL)
62 ERROR_RETURN;
63
64 /* Allocate memory for the result. */
65 if (base != NULL)
66 {
67 if (base != NULL)
68 return base;
69
70 result = *base;
71 }
72 else
73 {
74 /* Fill with pointers to C locale data to . */
4b10dd6c
UD
75 for (cnt = 0; cnt < __LC_LAST; ++cnt)
76 if (cnt != LC_ALL)
77 result.__locales[cnt] = _nl_C[cnt];
c84142e8
UD
78
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)
82 {
4cca6b86 83 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
c84142e8
UD
84 *result_ptr = result;
85
86 goto update;
87 }
88 }
89
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;
96
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;
102
103 if (__argz_append (&locale_path, &locale_path_len,
104 LOCALE_PATH, sizeof (LOCALE_PATH)) != 0)
105 return NULL;
106
107 /* Get the names for the locales we are interested in. We either
108 allow a composite name or a single name. */
4b10dd6c
UD
109 for (cnt = 0; cnt < __LC_LAST; ++cnt)
110 if (cnt != LC_ALL)
111 newnames[cnt] = locale;
c84142e8
UD
112 if (strchr (locale, ';') != NULL)
113 {
114 /* This is a composite name. Make a copy and split it up. */
115 char *np = strdupa (locale);
116 char *cp;
117
118 while ((cp = strchr (np, '=')) != NULL)
119 {
4b10dd6c
UD
120 for (cnt = 0; cnt < __LC_LAST; ++cnt)
121 if (cnt != LC_ALL
122 && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
c84142e8
UD
123 && memcmp (np, _nl_category_names[cnt], cp - np) == 0)
124 break;
125
4b10dd6c 126 if (cnt == __LC_LAST)
c84142e8
UD
127 /* Bogus category name. */
128 ERROR_RETURN;
129
130 /* Found the category this clause sets. */
131 newnames[cnt] = ++cp;
132 cp = strchr (cp, ';');
133 if (cp != NULL)
134 {
135 /* Examine the next clause. */
136 *cp = '\0';
137 np = cp + 1;
138 }
139 else
140 /* This was the last clause. We are done. */
141 break;
142 }
143
4b10dd6c
UD
144 for (cnt = 0; cnt < __LC_LAST; ++cnt)
145 if (cnt != LC_ALL
146 && (category_mask & 1 << cnt) != 0 && newnames[cnt] == locale)
c84142e8
UD
147 /* The composite name did not specify the category we need. */
148 ERROR_RETURN;
149 }
150
151 /* Now process all categories we are interested in. */
4b10dd6c
UD
152 for (cnt = 0; cnt < __LC_LAST; ++cnt)
153 if (cnt != LC_ALL && (category_mask & 1 << cnt) != 0)
c84142e8
UD
154 {
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;
159 }
160
161 /* We successfully loaded all required data. */
162 if (base == NULL)
163 {
164 /* Allocate new structure. */
4cca6b86 165 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
c84142e8
UD
166 if (result_ptr == NULL)
167 return NULL;
168
169 *result_ptr = result;
170 }
171 else
172 *(result_ptr = base) = result;
173
174 /* Update the special members. */
175 update:
176 {
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#if BYTE_ORDER == BIG_ENDIAN
181 result_ptr->__ctype_tolower = (const int *)
182 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER_EB)].string);
183 result_ptr->__ctype_toupper = (const int *)
184 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER_EB)].string);
185#elif BYTE_ORDER == LITTLE_ENDIAN
186 result_ptr->__ctype_tolower = (const int *)
187 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER_EL)].string);
188 result_ptr->__ctype_toupper = (const int *)
189 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER_EL)].string);
190#else
191#error bizarre byte order
192#endif
193 }
194
195 return result_ptr;
196}