]>
Commit | Line | Data |
---|---|---|
933e73fa | 1 | /* Functions to read locale data files. |
19bc17a9 | 2 | Copyright (C) 1995, 1996 Free Software Foundation, Inc. |
933e73fa RM |
3 | This file is part of the GNU C Library. |
4 | ||
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. | |
9 | ||
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. | |
14 | ||
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 | |
17 | not, write to the Free Software Foundation, Inc., 675 Mass Ave, | |
18 | Cambridge, MA 02139, USA. */ | |
19 | ||
20 | #include <errno.h> | |
21 | #include <fcntl.h> | |
22 | #include <unistd.h> | |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | #include <stdio.h> | |
26 | #include <sys/stat.h> | |
27 | #include <sys/mman.h> | |
28 | #include "localeinfo.h" | |
29 | ||
30 | const size_t _nl_category_num_items[] = | |
19bc17a9 | 31 | { |
933e73fa | 32 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ |
19bc17a9 | 33 | [category] = _NL_ITEM_INDEX (_NL_NUM_##category), |
933e73fa RM |
34 | #include "categories.def" |
35 | #undef DEFINE_CATEGORY | |
19bc17a9 RM |
36 | }; |
37 | ||
38 | ||
39 | #define NO_PAREN(arg, rest...) arg, ##rest | |
40 | ||
41 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ | |
42 | static const enum value_type _nl_value_type_##category[] = { NO_PAREN items }; | |
43 | #define DEFINE_ELEMENT(element, element_name, optstd, type, rest...) \ | |
44 | [_NL_ITEM_INDEX (element)] = type, | |
45 | #include "categories.def" | |
46 | #undef DEFINE_CATEGORY | |
47 | ||
48 | static const enum value_type *_nl_value_types[] = | |
49 | { | |
50 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ | |
51 | [category] = _nl_value_type_##category, | |
52 | #include "categories.def" | |
53 | #undef DEFINE_CATEGORY | |
54 | }; | |
55 | ||
933e73fa RM |
56 | |
57 | struct locale_data * | |
58 | _nl_load_locale (int category, char **name) | |
59 | { | |
933e73fa RM |
60 | int fd; |
61 | struct | |
62 | { | |
63 | unsigned int magic; | |
64 | unsigned int nstrings; | |
65 | unsigned int strindex[0]; | |
66 | } *filedata; | |
67 | struct stat st; | |
68 | struct locale_data *newdata; | |
69 | int swap = 0; | |
70 | inline unsigned int SWAP (const unsigned int *inw) | |
71 | { | |
72 | const unsigned char *inc = (const unsigned char *) inw; | |
73 | if (!swap) | |
74 | return *inw; | |
75 | return (inc[3] << 24) | (inc[2] << 16) | (inc[1] << 8) | inc[0]; | |
76 | } | |
77 | unsigned int i; | |
78 | ||
79 | if ((*name)[0] == '\0') | |
80 | { | |
f0bf9cb9 RM |
81 | *name = getenv ("LC_ALL"); |
82 | if (! *name || (*name)[0] == '\0') | |
83 | *name = getenv (_nl_category_names[category]); | |
84 | if (! *name || (*name)[0] == '\0') | |
933e73fa | 85 | *name = getenv ("LANG"); |
f0bf9cb9 | 86 | if (! *name || (*name)[0] == '\0') |
933e73fa RM |
87 | *name = (char *) "local"; |
88 | } | |
89 | ||
49e522bf | 90 | { |
49e522bf RM |
91 | const char *catname = _nl_category_names[category]; |
92 | size_t namelen = strlen (*name); | |
93 | size_t catlen = strlen (catname); | |
2b83a2a4 RM |
94 | char file[sizeof LOCALE_PATH + 1 + namelen + catlen * 2 + 4]; |
95 | if (strchr (*name, '/') != NULL) | |
96 | sprintf (file, "%s/%s", *name, catname); | |
97 | else | |
98 | sprintf (file, "%s/%s/%s", LOCALE_PATH, *name, catname); | |
49e522bf RM |
99 | fd = __open (file, O_RDONLY); |
100 | if (fd < 0) | |
101 | return NULL; | |
102 | if (__fstat (fd, &st) < 0) | |
103 | goto puntfd; | |
104 | if (S_ISDIR (st.st_mode)) | |
105 | { | |
1474b80f RM |
106 | /* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo |
107 | instead. */ | |
49e522bf RM |
108 | __close (fd); |
109 | memcpy (stpcpy (strchr (file, '\0'), "SYS_"), catname, catlen); | |
110 | fd = __open (file, O_RDONLY); | |
111 | if (fd < 0) | |
112 | return NULL; | |
113 | if (__fstat (fd, &st) < 0) | |
114 | goto puntfd; | |
115 | } | |
116 | } | |
933e73fa RM |
117 | |
118 | { | |
119 | /* Map in the file's data. */ | |
120 | int save = errno; | |
df4999e1 RM |
121 | #ifndef MAP_COPY |
122 | /* Linux seems to lack read-only copy-on-write. */ | |
123 | #define MAP_COPY MAP_PRIVATE | |
2f8033d6 RM |
124 | #endif |
125 | #ifndef MAP_FILE | |
126 | /* Some systems do not have this flag; it is superfluous. */ | |
127 | #define MAP_FILE 0 | |
883bc19b RM |
128 | #endif |
129 | #ifndef MAP_INHERIT | |
130 | /* Some systems might lack this; they lose. */ | |
131 | #define MAP_INHERIT 0 | |
df4999e1 | 132 | #endif |
933e73fa | 133 | filedata = (void *) __mmap ((caddr_t) 0, st.st_size, |
883bc19b RM |
134 | PROT_READ, MAP_FILE|MAP_COPY|MAP_INHERIT, |
135 | fd, 0); | |
933e73fa RM |
136 | if (filedata == (void *) -1) |
137 | { | |
138 | if (errno == ENOSYS) | |
139 | { | |
140 | /* No mmap; allocate a buffer and read from the file. */ | |
141 | filedata = malloc (st.st_size); | |
142 | if (filedata) | |
143 | { | |
144 | off_t to_read = st.st_size; | |
145 | ssize_t nread; | |
146 | char *p = (char *) filedata; | |
147 | while (to_read > 0) | |
148 | { | |
149 | nread = __read (fd, p, to_read); | |
150 | if (nread <= 0) | |
151 | { | |
152 | free (filedata); | |
153 | if (nread == 0) | |
154 | errno = EINVAL; /* Bizarreness going on. */ | |
155 | goto puntfd; | |
156 | } | |
157 | p += nread; | |
158 | to_read -= nread; | |
159 | } | |
160 | } | |
161 | else | |
162 | goto puntfd; | |
163 | errno = save; | |
164 | } | |
165 | else | |
166 | goto puntfd; | |
167 | } | |
168 | } | |
169 | ||
170 | if (filedata->magic == LIMAGIC (category)) | |
171 | /* Good data file in our byte order. */ | |
172 | swap = 0; | |
173 | else | |
174 | { | |
175 | /* Try the other byte order. */ | |
176 | swap = 1; | |
177 | if (SWAP (&filedata->magic) != LIMAGIC (category)) | |
178 | /* Bad data file in either byte order. */ | |
179 | { | |
180 | puntmap: | |
181 | __munmap ((caddr_t) filedata, st.st_size); | |
182 | puntfd: | |
183 | __close (fd); | |
184 | return NULL; | |
185 | } | |
186 | } | |
187 | ||
188 | #define W(word) SWAP (&(word)) | |
189 | ||
190 | if (W (filedata->nstrings) < _nl_category_num_items[category] || | |
191 | (sizeof *filedata + W (filedata->nstrings) * sizeof (unsigned int) | |
192 | >= st.st_size)) | |
193 | { | |
194 | /* Insufficient data. */ | |
195 | errno = EINVAL; | |
196 | goto puntmap; | |
197 | } | |
198 | ||
199 | newdata = malloc (sizeof *newdata + | |
19bc17a9 | 200 | W (filedata->nstrings) * sizeof (union locale_data_value)); |
933e73fa RM |
201 | if (! newdata) |
202 | goto puntmap; | |
203 | ||
204 | newdata->filedata = (void *) filedata; | |
205 | newdata->filesize = st.st_size; | |
206 | newdata->nstrings = W (filedata->nstrings); | |
207 | for (i = 0; i < newdata->nstrings; ++i) | |
208 | { | |
209 | unsigned int idx = W (filedata->strindex[i]); | |
210 | if (idx >= newdata->filesize) | |
211 | { | |
212 | free (newdata); | |
213 | errno = EINVAL; | |
214 | goto puntmap; | |
215 | } | |
19bc17a9 RM |
216 | if (_nl_value_types[category][i] == word) |
217 | newdata->values[i].word = W (*((u32_t *) (newdata->filedata + idx))); | |
218 | else | |
219 | newdata->values[i].string = newdata->filedata + idx; | |
933e73fa RM |
220 | } |
221 | ||
f0bf9cb9 | 222 | __close (fd); |
933e73fa RM |
223 | return newdata; |
224 | } | |
225 | \f | |
226 | void | |
227 | _nl_free_locale (struct locale_data *data) | |
228 | { | |
229 | int save = errno; | |
8b575de1 RM |
230 | if (! data) |
231 | /* Ignore a null pointer, like free does. */ | |
232 | return; | |
933e73fa RM |
233 | if (__munmap ((caddr_t) data->filedata, data->filesize) < 0) |
234 | { | |
235 | if (errno == ENOSYS) | |
236 | free ((void *) data->filedata); | |
237 | errno = save; | |
238 | } | |
239 | free (data); | |
240 | } | |
241 |