]> git.ipfire.org Git - thirdparty/glibc.git/blob - locale/programs/locfile.c
Update.
[thirdparty/glibc.git] / locale / programs / locfile.c
1 /* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
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 not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <sys/param.h>
29 #include <sys/stat.h>
30
31 #include "localedef.h"
32 #include "locfile.h"
33
34 #include "locfile-kw.h"
35
36
37 int
38 locfile_read (struct localedef_t *result, struct charmap_t *charmap)
39 {
40 const char *filename = result->name;
41 const char *repertoire_name = result->repertoire_name;
42 int locale_mask = result->needed ^ result->avail;
43 struct linereader *ldfile;
44
45 /* If no repertoire name was specified use the global one. */
46 if (repertoire_name == NULL)
47 repertoire_name = repertoire_global;
48
49 /* Open the locale definition file. */
50 ldfile = lr_open (filename, locfile_hash);
51 if (ldfile == NULL)
52 {
53 if (filename[0] != '/')
54 {
55 char *i18npath = getenv ("I18NPATH");
56 if (i18npath != NULL && *i18npath != '\0')
57 {
58 char path[strlen (filename) + 1 + strlen (i18npath)
59 + sizeof ("/locales/") - 1];
60 char *next;
61 i18npath = strdupa (i18npath);
62
63
64 while (ldfile == NULL
65 && (next = strsep (&i18npath, ":")) != NULL)
66 {
67 stpcpy (stpcpy (stpcpy (path, next), "/locales/"), filename);
68
69 ldfile = lr_open (path, locfile_hash);
70
71 if (ldfile == NULL)
72 {
73 stpcpy (stpcpy (path, next), filename);
74
75 ldfile = lr_open (path, locfile_hash);
76 }
77 }
78 }
79
80 /* Test in the default directory. */
81 if (ldfile == NULL)
82 {
83 char path[strlen (filename) + 1 + sizeof (LOCSRCDIR)];
84
85 stpcpy (stpcpy (stpcpy (path, LOCSRCDIR), "/"), filename);
86 ldfile = lr_open (path, locfile_hash);
87 }
88 }
89
90 if (ldfile == NULL)
91 return 1;
92 }
93
94 /* Parse locale definition file and store result in RESULT. */
95 while (1)
96 {
97 struct token *now = lr_token (ldfile, charmap, NULL);
98 enum token_t nowtok = now->tok;
99 struct token *arg;
100
101 if (nowtok == tok_eof)
102 break;
103
104 if (nowtok == tok_eol)
105 /* Ignore empty lines. */
106 continue;
107
108 switch (nowtok)
109 {
110 case tok_escape_char:
111 case tok_comment_char:
112 /* We need an argument. */
113 arg = lr_token (ldfile, charmap, NULL);
114
115 if (arg->tok != tok_ident)
116 {
117 SYNTAX_ERROR (_("bad argument"));
118 continue;
119 }
120
121 if (arg->val.str.lenmb != 1)
122 {
123 lr_error (ldfile, _("\
124 argument to `%s' must be a single character"),
125 nowtok == tok_escape_char
126 ? "escape_char" : "comment_char");
127
128 lr_ignore_rest (ldfile, 0);
129 continue;
130 }
131
132 if (nowtok == tok_escape_char)
133 ldfile->escape_char = *arg->val.str.startmb;
134 else
135 ldfile->comment_char = *arg->val.str.startmb;
136 break;
137
138 case tok_repertoiremap:
139 /* We need an argument. */
140 arg = lr_token (ldfile, charmap, NULL);
141
142 if (arg->tok != tok_ident)
143 {
144 SYNTAX_ERROR (_("bad argument"));
145 continue;
146 }
147
148 if (repertoire_name == NULL)
149 {
150 repertoire_name = memcpy (xmalloc (arg->val.str.lenmb + 1),
151 arg->val.str.startmb,
152 arg->val.str.lenmb);
153 ((char *) repertoire_name)[arg->val.str.lenmb] = '\0';
154 }
155 break;
156
157 case tok_lc_ctype:
158 ctype_read (ldfile, result, charmap, repertoire_name,
159 (locale_mask & CTYPE_LOCALE) == 0);
160 result->avail |= locale_mask & CTYPE_LOCALE;
161 continue;
162
163 case tok_lc_collate:
164 collate_read (ldfile, result, charmap, repertoire_name,
165 (locale_mask & COLLATE_LOCALE) == 0);
166 result->avail |= locale_mask & COLLATE_LOCALE;
167 continue;
168
169 case tok_lc_monetary:
170 monetary_read (ldfile, result, charmap, repertoire_name,
171 (locale_mask & MONETARY_LOCALE) == 0);
172 result->avail |= locale_mask & MONETARY_LOCALE;
173 continue;
174
175 case tok_lc_numeric:
176 numeric_read (ldfile, result, charmap, repertoire_name,
177 (locale_mask & NUMERIC_LOCALE) == 0);
178 result->avail |= locale_mask & NUMERIC_LOCALE;
179 continue;
180
181 case tok_lc_time:
182 time_read (ldfile, result, charmap, repertoire_name,
183 (locale_mask & TIME_LOCALE) == 0);
184 result->avail |= locale_mask & TIME_LOCALE;
185 continue;
186
187 case tok_lc_messages:
188 messages_read (ldfile, result, charmap, repertoire_name,
189 (locale_mask & MESSAGES_LOCALE) == 0);
190 result->avail |= locale_mask & MESSAGES_LOCALE;
191 continue;
192
193 case tok_lc_paper:
194 paper_read (ldfile, result, charmap, repertoire_name,
195 (locale_mask & PAPER_LOCALE) == 0);
196 result->avail |= locale_mask & PAPER_LOCALE;
197 continue;
198
199 case tok_lc_name:
200 name_read (ldfile, result, charmap, repertoire_name,
201 (locale_mask & NAME_LOCALE) == 0);
202 result->avail |= locale_mask & NAME_LOCALE;
203 continue;
204
205 case tok_lc_address:
206 address_read (ldfile, result, charmap, repertoire_name,
207 (locale_mask & ADDRESS_LOCALE) == 0);
208 result->avail |= locale_mask & ADDRESS_LOCALE;
209 continue;
210
211 case tok_lc_telephone:
212 telephone_read (ldfile, result, charmap, repertoire_name,
213 (locale_mask & TELEPHONE_LOCALE) == 0);
214 result->avail |= locale_mask & TELEPHONE_LOCALE;
215 continue;
216
217 case tok_lc_measurement:
218 measurement_read (ldfile, result, charmap, repertoire_name,
219 (locale_mask & MEASUREMENT_LOCALE) == 0);
220 result->avail |= locale_mask & MEASUREMENT_LOCALE;
221 continue;
222
223 case tok_lc_identification:
224 identification_read (ldfile, result, charmap, repertoire_name,
225 (locale_mask & IDENTIFICATION_LOCALE) == 0);
226 result->avail |= locale_mask & IDENTIFICATION_LOCALE;
227 continue;
228
229 default:
230 SYNTAX_ERROR (_("\
231 syntax error: not inside a locale definition section"));
232 continue;
233 }
234
235 /* The rest of the line must be empty. */
236 lr_ignore_rest (ldfile, 1);
237 }
238
239 /* We read all of the file. */
240 lr_close (ldfile);
241
242 return 0;
243 }
244
245
246 static void (*const check_funcs[]) (struct localedef_t *,
247 struct charmap_t *) =
248 {
249 [LC_CTYPE] = ctype_finish,
250 [LC_COLLATE] = collate_finish,
251 [LC_MESSAGES] = messages_finish,
252 [LC_MONETARY] = monetary_finish,
253 [LC_NUMERIC] = numeric_finish,
254 [LC_TIME] = time_finish,
255 [LC_PAPER] = paper_finish,
256 [LC_NAME] = name_finish,
257 [LC_ADDRESS] = address_finish,
258 [LC_TELEPHONE] = telephone_finish,
259 [LC_MEASUREMENT] = measurement_finish,
260 [LC_IDENTIFICATION] = identification_finish
261 };
262
263
264 void
265 check_all_categories (struct localedef_t *definitions,
266 struct charmap_t *charmap)
267 {
268 int cnt;
269
270 for (cnt = 0; cnt < sizeof (check_funcs) / sizeof (check_funcs[0]); ++cnt)
271 if (check_funcs[cnt] != NULL)
272 check_funcs[cnt] (definitions, charmap);
273 }
274
275
276 static void (*const write_funcs[]) (struct localedef_t *, struct charmap_t *,
277 const char *) =
278 {
279 [LC_CTYPE] = ctype_output,
280 [LC_COLLATE] = collate_output,
281 [LC_MESSAGES] = messages_output,
282 [LC_MONETARY] = monetary_output,
283 [LC_NUMERIC] = numeric_output,
284 [LC_TIME] = time_output,
285 [LC_PAPER] = paper_output,
286 [LC_NAME] = name_output,
287 [LC_ADDRESS] = address_output,
288 [LC_TELEPHONE] = telephone_output,
289 [LC_MEASUREMENT] = measurement_output,
290 [LC_IDENTIFICATION] = identification_output
291 };
292
293
294 void
295 write_all_categories (struct localedef_t *definitions,
296 struct charmap_t *charmap,
297 const char *output_path)
298 {
299 int cnt;
300
301 for (cnt = 0; cnt < sizeof (write_funcs) / sizeof (write_funcs[0]); ++cnt)
302 if (check_funcs[cnt] != NULL)
303 write_funcs[cnt] (definitions, charmap, output_path);
304 }
305
306
307 void
308 write_locale_data (const char *output_path, const char *category,
309 size_t n_elem, struct iovec *vec)
310 {
311 size_t cnt, step, maxiov;
312 int fd;
313 char *fname;
314
315 fname = malloc (strlen (output_path) + 2 * strlen (category) + 6);
316 if (fname == NULL)
317 error (5, errno, _("memory exhausted"));
318
319 /* Normally we write to the directory pointed to by the OUTPUT_PATH.
320 But for LC_MESSAGES we have to take care for the translation
321 data. This means we need to have a directory LC_MESSAGES in
322 which we place the file under the name SYS_LC_MESSAGES. */
323 sprintf (fname, "%s/%s", output_path, category);
324 if (strcmp (category, "LC_MESSAGES") == 0)
325 {
326 struct stat st;
327
328 if (stat (fname, &st) < 0)
329 {
330 if (mkdir (fname, 0777) < 0)
331 fd = creat (fname, 0666);
332 else
333 {
334 fd = -1;
335 errno = EISDIR;
336 }
337 }
338 else if (S_ISREG (st.st_mode))
339 fd = creat (fname, 0666);
340 else
341 {
342 fd = -1;
343 errno = EISDIR;
344 }
345 }
346 else
347 fd = creat (fname, 0666);
348
349 if (fd == -1)
350 {
351 int save_err = errno;
352
353 if (errno == EISDIR)
354 {
355 sprintf (fname, "%1$s/%2$s/SYS_%2$s", output_path, category);
356 fd = creat (fname, 0666);
357 if (fd == -1)
358 save_err = errno;
359 }
360
361 if (fd == -1)
362 {
363 if (!be_quiet)
364 error (0, save_err, _("\
365 cannot open output file `%s' for category `%s'"),
366 fname, category);
367 return;
368 }
369 }
370 free (fname);
371
372 #ifdef UIO_MAXIOV
373 maxiov = UIO_MAXIOV;
374 #else
375 maxiov = sysconf (_SC_UIO_MAXIOV);
376 #endif
377
378 /* Write the data using writev. But we must take care for the
379 limitation of the implementation. */
380 for (cnt = 0; cnt < n_elem; cnt += step)
381 {
382 step = n_elem - cnt;
383 if (maxiov > 0)
384 step = MIN (maxiov, step);
385
386 if (writev (fd, &vec[cnt], step) < 0)
387 {
388 if (!be_quiet)
389 error (0, errno, _("failure while writing data for category `%s'"),
390 category);
391 break;
392 }
393 }
394
395 close (fd);
396 }