Update.
[glibc.git] / locale / programs / locfile.c
blob6385df47e838720793124af791ee476c6f4f9985
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
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.
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.
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. */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <locale.h>
27 #include <malloc.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <sys/uio.h>
35 #include "locfile.h"
36 #include "linereader.h"
37 #include "localeinfo.h"
38 #include "locales.h"
41 /* Uncomment the following line in the production version. */
42 /* #define NDEBUG 1 */
43 #include <assert.h>
45 /* Define the lookup function. */
46 #include "locfile-kw.h"
49 /* Some useful macros. */
50 #define MIN(a, b) (__extension__ ({ typeof (a) _a = (a); \
51 typeof (b) _b = (b); \
52 _a < _b ? _a : _b; }))
55 void *xmalloc (size_t __n);
56 char *xstrdup (const char *__str);
58 struct localedef_t *
59 locfile_read (const char *filename, struct charset_t *charset)
61 struct linereader *ldfile;
62 struct localedef_t *result;
63 int state;
64 enum token_t expected_tok = tok_none;
65 const char *expected_str = NULL;
66 enum token_t ctype_tok_sym = tok_none;
67 const char *ctype_tok_str = NULL;
68 int copy_category = 0;
69 int cnt;
71 /* Allocate space for result. */
72 result = (struct localedef_t *) xmalloc (sizeof (struct localedef_t));
73 memset (result, '\0', sizeof (struct localedef_t));
75 ldfile = lr_open (filename, locfile_hash);
76 if (ldfile == NULL)
78 if (filename[0] != '/')
80 char *i18npath = __secure_getenv ("I18NPATH");
81 if (i18npath != NULL && *i18npath != '\0')
83 char path[strlen (filename) + 1 + strlen (i18npath) + 1];
84 char *next;
85 i18npath = strdupa (i18npath);
88 while (ldfile == NULL
89 && (next = strsep (&i18npath, ":")) != NULL)
91 stpcpy (stpcpy (stpcpy (path, next), "/"), filename);
93 ldfile = lr_open (path, locfile_hash);
97 /* Test in the default directory. */
98 if (ldfile == NULL)
100 char path[strlen (filename) + 1 + sizeof (LOCSRCDIR)];
102 stpcpy (stpcpy (stpcpy (path, LOCSRCDIR), "/"), filename);
103 ldfile = lr_open (path, locfile_hash);
107 if (ldfile == NULL)
109 result->failed = 1;
110 return result;
114 #define HANDLE_COPY(category, token, string) \
115 if (nowtok == tok_copy) \
117 copy_category = category; \
118 expected_tok = token; \
119 expected_str = string; \
120 state = 8; \
121 continue; \
123 ++state
125 #define LOCALE_PROLOG(token, string) \
126 if (nowtok == tok_eol) \
127 /* Ignore empty lines. */ \
128 continue; \
129 if (nowtok == tok_end) \
131 expected_tok = token; \
132 expected_str = string; \
133 state = 4; \
134 continue; \
136 if (nowtok == tok_copy) \
137 goto only_copy;
140 #define READ_STRING(fn, errlabel) \
141 do \
143 arg = lr_token (ldfile, charset); \
144 if (arg->tok != tok_string) \
145 goto errlabel; \
146 fn (ldfile, result, nowtok, arg, charset); \
147 lr_ignore_rest (ldfile, 1); \
149 while (0)
151 #define READ_STRING_LIST(fn, errlabel) \
152 do \
154 arg = lr_token (ldfile, charset); \
155 while (arg->tok == tok_string) \
157 fn (ldfile, result, nowtok, arg, charset); \
158 arg = lr_token (ldfile, charset); \
159 if (arg->tok != tok_semicolon) \
160 break; \
161 arg = lr_token (ldfile, charset); \
163 if (arg->tok != tok_eol) \
164 goto errlabel; \
166 while (0)
168 #define READ_NUMBER(fn, errlabel) \
169 do \
171 arg = lr_token (ldfile, charset); \
172 if (arg->tok != tok_minus1 && arg->tok != tok_number) \
173 goto errlabel; \
174 fn (ldfile, result, nowtok, arg, charset); \
175 lr_ignore_rest (ldfile, 1); \
177 while (0)
179 #define READ_NUMBER_LIST(fn, errlabel) \
180 do \
182 arg = lr_token (ldfile, charset); \
183 while (arg->tok == tok_minus1 || arg->tok == tok_number) \
185 fn (ldfile, result, nowtok, arg, charset); \
186 arg = lr_token (ldfile, charset); \
187 if (arg->tok != tok_semicolon) \
188 break; \
189 arg = lr_token (ldfile, charset); \
191 if (arg->tok != tok_eol) \
192 goto errlabel; \
194 while (0)
196 #define SYNTAX_ERROR(string) \
197 lr_error (ldfile, string); \
198 lr_ignore_rest (ldfile, 0);
201 /* Parse locale definition file and store result in RESULT. */
202 state = 1;
203 while (1)
205 /* What's on? */
206 struct token *now = lr_token (ldfile, charset);
207 enum token_t nowtok = now->tok;
208 struct token *arg;
210 if (nowtok == tok_eof)
211 break;
213 switch (state)
215 case 1:
216 /* The beginning. We expect the special declarations, EOL or
217 the start of any locale. */
218 if (nowtok == tok_eol)
219 /* Ignore empty lines. */
220 continue;
222 switch (nowtok)
224 case tok_escape_char:
225 case tok_comment_char:
226 /* We need an argument. */
227 arg = lr_token (ldfile, charset);
229 if (arg->tok != tok_ident)
231 SYNTAX_ERROR (_("bad argument"));
232 continue;
235 if (arg->val.str.len != 1)
237 lr_error (ldfile, _("\
238 argument to `%s' must be a single character"),
239 nowtok == tok_escape_char ? "escape_char"
240 : "comment_char");
242 lr_ignore_rest (ldfile, 0);
243 continue;
246 if (nowtok == tok_escape_char)
247 ldfile->escape_char = *arg->val.str.start;
248 else
249 ldfile->comment_char = *arg->val.str.start;
250 break;
252 case tok_lc_ctype:
253 state = 2;
254 break;
256 case tok_lc_collate:
257 state = 10;
258 break;
260 case tok_lc_monetary:
261 state = 20;
262 break;
264 case tok_lc_numeric:
265 state = 30;
266 break;
268 case tok_lc_time:
269 state = 40;
270 break;
272 case tok_lc_messages:
273 state = 50;
274 break;
276 default:
277 SYNTAX_ERROR (_("\
278 syntax error: not inside a locale definition section"));
279 continue;
281 lr_ignore_rest (ldfile, 1);
282 continue;
284 case 2:
285 HANDLE_COPY (LC_CTYPE, tok_lc_ctype, "LC_CYTPE");
287 ctype_startup (ldfile, result, charset);
288 /* FALLTHROUGH */
290 case 3:
291 /* Here we accept all the character classes, tolower/toupper,
292 and following ANSI C:1995 self-defined classes. */
293 LOCALE_PROLOG (tok_lc_ctype, "LC_CTYPE");
295 if (nowtok == tok_charclass)
297 READ_STRING_LIST (ctype_class_new, bad_new_charclass);
298 continue;
299 bad_new_charclass:
300 SYNTAX_ERROR (_("\
301 syntax error in definition of new character class"));
302 continue;
305 if (nowtok == tok_charconv)
307 READ_STRING_LIST (ctype_map_new, bad_new_charconv);
308 continue;
309 bad_new_charconv:
310 SYNTAX_ERROR (_("\
311 syntax error in definition of new character map"));
312 continue;
315 if (nowtok == tok_upper || nowtok == tok_lower
316 || nowtok == tok_alpha || nowtok == tok_digit
317 || nowtok == tok_alnum || nowtok == tok_space
318 || nowtok == tok_cntrl || nowtok == tok_punct
319 || nowtok == tok_graph || nowtok == tok_print
320 || nowtok == tok_xdigit || nowtok == tok_blank)
322 ctype_tok_sym = nowtok;
323 ctype_tok_str = NULL;
324 state = 5;
325 continue;
328 if (nowtok == tok_toupper|| nowtok == tok_tolower)
330 ctype_tok_sym = nowtok;
331 ctype_tok_str = NULL;
332 state = 6;
333 continue;
336 if (nowtok != tok_ident)
337 goto bad_charclass;
339 /* We possibly have a self-defined character class. */
340 if (ctype_is_charclass (ldfile, result, now->val.str.start))
342 ctype_tok_sym = nowtok;
343 ctype_tok_str = now->val.str.start;
344 state = 5;
345 continue;
348 /* ...or a self-defined character map. */
349 if (ctype_is_charconv (ldfile, result, now->val.str.start))
351 ctype_tok_sym = nowtok;
352 ctype_tok_str = now->val.str.start;
353 state = 6;
354 continue;
357 SYNTAX_ERROR (_("syntax error in definition of LC_CTYPE category"));
358 continue;
360 case 4:
361 /* Handle `END xxx'. */
362 if (nowtok != expected_tok)
363 lr_error (ldfile, _("\
364 `%1$s' definition does not end with `END %1$s'"), expected_str);
366 lr_ignore_rest (ldfile, nowtok == expected_tok);
367 state = 1;
368 continue;
370 case 5:
371 /* Here we expect a semicolon separated list of bsymbols. The
372 bit to be set in the word is given in CHARCLASS_BIT. */
373 arg = now;
375 ctype_class_start (ldfile, result, ctype_tok_sym, ctype_tok_str,
376 charset);
378 while (arg->tok != tok_eol)
380 /* Any token other than a bsymbol is an error. */
381 if (arg->tok != tok_bsymbol)
383 bad_charclass:
384 SYNTAX_ERROR (_("\
385 syntax error in character class definition"));
386 break;
389 /* Lookup value for token and write into array. */
390 ctype_class_from (ldfile, result, arg, charset);
392 arg = lr_token (ldfile, charset);
393 if (arg->tok == tok_semicolon)
394 arg = lr_token (ldfile, charset);
395 else if (arg->tok != tok_eol)
396 goto bad_charclass;
398 /* Look for ellipsis. */
399 if (arg->tok == tok_ellipsis)
401 arg = lr_token (ldfile, charset);
402 if (arg->tok != tok_semicolon)
403 goto bad_charclass;
405 arg = lr_token (ldfile, charset);
406 if (arg->tok != tok_bsymbol)
407 goto bad_charclass;
409 /* Write range starting at LAST to ARG->VAL. */
410 ctype_class_to (ldfile, result, arg, charset);
412 arg = lr_token (ldfile, charset);
413 if (arg->tok == tok_semicolon)
414 arg = lr_token (ldfile, charset);
415 else if (arg->tok != tok_eol)
416 goto bad_charclass;
420 /* Mark class as already seen. */
421 ctype_class_end (ldfile, result);
422 state = 3;
424 continue;
426 case 6:
427 /* Here we expect a list of character mappings. Note: the
428 first opening brace is already matched. */
429 ctype_map_start (ldfile, result, ctype_tok_sym, ctype_tok_str,
430 charset);
432 while (1)
434 /* Match ( bsymbol , bsymbol ) */
435 if (now->tok != tok_open_brace)
436 goto bad_charconv;
438 now = lr_token (ldfile, charset);
439 if (now->tok != tok_bsymbol)
441 bad_charconv:
442 SYNTAX_ERROR (_("\
443 syntax error in character conversion definition"));
444 state = 3;
445 break;
448 /* Lookup arg and assign to FROM. */
449 ctype_map_from (ldfile, result, now, charset);
451 now = lr_token (ldfile, charset);
452 if (now->tok != tok_comma)
453 goto bad_charconv;
455 now = lr_token (ldfile, charset);
456 if (now->tok != tok_bsymbol)
457 goto bad_charconv;
459 /* Lookup arg and assign to TO. */
460 ctype_map_to (ldfile, result, now, charset);
462 now = lr_token (ldfile, charset);
463 if (now->tok != tok_close_brace)
464 goto bad_charconv;
466 now = lr_token (ldfile, charset);
467 if (now->tok == tok_eol)
469 state = 3;
470 break;
472 if (now->tok != tok_semicolon)
473 goto bad_charconv;
475 now = lr_token (ldfile, charset);
478 ctype_map_end (ldfile, result);
479 continue;
481 case 8:
483 /* We have seen `copy'. First match the argument. */
484 int warned = 0;
486 if (nowtok != tok_string)
487 lr_error (ldfile, _("expect string argument for `copy'"));
488 else
489 def_to_process (now->val.str.start, 1 << copy_category);
491 lr_ignore_rest (ldfile, nowtok == tok_string);
493 /* The rest of the line must be empty
494 and the next keyword must be `END xxx'. */
496 while (lr_token (ldfile, charset)->tok != tok_end)
498 if (warned == 0)
500 only_copy:
501 lr_error (ldfile, _("\
502 no other keyword shall be specified when `copy' is used"));
503 warned = 1;
506 lr_ignore_rest (ldfile, 0);
509 state = 4;
511 continue;
513 case 10:
514 HANDLE_COPY (LC_COLLATE, tok_lc_collate, "LC_COLLATE");
516 collate_startup (ldfile, result, charset);
517 /* FALLTHROUGH */
519 case 11:
520 /* Process the LC_COLLATE section. We expect `END LC_COLLATE'
521 any of the collation specifications, or any bsymbol. */
522 LOCALE_PROLOG (tok_lc_collate, "LC_COLLATE");
524 if (nowtok == tok_order_start)
526 state = 12;
527 continue;
530 if (nowtok != tok_collating_element
531 && nowtok != tok_collating_symbol)
533 bad_collation:
534 lr_error (ldfile, _("\
535 syntax error in collation definition"));
536 lr_ignore_rest (ldfile, 0);
537 continue;
540 /* Get argument. */
541 arg = lr_token (ldfile, charset);
542 if (arg->tok != tok_bsymbol)
544 lr_error (ldfile, _("\
545 collation symbol expected after `%s'"),
546 nowtok == tok_collating_element
547 ? "collating-element" : "collating-symbol");
548 lr_ignore_rest (ldfile, 0);
549 continue;
552 if (nowtok == tok_collating_element)
554 /* Save to-value as new name. */
555 collate_element_to (ldfile, result, arg, charset);
557 arg = lr_token (ldfile, charset);
558 if (arg->tok != tok_from)
560 lr_error (ldfile, _("\
561 `from' expected after first argument to `collating-element'"));
562 lr_ignore_rest (ldfile, 0);
563 continue;
566 arg = lr_token (ldfile, charset);
567 if (arg->tok != tok_string)
569 lr_error (ldfile, _("\
570 from-value of `collating-element' must be a string"));
571 lr_ignore_rest (ldfile, 0);
572 continue;
575 /* Enter new collating element. */
576 collate_element_from (ldfile, result, arg, charset);
578 else
579 /* Enter new collating symbol into table. */
580 collate_symbol (ldfile, result, arg, charset);
582 lr_ignore_rest (ldfile, 1);
583 continue;
585 case 12:
586 /* We parse the rest of the line containing `order_start'.
587 In any case we continue with parsing the symbols. */
588 state = 13;
590 cnt = 0;
591 while (now->tok != tok_eol)
593 int collation_method = 0;
595 ++cnt;
599 if (now->tok == tok_forward)
600 collation_method |= sort_forward;
601 else if (now->tok == tok_backward)
602 collation_method |= sort_backward;
603 else if (now->tok == tok_position)
604 collation_method |= sort_position;
605 else
607 lr_error (ldfile, _("unknown collation directive"));
608 lr_ignore_rest (ldfile, 0);
609 continue;
612 now = lr_token (ldfile, charset);
614 while (now->tok == tok_comma
615 && ((now = lr_token (ldfile, charset)) != tok_none));
617 /* Check for consistency: forward and backwards are
618 mutually exclusive. */
619 if ((collation_method & sort_forward) != 0
620 && (collation_method & sort_backward) != 0)
622 lr_error (ldfile, _("\
623 sorting order `forward' and `backward' are mutually exclusive"));
624 /* The recover clear the backward flag. */
625 collation_method &= ~sort_backward;
628 /* ??? I don't know whether this is correct but while
629 thinking about the `strcoll' functions I found that I
630 need a direction when performing position depended
631 collation. So I assume here that implicitly the
632 direction `forward' is given when `position' alone is
633 written. --drepper */
634 if (collation_method == sort_position)
635 collation_method |= sort_forward;
637 /* Enter info about next collation order. */
638 collate_new_order (ldfile, result, collation_method);
640 if (now->tok != tok_eol && now->tok != tok_semicolon)
642 lr_error (ldfile, _("\
643 syntax error in `order_start' directive"));
644 lr_ignore_rest (ldfile, 0);
645 break;
648 if (now->tok == tok_semicolon)
649 now = lr_token (ldfile, charset);
652 /* If no argument to `order_start' is given, one `forward'
653 argument is implicitly assumed. */
654 if (cnt == 0)
655 collate_new_order (ldfile, result, sort_forward);
658 /* We now know about all sorting rules. */
659 collate_build_arrays (ldfile, result);
661 continue;
663 case 13:
664 /* We read one symbol a line until `order_end' is found. */
666 static int last_correct = 1;
668 if (nowtok == tok_order_end)
670 state = 14;
671 lr_ignore_rest (ldfile, 1);
672 continue;
675 /* Ignore empty lines. */
676 if (nowtok == tok_eol)
677 continue;
679 if (nowtok != tok_bsymbol && nowtok != tok_undefined
680 && nowtok != tok_ellipsis)
682 if (last_correct == 1)
684 lr_error (ldfile, _("\
685 syntax error in collating order definition"));
686 last_correct = 0;
688 lr_ignore_rest (ldfile, 0);
689 continue;
691 else
693 last_correct = 1;
695 /* Remember current token. */
696 if (collate_order_elem (ldfile, result, now, charset) < 0)
697 continue;
700 /* Read optional arguments. */
701 arg = lr_token (ldfile, charset);
702 while (arg->tok != tok_eol)
704 if (arg->tok != tok_ignore && arg->tok != tok_ellipsis
705 && arg->tok != tok_bsymbol && arg->tok != tok_string)
706 break;
708 if (arg->tok == tok_ignore || arg->tok == tok_ellipsis
709 || arg->tok == tok_string)
711 /* Call handler for simple weights. */
712 if (collate_simple_weight (ldfile, result, arg, charset)
713 < 0)
714 goto illegal_weight;
716 arg = lr_token (ldfile, charset);
718 else
721 /* Collect char. */
722 int ok = collate_weight_bsymbol (ldfile, result, arg,
723 charset);
724 if (ok < 0)
725 goto illegal_weight;
727 arg = lr_token (ldfile, charset);
729 while (arg->tok == tok_bsymbol);
731 /* Are there more weights? */
732 if (arg->tok != tok_semicolon)
733 break;
735 /* Yes, prepare next weight. */
736 if (collate_next_weight (ldfile, result) < 0)
737 goto illegal_weight;
739 arg = lr_token (ldfile, charset);
742 if (arg->tok != tok_eol)
744 SYNTAX_ERROR (_("syntax error in order specification"));
747 collate_end_weight (ldfile, result);
748 illegal_weight:
750 continue;
752 case 14:
753 /* Following to the `order_end' keyword we don't expect
754 anything but the `END'. */
755 if (nowtok == tok_eol)
756 continue;
758 if (nowtok != tok_end)
759 goto bad_collation;
761 expected_tok = tok_lc_collate;
762 expected_str = "LC_COLLATE";
763 state = 4;
765 ldfile->translate_strings = 1;
766 continue;
768 case 20:
769 HANDLE_COPY (LC_MONETARY, tok_lc_monetary, "LC_MONETARY");
771 monetary_startup (ldfile, result, charset);
772 /* FALLTHROUGH */
774 case 21:
775 LOCALE_PROLOG (tok_lc_monetary, "LC_MONETARY");
777 switch (nowtok)
779 case tok_int_curr_symbol:
780 case tok_currency_symbol:
781 case tok_mon_decimal_point:
782 case tok_mon_thousands_sep:
783 case tok_positive_sign:
784 case tok_negative_sign:
785 READ_STRING (monetary_add, bad_monetary);
786 break;
788 case tok_int_frac_digits:
789 case tok_frac_digits:
790 case tok_p_cs_precedes:
791 case tok_p_sep_by_space:
792 case tok_n_cs_precedes:
793 case tok_n_sep_by_space:
794 case tok_p_sign_posn:
795 case tok_n_sign_posn:
796 READ_NUMBER (monetary_add, bad_monetary);
797 break;
799 case tok_mon_grouping:
800 /* We have a semicolon separated list of integers. */
801 READ_NUMBER_LIST (monetary_add, bad_monetary);
802 break;
804 default:
805 bad_monetary:
806 SYNTAX_ERROR (_("syntax error in monetary locale definition"));
808 continue;
810 case 30:
811 HANDLE_COPY (LC_NUMERIC, tok_lc_numeric, "LC_NUMERIC");
813 numeric_startup (ldfile, result, charset);
814 /* FALLTHROUGH */
816 case 31:
817 LOCALE_PROLOG (tok_lc_numeric, "LC_NUMERIC");
819 switch (nowtok)
821 case tok_decimal_point:
822 case tok_thousands_sep:
823 READ_STRING (numeric_add, bad_numeric);
824 break;
826 case tok_grouping:
827 /* We have a semicolon separated list of integers. */
828 READ_NUMBER_LIST (numeric_add, bad_numeric);
829 break;
831 default:
832 bad_numeric:
833 SYNTAX_ERROR (_("syntax error in numeric locale definition"));
835 continue;
837 case 40:
838 HANDLE_COPY (LC_TIME, tok_lc_time, "LC_TIME");
840 time_startup (ldfile, result, charset);
841 /* FALLTHROUGH */
843 case 41:
844 LOCALE_PROLOG (tok_lc_time, "LC_TIME");
846 switch (nowtok)
848 case tok_abday:
849 case tok_day:
850 case tok_abmon:
851 case tok_mon:
852 case tok_am_pm:
853 case tok_alt_digits:
854 case tok_era:
855 READ_STRING_LIST (time_add, bad_time);
856 continue;
858 case tok_d_t_fmt:
859 case tok_d_fmt:
860 case tok_t_fmt:
861 case tok_t_fmt_ampm:
862 case tok_era_year:
863 case tok_era_d_t_fmt:
864 case tok_era_d_fmt:
865 case tok_era_t_fmt:
866 READ_STRING (time_add, bad_time);
867 break;
869 default:
870 bad_time:
871 SYNTAX_ERROR (_("syntax error in time locale definition"));
873 continue;
875 case 50:
876 HANDLE_COPY (LC_MESSAGES, tok_lc_messages, "LC_MESSAGES");
878 messages_startup (ldfile, result, charset);
879 /* FALLTHROUGH */
881 case 51:
882 LOCALE_PROLOG (tok_lc_messages, "LC_MESSAGES");
884 switch (nowtok)
886 case tok_yesexpr:
887 case tok_noexpr:
888 case tok_yesstr:
889 case tok_nostr:
890 READ_STRING (messages_add, bad_message);
891 break;
893 default:
894 bad_message:
895 SYNTAX_ERROR (_("syntax error in message locale definition"));
897 continue;
899 default:
900 error (5, 0, _("%s: error in state machine"), __FILE__);
901 /* NOTREACHED */
904 break;
907 /* We read all of the file. */
908 lr_close (ldfile);
910 /* Let's see what information is available. */
911 for (cnt = LC_CTYPE; cnt <= LC_MESSAGES; ++cnt)
912 if (result->categories[cnt].generic != NULL)
913 result->avail |= 1 << cnt;
915 return result;
919 void
920 check_all_categories (struct localedef_t *locale, struct charset_t *charset)
922 /* Call the finishing functions for all locales. */
923 if ((locale->avail & (1 << LC_CTYPE)) != 0
924 && (locale->binary & (1 << LC_CTYPE)) == 0)
925 ctype_finish (locale, charset);
926 if ((locale->avail & (1 << LC_COLLATE)) != 0
927 && (locale->binary & (1 << LC_COLLATE)) == 0)
928 collate_finish (locale, charset);
929 if ((locale->avail & (1 << LC_MONETARY)) != 0
930 && (locale->binary & (1 << LC_MONETARY)) == 0)
931 monetary_finish (locale);
932 if ((locale->avail & (1 << LC_NUMERIC)) != 0
933 && (locale->binary & (1 << LC_NUMERIC)) == 0)
934 numeric_finish (locale);
935 if ((locale->avail & (1 << LC_TIME)) != 0
936 && (locale->binary & (1 << LC_TIME)) == 0)
937 time_finish (locale);
938 if ((locale->avail & (1 << LC_MESSAGES)) != 0
939 && (locale->binary & (1 << LC_MESSAGES)) == 0)
940 messages_finish (locale);
944 void
945 write_all_categories (struct localedef_t *locale, struct charset_t *charset,
946 const char *output_path)
948 /* Call all functions to write locale data. */
949 if ((locale->avail & (1 << LC_CTYPE)) != 0)
950 ctype_output (locale, charset, output_path);
951 if ((locale->avail & (1 << LC_COLLATE)) != 0)
952 collate_output (locale, charset, output_path);
953 if ((locale->avail & (1 << LC_MONETARY)) != 0)
954 monetary_output (locale, output_path);
955 if ((locale->avail & (1 << LC_NUMERIC)) != 0)
956 numeric_output (locale, output_path);
957 if ((locale->avail & (1 << LC_TIME)) != 0)
958 time_output (locale, output_path);
959 if ((locale->avail & (1 << LC_MESSAGES)) != 0)
960 messages_output (locale, output_path);
964 void
965 write_locale_data (const char *output_path, const char *category,
966 size_t n_elem, struct iovec *vec)
968 size_t cnt, step, maxiov;
969 int fd;
970 char *fname;
972 fname = malloc (strlen (output_path) + 2 * strlen (category) + 6);
973 if (fname == NULL)
974 error (5, errno, _("memory exhausted"));
976 /* Normally we write to the directory pointed to by the OUTPUT_PATH.
977 But for LC_MESSAGES we have to take care for the translation
978 data. This means we need to have a directory LC_MESSAGES in
979 which we place the file under the name SYS_LC_MESSAGES. */
980 sprintf (fname, "%s%s", output_path, category);
981 if (strcmp (category, "LC_MESSAGES") == 0)
983 struct stat st;
985 if (stat (fname, &st) < 0)
987 if (mkdir (fname, 0777) < 0)
988 fd = creat (fname, 0666);
989 else
991 fd = -1;
992 errno = EISDIR;
995 else if (S_ISREG (st.st_mode))
996 fd = creat (fname, 0666);
997 else
999 fd = -1;
1000 errno = EISDIR;
1003 else
1004 fd = creat (fname, 0666);
1006 if (fd == -1)
1008 int save_err = errno;
1010 if (errno == EISDIR)
1012 sprintf (fname, "%1$s%2$s/SYS_%2$s", output_path, category);
1013 fd = creat (fname, 0666);
1014 if (fd == -1)
1015 save_err = errno;
1018 if (fd == -1 && !be_quiet)
1020 error (0, save_err, _("\
1021 cannot open output file `%s' for category `%s'"),
1022 fname, category);
1023 return;
1026 free (fname);
1028 #ifdef UIO_MAXIOV
1029 maxiov = UIO_MAXIOV;
1030 #else
1031 maxiov = sysconf (_SC_UIO_MAXIOV);
1032 #endif
1034 /* Write the data using writev. But we must take care for the
1035 limitation of the implementation. */
1036 for (cnt = 0; cnt < n_elem; cnt += step)
1038 step = n_elem - cnt;
1039 if (maxiov > 0)
1040 step = MIN (maxiov, step);
1042 if (writev (fd, &vec[cnt], step) < 0 && !be_quiet)
1044 error (0, errno, _("failure while writing data for category `%s'"),
1045 category);
1046 break;
1050 close (fd);