]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/programs/locfile.c
Sat Jul 27 13:02:09 1996 Ulrich Drepper <drepper@cygnus.com>
[thirdparty/glibc.git] / locale / programs / locfile.c
CommitLineData
19bc17a9
RM
1/* Copyright (C) 1996 Free Software Foundation, Inc.
2This file is part of the GNU C Library.
3Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
4
5The GNU C Library is free software; you can redistribute it and/or
6modify it under the terms of the GNU Library General Public License as
7published by the Free Software Foundation; either version 2 of the
8License, or (at your option) any later version.
9
10The GNU C Library is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13Library General Public License for more details.
14
15You should have received a copy of the GNU Library General Public
16License along with the GNU C Library; see the file COPYING.LIB. If
17not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18Boston, 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 <locale.h>
27#include <malloc.h>
75cd5204 28#include <stdio.h>
19bc17a9
RM
29#include <string.h>
30#include <unistd.h>
31#include <sys/stat.h>
32#include <sys/uio.h>
33
34#include "locfile.h"
35#include "linereader.h"
36#include "localeinfo.h"
37#include "locales.h"
38
39
40/* Uncomment the following line in the production version. */
41/* #define NDEBUG 1 */
42#include <assert.h>
43
44/* Define the lookup function. */
45#include "locfile-kw.h"
46
47
48/* Some useful macros. */
49#define MIN(a, b) (__extension__ ({ typeof (a) _a = (a); \
50 typeof (b) _b = (b); \
51 _a < _b ? _a : _b; }))
52
53
54void *xmalloc (size_t __n);
55char *xstrdup (const char *__str);
56
57struct localedef_t *
58locfile_read (const char *filename, struct charset_t *charset)
59{
60 struct linereader *ldfile;
61 struct localedef_t *result;
62 int state;
63 enum token_t expected_tok = tok_none;
64 const char *expected_str = NULL;
65 enum token_t ctype_tok_sym = tok_none;
66 const char *ctype_tok_str = NULL;
67 int copy_category = 0;
68 int cnt;
69
70 /* Allocate space for result. */
71 result = (struct localedef_t *) xmalloc (sizeof (struct localedef_t));
72 memset (result, '\0', sizeof (struct localedef_t));
73
74 ldfile = lr_open (filename, locfile_hash);
75 if (ldfile == NULL)
76 {
77 if (filename[0] != '/')
78 {
79 char path[strlen (filename) + 1 + sizeof (LOCSRCDIR)];
80
81 stpcpy (stpcpy (stpcpy (path, LOCSRCDIR), "/"), filename);
82 ldfile = lr_open (path, locfile_hash);
83 }
84
85 if (ldfile == NULL)
86 {
87 result->failed = 1;
88 return result;
89 }
90 }
91
92#define HANDLE_COPY(category, token, string) \
93 if (nowtok == tok_copy) \
94 { \
95 copy_category = category; \
96 expected_tok = token; \
97 expected_str = string; \
98 state = 8; \
99 continue; \
100 } \
101 ++state
102
103#define LOCALE_PROLOG(token, string) \
104 if (nowtok == tok_eol) \
105 /* Ignore empty lines. */ \
106 continue; \
107 if (nowtok == tok_end) \
108 { \
109 expected_tok = token; \
110 expected_str = string; \
111 state = 4; \
112 continue; \
113 } \
114 if (nowtok == tok_copy) \
115 goto only_copy;
116
117
118#define READ_STRING(fn, errlabel) \
119 do \
120 { \
121 arg = lr_token (ldfile, charset); \
122 if (arg->tok != tok_string) \
123 goto errlabel; \
124 fn (ldfile, result, nowtok, arg, charset); \
125 lr_ignore_rest (ldfile, 1); \
126 } \
127 while (0)
128
129#define READ_STRING_LIST(fn, errlabel) \
130 do \
131 { \
132 arg = lr_token (ldfile, charset); \
133 while (arg->tok == tok_string) \
134 { \
135 fn (ldfile, result, nowtok, arg, charset); \
136 arg = lr_token (ldfile, charset); \
137 if (arg->tok != tok_semicolon) \
138 break; \
139 arg = lr_token (ldfile, charset); \
140 } \
141 if (arg->tok != tok_eol) \
142 goto errlabel; \
143 } \
144 while (0)
145
146#define READ_NUMBER(fn, errlabel) \
147 do \
148 { \
149 arg = lr_token (ldfile, charset); \
150 if (arg->tok != tok_minus1 && arg->tok != tok_number) \
151 goto errlabel; \
152 fn (ldfile, result, nowtok, arg, charset); \
153 lr_ignore_rest (ldfile, 1); \
154 } \
155 while (0)
156
157#define READ_NUMBER_LIST(fn, errlabel) \
158 do \
159 { \
160 arg = lr_token (ldfile, charset); \
161 while (arg->tok == tok_minus1 || arg->tok == tok_number) \
162 { \
163 fn (ldfile, result, nowtok, arg, charset); \
164 arg = lr_token (ldfile, charset); \
165 if (arg->tok != tok_semicolon) \
166 break; \
167 arg = lr_token (ldfile, charset); \
168 } \
169 if (arg->tok != tok_eol) \
170 goto errlabel; \
171 } \
172 while (0)
173
174#define SYNTAX_ERROR(string) \
175 lr_error (ldfile, string); \
176 lr_ignore_rest (ldfile, 0);
177
178
179 /* Parse locale definition file and store result in RESULT. */
180 state = 1;
181 while (1)
182 {
183 /* What's on? */
184 struct token *now = lr_token (ldfile, charset);
185 enum token_t nowtok = now->tok;
186 struct token *arg;
187
188 if (nowtok == tok_eof)
189 break;
190
191 switch (state)
192 {
193 case 1:
194 /* The beginning. We expect the special declarations, EOL or
195 the start of any locale. */
196 if (nowtok == tok_eol)
197 /* Ignore empty lines. */
198 continue;
199
200 switch (nowtok)
201 {
202 case tok_escape_char:
203 case tok_comment_char:
204 /* We need an argument. */
205 arg = lr_token (ldfile, charset);
206
207 if (arg->tok != tok_ident)
208 {
209 SYNTAX_ERROR (_("bad argument"));
210 continue;
211 }
212
213 if (arg->val.str.len != 1)
214 {
215 lr_error (ldfile, _("\
216argument to `%s' must be a single character"),
217 nowtok == tok_escape_char ? "escape_char"
218 : "comment_char");
219
220 lr_ignore_rest (ldfile, 0);
221 continue;
222 }
223
224 if (nowtok == tok_escape_char)
225 ldfile->escape_char = *arg->val.str.start;
226 else
227 ldfile->comment_char = *arg->val.str.start;
228 break;
229
230 case tok_lc_ctype:
231 state = 2;
232 break;
233
234 case tok_lc_collate:
235 state = 10;
236 break;
237
238 case tok_lc_monetary:
239 state = 20;
240 break;
241
242 case tok_lc_numeric:
243 state = 30;
244 break;
245
246 case tok_lc_time:
247 state = 40;
248 break;
249
250 case tok_lc_messages:
251 state = 50;
252 break;
253
254 default:
255 SYNTAX_ERROR (_("\
256syntax error: not inside a locale definition section"));
257 continue;
258 }
259 lr_ignore_rest (ldfile, 1);
260 continue;
261
262 case 2:
263 HANDLE_COPY (LC_CTYPE, tok_lc_ctype, "LC_CYTPE");
264
265 ctype_startup (ldfile, result, charset);
266 /* FALLTHROUGH */
267
268 case 3:
269 /* Here we accept all the character classes, tolower/toupper,
270 and following ANSI C:1995 self-defined classes. */
271 LOCALE_PROLOG (tok_lc_ctype, "LC_CTYPE");
272
273 if (nowtok == tok_charclass)
274 {
275 READ_STRING_LIST (ctype_class_new, bad_new_charclass);
276 continue;
277 bad_new_charclass:
278 SYNTAX_ERROR (_("\
279syntax error in definition of new character class"));
280 continue;
281 }
282
503054c0 283 if (nowtok == tok_charconv)
19bc17a9 284 {
503054c0 285 READ_STRING_LIST (ctype_map_new, bad_new_charconv);
19bc17a9 286 continue;
503054c0 287 bad_new_charconv:
19bc17a9
RM
288 SYNTAX_ERROR (_("\
289syntax error in definition of new character map"));
290 continue;
291 }
292
293 if (nowtok == tok_upper || nowtok == tok_lower
294 || nowtok == tok_alpha || nowtok == tok_digit
295 || nowtok == tok_alnum || nowtok == tok_space
296 || nowtok == tok_cntrl || nowtok == tok_punct
297 || nowtok == tok_graph || nowtok == tok_print
298 || nowtok == tok_xdigit || nowtok == tok_blank)
299 {
300 ctype_tok_sym = nowtok;
301 ctype_tok_str = NULL;
302 state = 5;
303 continue;
304 }
305
306 if (nowtok == tok_toupper|| nowtok == tok_tolower)
307 {
308 ctype_tok_sym = nowtok;
309 ctype_tok_str = NULL;
310 state = 6;
311 continue;
312 }
313
314 if (nowtok != tok_ident)
315 goto bad_charclass;
316
317 /* We possibly have a self-defined character class. */
318 if (ctype_is_charclass (ldfile, result, now->val.str.start))
319 {
320 ctype_tok_sym = nowtok;
321 ctype_tok_str = now->val.str.start;
322 state = 5;
323 continue;
324 }
325
326 /* ...or a self-defined character map. */
503054c0 327 if (ctype_is_charconv (ldfile, result, now->val.str.start))
19bc17a9
RM
328 {
329 ctype_tok_sym = nowtok;
330 ctype_tok_str = now->val.str.start;
331 state = 6;
332 continue;
333 }
334
335 SYNTAX_ERROR (_("syntax error in definition of LC_CTYPE category"));
336 continue;
337
338 case 4:
339 /* Handle `END xxx'. */
340 if (nowtok != expected_tok)
341 lr_error (ldfile, _("\
342`%1$s' definition does not end with `END %1$s'"), expected_str);
343
344 lr_ignore_rest (ldfile, nowtok == expected_tok);
345 state = 1;
346 continue;
347
348 case 5:
349 /* Here we expect a semicolon separated list of bsymbols. The
350 bit to be set in the word is given in CHARCLASS_BIT. */
351 arg = now;
352
353 ctype_class_start (ldfile, result, ctype_tok_sym, ctype_tok_str,
354 charset);
355
356 while (arg->tok != tok_eol)
357 {
358 /* Any token other than a bsymbol is an error. */
359 if (arg->tok != tok_bsymbol)
360 {
361 bad_charclass:
362 SYNTAX_ERROR (_("\
363syntax error in character class definition"));
364 break;
365 }
366
367 /* Lookup value for token and write into array. */
368 ctype_class_from (ldfile, result, arg, charset);
369
370 arg = lr_token (ldfile, charset);
371 if (arg->tok == tok_semicolon)
372 arg = lr_token (ldfile, charset);
373 else if (arg->tok != tok_eol)
374 goto bad_charclass;
375
376 /* Look for ellipsis. */
377 if (arg->tok == tok_ellipsis)
378 {
379 arg = lr_token (ldfile, charset);
380 if (arg->tok != tok_semicolon)
381 goto bad_charclass;
382
383 arg = lr_token (ldfile, charset);
384 if (arg->tok != tok_bsymbol)
385 goto bad_charclass;
386
387 /* Write range starting at LAST to ARG->VAL. */
388 ctype_class_to (ldfile, result, arg, charset);
389
390 arg = lr_token (ldfile, charset);
391 if (arg->tok == tok_semicolon)
392 arg = lr_token (ldfile, charset);
393 else if (arg->tok != tok_eol)
394 goto bad_charclass;
395 }
396 }
397
398 /* Mark class as already seen. */
399 ctype_class_end (ldfile, result);
400 state = 3;
401
402 continue;
403
404 case 6:
405 /* Here we expect a list of character mappings. Note: the
406 first opening brace is already matched. */
407 ctype_map_start (ldfile, result, ctype_tok_sym, ctype_tok_str,
408 charset);
409
410 while (1)
411 {
412 /* Match ( bsymbol , bsymbol ) */
413 if (now->tok != tok_open_brace)
503054c0 414 goto bad_charconv;
19bc17a9
RM
415
416 now = lr_token (ldfile, charset);
417 if (now->tok != tok_bsymbol)
418 {
503054c0 419 bad_charconv:
19bc17a9 420 SYNTAX_ERROR (_("\
503054c0 421syntax error in character conversion definition"));
19bc17a9
RM
422 state = 3;
423 break;
424 }
425
426 /* Lookup arg and assign to FROM. */
427 ctype_map_from (ldfile, result, now, charset);
428
429 now = lr_token (ldfile, charset);
430 if (now->tok != tok_comma)
503054c0 431 goto bad_charconv;
19bc17a9
RM
432
433 now = lr_token (ldfile, charset);
434 if (now->tok != tok_bsymbol)
503054c0 435 goto bad_charconv;
19bc17a9
RM
436
437 /* Lookup arg and assign to TO. */
438 ctype_map_to (ldfile, result, now, charset);
439
440 now = lr_token (ldfile, charset);
441 if (now->tok != tok_close_brace)
503054c0 442 goto bad_charconv;
19bc17a9
RM
443
444 now = lr_token (ldfile, charset);
445 if (now->tok == tok_eol)
446 {
447 state = 3;
448 break;
449 }
450 if (now->tok != tok_semicolon)
503054c0 451 goto bad_charconv;
19bc17a9
RM
452
453 now = lr_token (ldfile, charset);
454 }
455
456 ctype_map_end (ldfile, result);
457 continue;
458
459 case 8:
460 {
461 /* We have seen `copy'. First match the argument. */
462 int warned = 0;
463
464 if (nowtok != tok_string)
465 lr_error (ldfile, _("expect string argument for `copy'"));
466 else
467 def_to_process (now->val.str.start, 1 << copy_category);
468
469 lr_ignore_rest (ldfile, nowtok == tok_string);
470
471 /* The rest of the line must be empty
472 and the next keyword must be `END xxx'. */
473
474 while (lr_token (ldfile, charset)->tok != tok_end)
475 {
476 if (warned == 0)
477 {
478 only_copy:
479 lr_error (ldfile, _("\
480no other keyword shall be specified when `copy' is used"));
481 warned = 1;
482 }
483
484 lr_ignore_rest (ldfile, 0);
485 }
486
487 state = 4;
488 }
489 continue;
490
491 case 10:
492 HANDLE_COPY (LC_COLLATE, tok_lc_collate, "LC_COLLATE");
493
494 collate_startup (ldfile, result, charset);
495 /* FALLTHROUGH */
496
497 case 11:
498 /* Process the LC_COLLATE section. We expect `END LC_COLLATE'
499 any of the collation specifications, or any bsymbol. */
500 LOCALE_PROLOG (tok_lc_collate, "LC_COLLATE");
501
502 if (nowtok == tok_order_start)
503 {
504 state = 12;
505 continue;
506 }
507
508 if (nowtok != tok_collating_element
509 && nowtok != tok_collating_symbol)
510 {
511 bad_collation:
512 lr_error (ldfile, _("\
513syntax error in collation definition"));
514 lr_ignore_rest (ldfile, 0);
515 continue;
516 }
517
518 /* Get argument. */
519 arg = lr_token (ldfile, charset);
520 if (arg->tok != tok_bsymbol)
521 {
522 lr_error (ldfile, _("\
523collation symbol expected after `%s'"),
524 nowtok == tok_collating_element
525 ? "collating-element" : "collating-symbol");
526 lr_ignore_rest (ldfile, 0);
527 continue;
528 }
529
530 if (nowtok == tok_collating_element)
531 {
532 /* Save to-value as new name. */
533 collate_element_to (ldfile, result, arg, charset);
534
535 arg = lr_token (ldfile, charset);
536 if (arg->tok != tok_from)
537 {
538 lr_error (ldfile, _("\
539`from' expected after first argument to `collating-element'"));
540 lr_ignore_rest (ldfile, 0);
541 continue;
542 }
543
544 arg = lr_token (ldfile, charset);
545 if (arg->tok != tok_string)
546 {
547 lr_error (ldfile, _("\
548from-value of `collating-element' must be a string"));
549 lr_ignore_rest (ldfile, 0);
550 continue;
551 }
552
553 /* Enter new collating element. */
554 collate_element_from (ldfile, result, arg, charset);
555 }
556 else
557 /* Enter new collating symbol into table. */
558 collate_symbol (ldfile, result, arg, charset);
559
560 lr_ignore_rest (ldfile, 1);
561 continue;
562
563 case 12:
564 /* We parse the rest of the line containing `order_start'.
565 In any case we continue with parsing the symbols. */
566 state = 13;
567
568 cnt = 0;
569 while (now->tok != tok_eol)
570 {
571 int collation_method = 0;
572
573 ++cnt;
574
575 do
576 {
577 if (now->tok == tok_forward)
578 collation_method |= sort_forward;
579 else if (now->tok == tok_backward)
580 collation_method |= sort_backward;
581 else if (now->tok == tok_position)
582 collation_method |= sort_position;
583 else
584 {
585 lr_error (ldfile, _("unknown collation directive"));
586 lr_ignore_rest (ldfile, 0);
587 continue;
588 }
589
590 now = lr_token (ldfile, charset);
591 }
592 while (now->tok == tok_comma
593 && (now == lr_token (ldfile, charset) != tok_none));
594
595 /* Check for consistency: forward and backwards are
596 mutually exclusive. */
597 if ((collation_method & sort_forward) != 0
598 && (collation_method & sort_backward) != 0)
599 {
600 lr_error (ldfile, _("\
601sorting order `forward' and `backward' are mutually exclusive"));
602 /* The recover clear the backward flag. */
603 collation_method &= ~sort_backward;
604 }
605
606 /* ??? I don't know whether this is correct but while
607 thinking about the `strcoll' functions I found that I
608 need a direction when performing position depended
609 collation. So I assume here that implicitly the
610 direction `forward' is given when `position' alone is
611 written. --drepper */
612 if (collation_method == sort_position)
613 collation_method |= sort_forward;
614
615 /* Enter info about next collation order. */
616 collate_new_order (ldfile, result, collation_method);
617
618 if (now->tok != tok_eol && now->tok != tok_semicolon)
619 {
620 lr_error (ldfile, _("\
621syntax error in `order_start' directive"));
622 lr_ignore_rest (ldfile, 0);
623 break;
624 }
625
626 if (now->tok == tok_semicolon)
627 now = lr_token (ldfile, charset);
628 }
629
630 /* If no argument to `order_start' is given, one `forward'
631 argument is implicitely assumed. */
632 if (cnt == 0)
633 collate_new_order (ldfile, result, sort_forward);
634
635
636 /* We now know about all sorting rules. */
637 collate_build_arrays (ldfile, result);
638
639 continue;
640
641 case 13:
642 /* We read one symbol a line until `order_end' is found. */
643 {
644 static int last_correct = 1;
645
646 if (nowtok == tok_order_end)
647 {
648 state = 14;
649 lr_ignore_rest (ldfile, 1);
650 continue;
651 }
652
653 /* Ignore empty lines. */
654 if (nowtok == tok_eol)
655 continue;
656
657 if (nowtok != tok_bsymbol && nowtok != tok_undefined
658 && nowtok != tok_ellipsis)
659 {
660 if (last_correct == 1)
661 {
662 lr_error (ldfile, _("\
663syntax error in collating order definition"));
664 last_correct = 0;
665 }
666 lr_ignore_rest (ldfile, 0);
667 continue;
668 }
669 else
670 {
671 last_correct = 1;
672
673 /* Remember current token. */
674 if (collate_order_elem (ldfile, result, now, charset) < 0)
675 continue;
676 }
677
678 /* Read optional arguments. */
679 arg = lr_token (ldfile, charset);
680 while (arg->tok != tok_eol)
681 {
682 if (arg->tok != tok_ignore && arg->tok != tok_ellipsis
683 && arg->tok != tok_bsymbol && arg->tok != tok_string)
684 break;
685
686 if (arg->tok == tok_ignore || arg->tok == tok_ellipsis
687 || arg->tok == tok_string)
688 {
689 /* Call handler for simple weights. */
690 if (collate_simple_weight (ldfile, result, arg, charset)
691 < 0)
692 goto illegal_weight;
693
694 arg = lr_token (ldfile, charset);
695 }
696 else
697 do
698 {
699 /* Collect char. */
700 int ok = collate_weight_bsymbol (ldfile, result, arg,
701 charset);
702 if (ok < 0)
703 goto illegal_weight;
704
705 arg = lr_token (ldfile, charset);
706 }
707 while (arg->tok == tok_bsymbol);
708
709 /* Are there more weights? */
710 if (arg->tok != tok_semicolon)
711 break;
712
713 /* Yes, prepare next weight. */
714 if (collate_next_weight (ldfile, result) < 0)
715 goto illegal_weight;
716
717 arg = lr_token (ldfile, charset);
718 }
719
720 if (arg->tok != tok_eol)
721 {
722 SYNTAX_ERROR (_("syntax error in order specification"));
723 }
724
725 collate_end_weight (ldfile, result);
726 illegal_weight:
727 }
728 continue;
729
730 case 14:
731 /* Following to the `order_end' keyword we don't expect
732 anything but the `END'. */
733 if (nowtok == tok_eol)
734 continue;
735
736 if (nowtok != tok_end)
737 goto bad_collation;
738
739 expected_tok = tok_lc_collate;
740 expected_str = "LC_COLLATE";
741 state = 4;
742
743 ldfile->translate_strings = 1;
744 continue;
745
746 case 20:
747 HANDLE_COPY (LC_MONETARY, tok_lc_monetary, "LC_MONETARY");
748
749 monetary_startup (ldfile, result, charset);
750 /* FALLTHROUGH */
751
752 case 21:
753 LOCALE_PROLOG (tok_lc_monetary, "LC_MONETARY");
754
755 switch (nowtok)
756 {
757 case tok_int_curr_symbol:
758 case tok_currency_symbol:
759 case tok_mon_decimal_point:
760 case tok_mon_thousands_sep:
761 case tok_positive_sign:
762 case tok_negative_sign:
763 READ_STRING (monetary_add, bad_monetary);
764 break;
765
766 case tok_int_frac_digits:
767 case tok_frac_digits:
768 case tok_p_cs_precedes:
769 case tok_p_sep_by_space:
770 case tok_n_cs_precedes:
771 case tok_n_sep_by_space:
772 case tok_p_sign_posn:
773 case tok_n_sign_posn:
774 READ_NUMBER (monetary_add, bad_monetary);
775 break;
776
777 case tok_mon_grouping:
778 /* We have a semicolon separated list of integers. */
779 READ_NUMBER_LIST (monetary_add, bad_monetary);
780 break;
781
782 default:
783 bad_monetary:
784 SYNTAX_ERROR (_("syntax error in monetary locale definition"));
785 }
786 continue;
787
788 case 30:
789 HANDLE_COPY (LC_NUMERIC, tok_lc_numeric, "LC_NUMERIC");
790
791 numeric_startup (ldfile, result, charset);
792 /* FALLTHROUGH */
793
794 case 31:
795 LOCALE_PROLOG (tok_lc_numeric, "LC_NUMERIC");
796
797 switch (nowtok)
798 {
799 case tok_decimal_point:
800 case tok_thousands_sep:
801 READ_STRING (numeric_add, bad_numeric);
802 break;
803
804 case tok_grouping:
805 /* We have a semicolon separated list of integers. */
806 READ_NUMBER_LIST (numeric_add, bad_numeric);
807 break;
808
809 default:
810 bad_numeric:
811 SYNTAX_ERROR (_("syntax error in numeric locale definition"));
812 }
813 continue;
814
815 case 40:
816 HANDLE_COPY (LC_TIME, tok_lc_time, "LC_TIME");
817
818 time_startup (ldfile, result, charset);
819 /* FALLTHROUGH */
820
821 case 41:
822 LOCALE_PROLOG (tok_lc_time, "LC_TIME");
823
824 switch (nowtok)
825 {
826 case tok_abday:
827 case tok_day:
828 case tok_abmon:
829 case tok_mon:
830 case tok_am_pm:
831 case tok_alt_digits:
832 READ_STRING_LIST (time_add, bad_time);
833 continue;
834
835 case tok_d_t_fmt:
836 case tok_d_fmt:
837 case tok_t_fmt:
838 case tok_t_fmt_ampm:
839 case tok_era:
840 case tok_era_year:
841 case tok_era_d_t_fmt:
842 case tok_era_d_fmt:
843 case tok_era_t_fmt:
844 READ_STRING (time_add, bad_time);
845 break;
846
847 default:
848 bad_time:
849 SYNTAX_ERROR (_("syntax error in time locale definition"));
850 }
851 continue;
852
853 case 50:
854 HANDLE_COPY (LC_MESSAGES, tok_lc_messages, "LC_MESSAGES");
855
856 messages_startup (ldfile, result, charset);
857 /* FALLTHROUGH */
858
859 case 51:
860 LOCALE_PROLOG (tok_lc_messages, "LC_MESSAGES");
861
862 switch (nowtok)
863 {
864 case tok_yesexpr:
865 case tok_noexpr:
866 case tok_yesstr:
867 case tok_nostr:
868 READ_STRING (messages_add, bad_message);
869 break;
870
871 default:
872 bad_message:
873 SYNTAX_ERROR (_("syntax error in message locale definition"));
874 }
875 continue;
876
877 default:
878 error (5, 0, _("%s: error in state machine"), __FILE__);
879 /* NOTREACHED */
880 }
881
882 break;
883 }
884
885 /* We read all of the file. */
886 lr_close (ldfile);
887
888 /* Let's see what information is available. */
889 for (cnt = LC_CTYPE; cnt <= LC_MESSAGES; ++cnt)
890 if (result->categories[cnt].generic != NULL)
891 result->avail |= 1 << cnt;
892
893 return result;
894}
895
896
897void
898check_all_categories (struct localedef_t *locale, struct charset_t *charset)
899{
900 /* Call the finishing functions for all locales. */
901 if ((locale->binary & (1 << LC_CTYPE)) == 0)
902 ctype_finish (locale, charset);
903 if ((locale->binary & (1 << LC_COLLATE)) == 0)
904 collate_finish (locale, charset);
905 if ((locale->binary & (1 << LC_MONETARY)) == 0)
906 monetary_finish (locale);
907 if ((locale->binary & (1 << LC_NUMERIC)) == 0)
908 numeric_finish (locale);
909 if ((locale->binary & (1 << LC_TIME)) == 0)
910 time_finish (locale);
911 if ((locale->binary & (1 << LC_MESSAGES)) == 0)
912 messages_finish (locale);
913}
914
915
916void
75cd5204
RM
917write_all_categories (struct localedef_t *locale, struct charset_t *charset,
918 const char *output_path)
19bc17a9
RM
919{
920 /* Call all functions to write locale data. */
75cd5204 921 ctype_output (locale, charset, output_path);
19bc17a9
RM
922 collate_output (locale, output_path);
923 monetary_output (locale, output_path);
924 numeric_output (locale, output_path);
925 time_output (locale, output_path);
926 messages_output (locale, output_path);
927}
928
929
930void
931write_locale_data (const char *output_path, const char *category,
932 size_t n_elem, struct iovec *vec)
933{
c199a24f 934 size_t cnt, step, maxiov;
19bc17a9
RM
935 int fd;
936 char *fname;
937
036cc82f
RM
938 fname = malloc (strlen (output_path) + strlen (category) + 6);
939 if (fname == NULL)
940 error (5, errno, _("memory exhausted"));
941
942 /* Normally we write to the directory pointed to by the OUTPUT_PATH.
943 But for LC_MESSAGES we have to take care for the translation
944 data. This means we need to have a directory LC_MESSAGES in
945 which we place the file under the name SYS_LC_MESSAGES. */
946 if (strcmp (category, "LC_MESSAGES") == 0)
947 fd = -1;
948 else
949 {
950 sprintf (fname, "%s%s", output_path, category);
951 fd = creat (fname, 0666);
952 }
953
19bc17a9
RM
954 if (fd == -1)
955 {
956 int save_err = errno;
957
958 if (errno == EISDIR)
959 {
036cc82f 960 sprintf (fname, "%1$s%2$s/SYS_%2$s", output_path, category);
19bc17a9
RM
961 fd = creat (fname, 0666);
962 if (fd == -1)
963 save_err = errno;
964 }
965
966 if (fd == -1)
967 {
968 error (0, save_err, _("cannot open output file for category `%s'"),
969 category);
970 return;
971 }
972 }
973 free (fname);
974
c199a24f
MB
975#ifdef UIO_MAXIOV
976 maxiov = UIO_MAXIOV;
977#else
978 maxiov = sysconf (_SC_UIO_MAXIOV);
979#endif
980
19bc17a9
RM
981 /* Write the data using writev. But we must take care for the
982 limitation of the implementation. */
983 for (cnt = 0; cnt < n_elem; cnt += step)
984 {
c199a24f
MB
985 step = n_elem - cnt;
986 if (maxiov > 0)
987 step = MIN (maxiov, step);
19bc17a9
RM
988
989 if (writev (fd, &vec[cnt], step) < 0)
990 {
991 error (0, errno, _("failure while writing data for category `%s'"),
992 category);
993 break;
994 }
995 }
996
997 close (fd);
998}