]>
Commit | Line | Data |
---|---|---|
a641835a | 1 | /* Copyright (C) 1996 Free Software Foundation, Inc. |
2c6fe0bd UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>. | |
a641835a | 4 | |
2c6fe0bd 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. | |
a641835a | 9 | |
2c6fe0bd 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. | |
a641835a | 14 | |
2c6fe0bd 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. */ | |
a641835a RM |
19 | |
20 | #include <endian.h> | |
21 | #include <fcntl.h> | |
22 | #include <string.h> | |
23 | #include <stdlib.h> | |
24 | #include <unistd.h> | |
25 | #include <sys/mman.h> | |
26 | #include <sys/stat.h> | |
27 | ||
28 | #include "catgetsinfo.h" | |
29 | ||
30 | ||
31 | #define SWAPU32(w) \ | |
32 | (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24)) | |
33 | ||
34 | ||
35 | void | |
36 | __open_catalog (__nl_catd catalog, int with_path) | |
37 | { | |
38 | int fd; | |
39 | struct stat st; | |
40 | int swapping; | |
41 | ||
42 | if (strchr (catalog->cat_name, '/') != NULL || !with_path) | |
43 | fd = open (catalog->cat_name, O_RDONLY); | |
44 | else | |
45 | { | |
46 | const char *run_nlspath = catalog->nlspath; | |
47 | #define ENOUGH(n) \ | |
48 | if (bufact + (n) >=bufmax) \ | |
49 | { \ | |
50 | char *old_buf = buf; \ | |
51 | bufmax += 256 + (n); \ | |
52 | buf = (char *) alloca (bufmax); \ | |
53 | memcpy (buf, old_buf, bufact); \ | |
54 | } | |
55 | ||
56 | /* The RUN_NLSPATH variable contains a colon separated list of | |
57 | descriptions where we expect to find catalogs. We have to | |
58 | recognize certain % substitutions and stop when we found the | |
59 | first existing file. */ | |
60 | char *buf; | |
61 | size_t bufact; | |
62 | size_t bufmax; | |
63 | ||
64 | buf = NULL; | |
65 | bufmax = 0; | |
66 | ||
67 | fd = -1; | |
68 | while (*run_nlspath != '\0') | |
69 | { | |
70 | bufact = 0; | |
71 | while (*run_nlspath != ':' && *run_nlspath != '\0') | |
72 | if (*run_nlspath == '%') | |
73 | { | |
74 | const char *tmp; | |
75 | ||
76 | ++run_nlspath; /* We have seen the `%'. */ | |
77 | switch (*run_nlspath++) | |
78 | { | |
79 | case 'N': | |
80 | /* Use the catalog name. */ | |
81 | ENOUGH (strlen (catalog->cat_name)); | |
a5113b14 | 82 | bufact = __stpcpy (&buf[bufact], catalog->cat_name) - buf; |
a641835a RM |
83 | break; |
84 | case 'L': | |
85 | /* Use the current locale category value. */ | |
86 | ENOUGH (strlen (catalog->env_var)); | |
a5113b14 | 87 | bufact = __stpcpy (&buf[bufact], catalog->env_var) - buf; |
a641835a RM |
88 | break; |
89 | case 'l': | |
90 | /* Use language element of locale category value. */ | |
91 | tmp = catalog->env_var; | |
92 | do | |
93 | { | |
94 | ENOUGH (1); | |
95 | buf[bufact++] = *tmp++; | |
96 | } | |
97 | while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); | |
98 | break; | |
99 | case 't': | |
100 | /* Use territory element of locale category value. */ | |
101 | tmp = catalog->env_var; | |
102 | do | |
103 | ++tmp; | |
104 | while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); | |
105 | if (*tmp == '_') | |
106 | { | |
107 | ++tmp; | |
108 | do | |
109 | { | |
110 | ENOUGH (1); | |
111 | buf[bufact++] = *tmp; | |
112 | } | |
113 | while (*tmp != '\0' && *tmp != '.'); | |
114 | } | |
115 | break; | |
116 | case 'c': | |
117 | /* Use code set element of locale category value. */ | |
118 | tmp = catalog->env_var; | |
119 | do | |
120 | ++tmp; | |
121 | while (*tmp != '\0' && *tmp != '.'); | |
122 | if (*tmp == '.') | |
123 | { | |
124 | ++tmp; | |
125 | do | |
126 | { | |
127 | ENOUGH (1); | |
128 | buf[bufact++] = *tmp; | |
129 | } | |
130 | while (*tmp != '\0'); | |
131 | } | |
132 | break; | |
133 | case '%': | |
134 | ENOUGH (1); | |
135 | buf[bufact++] = '%'; | |
136 | break; | |
137 | default: | |
138 | /* Unknown variable: ignore this path element. */ | |
139 | bufact = 0; | |
140 | while (*run_nlspath != '\0' && *run_nlspath != ':') | |
141 | ++run_nlspath; | |
142 | break; | |
143 | } | |
144 | } | |
145 | else | |
146 | { | |
147 | ENOUGH (1); | |
148 | buf[bufact++] = *run_nlspath++; | |
149 | } | |
150 | ENOUGH (1); | |
151 | buf[bufact] = '\0'; | |
152 | ||
153 | if (bufact != 0) | |
154 | { | |
a5113b14 | 155 | fd = __open (buf, O_RDONLY); |
a641835a RM |
156 | if (fd >= 0) |
157 | break; | |
158 | } | |
159 | ||
160 | ++run_nlspath; | |
161 | } | |
162 | } | |
163 | ||
a5113b14 | 164 | if (fd < 0 || __fstat (fd, &st) < 0) |
a641835a RM |
165 | { |
166 | catalog->status = nonexisting; | |
167 | return; | |
168 | } | |
169 | ||
170 | #ifndef MAP_COPY | |
171 | /* Linux seems to lack read-only copy-on-write. */ | |
172 | #define MAP_COPY MAP_PRIVATE | |
173 | #endif | |
174 | #ifndef MAP_FILE | |
175 | /* Some systems do not have this flag; it is superfluous. */ | |
176 | #define MAP_FILE 0 | |
177 | #endif | |
178 | #ifndef MAP_INHERIT | |
179 | /* Some systems might lack this; they lose. */ | |
180 | #define MAP_INHERIT 0 | |
181 | #endif | |
182 | catalog->file_size = st.st_size; | |
183 | catalog->file_ptr = | |
a5113b14 UD |
184 | (struct catalog_obj *) __mmap (NULL, st.st_size, PROT_READ, |
185 | MAP_FILE|MAP_COPY|MAP_INHERIT, fd, 0); | |
a641835a RM |
186 | if (catalog->file_ptr != (struct catalog_obj *) -1) |
187 | /* Tell the world we managed to mmap the file. */ | |
188 | catalog->status = mmaped; | |
189 | else | |
190 | { | |
191 | /* mmap failed perhaps because the system call is not | |
192 | implemented. Try to load the file. */ | |
193 | size_t todo; | |
194 | catalog->file_ptr = malloc (st.st_size); | |
195 | if (catalog->file_ptr == NULL) | |
196 | { | |
197 | catalog->status = nonexisting; | |
198 | return; | |
199 | } | |
200 | todo = st.st_size; | |
201 | /* Save read, handle partial reads. */ | |
202 | do | |
203 | { | |
a5113b14 UD |
204 | size_t now = __read (fd, (((char *) &catalog->file_ptr) |
205 | + (st.st_size - todo)), todo); | |
a641835a RM |
206 | if (now == 0) |
207 | { | |
208 | free ((void *) catalog->file_ptr); | |
209 | catalog->status = nonexisting; | |
210 | return; | |
211 | } | |
212 | todo -= now; | |
213 | } | |
214 | while (todo > 0); | |
215 | catalog->status = malloced; | |
216 | } | |
217 | ||
218 | /* We don't need the file anymore. */ | |
a5113b14 | 219 | __close (fd); |
a641835a RM |
220 | |
221 | /* Determine whether the file is a catalog file and if yes whether | |
222 | it is written using the correct byte order. Else we have to swap | |
223 | the values. */ | |
224 | if (catalog->file_ptr->magic == CATGETS_MAGIC) | |
225 | swapping = 0; | |
226 | else if (catalog->file_ptr->magic == SWAPU32 (CATGETS_MAGIC)) | |
227 | swapping = 1; | |
228 | else | |
229 | { | |
230 | /* Illegal file. Free he resources and mark catalog as not | |
231 | usable. */ | |
232 | if (catalog->status == mmaped) | |
a5113b14 | 233 | __munmap ((void *) catalog->file_ptr, catalog->file_size); |
a641835a RM |
234 | else |
235 | free (catalog->file_ptr); | |
236 | catalog->status = nonexisting; | |
237 | return; | |
238 | } | |
239 | ||
240 | #define SWAP(x) (swapping ? SWAPU32 (x) : (x)) | |
241 | ||
242 | /* Get dimensions of the used hashing table. */ | |
243 | catalog->plane_size = SWAP (catalog->file_ptr->plane_size); | |
244 | catalog->plane_depth = SWAP (catalog->file_ptr->plane_depth); | |
245 | ||
246 | /* The file contains two versions of the pointer tables. Pick the | |
247 | right one for the local byte order. */ | |
248 | #if __BYTE_ORDER == __LITTLE_ENDIAN | |
249 | catalog->name_ptr = &catalog->file_ptr->name_ptr[0]; | |
250 | #elif __BYTE_ORDER == __BIG_ENDIAN | |
251 | catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size | |
252 | * catalog->plane_depth | |
253 | * 3]; | |
254 | #else | |
255 | # error Cannot handle __BYTE_ORDER byte order | |
256 | #endif | |
257 | ||
258 | /* The rest of the file contains all the strings. They are | |
259 | addressed relative to the position of the first string. */ | |
260 | catalog->strings = | |
261 | (const char *) &catalog->file_ptr->name_ptr[catalog->plane_size | |
262 | * catalog->plane_depth * 3 * 2]; | |
263 | } |