]>
Commit | Line | Data |
---|---|---|
c84142e8 | 1 | /* Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
e4cf5070 UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996. | |
7a12c6bb | 4 | |
e4cf5070 UD |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | License, or (at your option) any later version. | |
7a12c6bb | 9 | |
e4cf5070 UD |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Library General Public License for more details. | |
7a12c6bb | 14 | |
e4cf5070 UD |
15 | You should have received a copy of the GNU Library General Public |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
7a12c6bb RM |
19 | |
20 | #include <locale.h> | |
21 | #include <stdlib.h> | |
22 | #include <string.h> | |
c84142e8 | 23 | #include <sys/mman.h> |
7a12c6bb RM |
24 | |
25 | #include "localeinfo.h" | |
26 | ||
27 | ||
28 | /* Constant data defined in setlocale.c. */ | |
c84142e8 | 29 | extern struct locale_data *const _nl_C[]; |
7a12c6bb RM |
30 | |
31 | ||
32 | /* For each category we keep a list of records for the locale files | |
33 | which are somehow addressed. */ | |
34 | static struct loaded_l10nfile *locale_file_list[LC_ALL]; | |
35 | ||
36 | ||
c84142e8 | 37 | struct locale_data * |
7a12c6bb | 38 | _nl_find_locale (const char *locale_path, size_t locale_path_len, |
c84142e8 | 39 | int category, const char **name) |
7a12c6bb RM |
40 | { |
41 | int mask; | |
42 | /* Name of the locale for this category. */ | |
43 | char *loc_name; | |
44 | const char *language; | |
45 | const char *modifier; | |
46 | const char *territory; | |
47 | const char *codeset; | |
48 | const char *normalized_codeset; | |
49 | const char *special; | |
50 | const char *sponsor; | |
51 | const char *revision; | |
52 | struct loaded_l10nfile *locale_file; | |
53 | ||
54 | if ((*name)[0] == '\0') | |
55 | { | |
56 | /* The user decides which locale to use by setting environment | |
57 | variables. */ | |
58 | *name = getenv ("LC_ALL"); | |
59 | if (*name == NULL || (*name)[0] == '\0') | |
60 | *name = getenv (_nl_category_names[category]); | |
61 | if (*name == NULL || (*name)[0] == '\0') | |
62 | *name = getenv ("LANG"); | |
63 | if (*name == NULL || (*name)[0] == '\0') | |
64 | *name = (char *) _nl_C_name; | |
65 | } | |
66 | ||
67 | if (strcmp (*name, _nl_C_name) == 0 || strcmp (*name, "POSIX") == 0) | |
68 | { | |
69 | /* We need not load anything. The needed data is contained in | |
70 | the library itself. */ | |
71 | *name = (char *) _nl_C_name; | |
72 | return _nl_C[category]; | |
73 | } | |
74 | ||
75 | /* We really have to load some data. First see whether the name is | |
76 | an alias. Please note that this makes it impossible to have "C" | |
77 | or "POSIX" as aliases. */ | |
fa0bc87c | 78 | loc_name = (char *) _nl_expand_alias (*name); |
7a12c6bb RM |
79 | if (loc_name == NULL) |
80 | /* It is no alias. */ | |
c84142e8 | 81 | loc_name = (char *) *name; |
7a12c6bb RM |
82 | |
83 | /* Make a writable copy of the locale name. */ | |
c84142e8 | 84 | loc_name = __strdup (loc_name); |
7a12c6bb RM |
85 | |
86 | /* LOCALE can consist of up to four recognized parts for the XPG syntax: | |
87 | ||
88 | language[_territory[.codeset]][@modifier] | |
89 | ||
90 | and six parts for the CEN syntax: | |
91 | ||
e4cf5070 | 92 | language[_territory][+audience][+special][,[sponsor][_revision]] |
7a12c6bb RM |
93 | |
94 | Beside the first all of them are allowed to be missing. If the | |
95 | full specified locale is not found, the less specific one are | |
96 | looked for. The various part will be stripped of according to | |
97 | the following order: | |
98 | (1) revision | |
99 | (2) sponsor | |
100 | (3) special | |
101 | (4) codeset | |
102 | (5) normalized codeset | |
103 | (6) territory | |
104 | (7) audience/modifier | |
105 | */ | |
106 | mask = _nl_explode_name (loc_name, &language, &modifier, &territory, | |
107 | &codeset, &normalized_codeset, &special, | |
108 | &sponsor, &revision); | |
109 | ||
110 | /* If exactly this locale was already asked for we have an entry with | |
111 | the complete name. */ | |
112 | locale_file = _nl_make_l10nflist (&locale_file_list[category], | |
113 | locale_path, locale_path_len, mask, | |
114 | language, territory, codeset, | |
115 | normalized_codeset, modifier, special, | |
116 | sponsor, revision, | |
117 | _nl_category_names[category], 0); | |
118 | ||
119 | if (locale_file == NULL) | |
120 | { | |
121 | /* Find status record for addressed locale file. We have to search | |
122 | through all directories in the locale path. */ | |
123 | locale_file = _nl_make_l10nflist (&locale_file_list[category], | |
124 | locale_path, locale_path_len, mask, | |
125 | language, territory, codeset, | |
126 | normalized_codeset, modifier, special, | |
127 | sponsor, revision, | |
128 | _nl_category_names[category], 1); | |
129 | if (locale_file == NULL) | |
130 | /* This means we are out of core. */ | |
131 | return NULL; | |
132 | } | |
133 | else | |
c84142e8 UD |
134 | /* If the addressed locale is already available it should be |
135 | freed. If we would not do this switching back and force | |
136 | between two locales would slowly eat up all memory. */ | |
fa0bc87c | 137 | free ((void *) loc_name); |
7a12c6bb RM |
138 | |
139 | if (locale_file->decided == 0) | |
140 | _nl_load_locale (locale_file, category); | |
141 | ||
142 | if (locale_file->data == NULL) | |
143 | { | |
144 | int cnt; | |
145 | for (cnt = 0; locale_file->successor[cnt] != NULL; ++cnt) | |
146 | { | |
147 | if (locale_file->successor[cnt]->decided == 0) | |
148 | _nl_load_locale (locale_file->successor[cnt], category); | |
149 | if (locale_file->successor[cnt]->data != NULL) | |
150 | break; | |
151 | } | |
152 | /* Move the entry we found (or NULL) to the first place of | |
153 | successors. */ | |
154 | locale_file->successor[0] = locale_file->successor[cnt]; | |
155 | locale_file = locale_file->successor[cnt]; | |
156 | } | |
157 | ||
158 | if (locale_file == NULL) | |
159 | return NULL; | |
160 | ||
161 | /* Determine the locale name for which loading succeeded. This | |
162 | information comes from the file name. The form is | |
036cc82f | 163 | <path>/<locale>/LC_foo. We must extract the <locale> part. */ |
7a12c6bb RM |
164 | if (((struct locale_data *) locale_file->data)->name == NULL) |
165 | { | |
036cc82f | 166 | char *cp, *endp; |
7a12c6bb RM |
167 | |
168 | endp = strrchr (locale_file->filename, '/'); | |
169 | cp = endp - 1; | |
170 | while (cp[-1] != '/') | |
171 | --cp; | |
036cc82f RM |
172 | ((struct locale_data *) locale_file->data)->name = __strndup (cp, |
173 | endp - cp); | |
7a12c6bb RM |
174 | } |
175 | *name = (char *) ((struct locale_data *) locale_file->data)->name; | |
176 | ||
c84142e8 UD |
177 | /* Increment the usage count. */ |
178 | if (((struct locale_data *) locale_file->data)->usage_count | |
179 | != MAX_USAGE_COUNT) | |
180 | ++((struct locale_data *) locale_file->data)->usage_count; | |
181 | ||
7a12c6bb RM |
182 | return (struct locale_data *) locale_file->data; |
183 | } | |
c84142e8 UD |
184 | |
185 | ||
186 | /* Calling this function assumes the lock for handling global locale data | |
187 | is acquired. */ | |
188 | void | |
189 | _nl_remove_locale (int locale, struct locale_data *data) | |
190 | { | |
191 | if (--data->usage_count == 0) | |
192 | { | |
193 | /* First search the entry in the list of loaded files. */ | |
194 | struct loaded_l10nfile *ptr = locale_file_list[locale]; | |
195 | ||
196 | /* Search for the entry. It must be in the list. Otherwise it | |
197 | is a bug and we crash badly. */ | |
198 | while ((struct locale_data *) ptr->data != data) | |
199 | ptr = ptr->next; | |
200 | ||
201 | /* Mark the data as not available anymore. So when the data has | |
202 | to be used again it is reloaded. */ | |
203 | ptr->decided = 0; | |
204 | ptr->data = NULL; | |
205 | ||
206 | /* Really delete the data. First delete the real data. */ | |
207 | if (data->mmaped) | |
208 | { | |
209 | /* Try to unmap the area. If this fails we mark the area as | |
210 | permanent. */ | |
211 | if (__munmap ((caddr_t) data->filedata, data->filesize) != 0) | |
212 | { | |
213 | data->usage_count = MAX_USAGE_COUNT; | |
214 | return; | |
215 | } | |
216 | } | |
217 | else | |
218 | /* The memory was malloced. */ | |
219 | free ((void *) data->filedata); | |
220 | ||
221 | /* Now free the structure itself. */ | |
222 | free (data); | |
223 | } | |
224 | } |