1 /* Copyright (C) 1995 Free Software Foundation, Inc.
3 The GNU C Library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Library General Public License as
5 published by the Free Software Foundation; either version 2 of the
6 License, or (at your option) any later version.
8 The GNU C Library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public
14 License along with the GNU C Library; see the file COPYING.LIB. If
15 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
16 Cambridge, MA 02139, USA. */
33 #include "localedef.h"
34 #include "localeinfo.h"
37 /* We don't have these constants defined because we don't use them. Give
39 #define CTYPE_MB_CUR_MIN 0
40 #define CTYPE_MB_CUR_MAX 0
41 #define CTYPE_HASH_SIZE 0
42 #define CTYPE_HASH_LAYERS 0
44 #define CTYPE_TOUPPER_EB 0
45 #define CTYPE_TOLOWER_EB 0
46 #define CTYPE_TOUPPER_EL 0
47 #define CTYPE_TOLOWER_EL 0
50 /* We have all categories defined in `categories.def'. Now construct
51 the description and data structure used for all categories. */
52 #define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
53 struct cat_item category##_desc[] = \
58 char *category##_values[NELEMS (category##_desc) - 1] = { NULL, };
59 #include "categories.def"
60 #undef DEFINE_CATEGORY
62 struct category category
[] =
64 #define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
65 [category] = { _NL_NUM_##category, name, NELEMS (category##_desc) - 1, \
66 category##_desc, category##_values, in, check, out },
67 #include "categories.def"
68 #undef DEFINE_CATEGORY
70 #define NCATEGORIES NELEMS (category)
73 #define SYNTAX_ERROR \
74 error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
75 locfile_data.filename, locfile_data.line_no)
78 /* Prototypes for local functions. */
79 static int get_byte (char *byte_ptr
);
80 static char *is_locale_name (int cat_no
, const char *str
, int len
);
83 /* Read a locale definition file FILE. The format is defined in
86 locfile_read (const char *fname
)
88 /* Pointer to text of last token. */
90 /* Length of last token (or if NUMBER the value itself). */
92 /* The last returned token. */
94 /* For error correction we remember whether the last token was correct. */
95 int correct_token
= 1;
97 /* Open the desired input file on stdin. */
100 while ((token
= locfile_lex (&ptr
, &len
)) != 0)
104 for (cat_no
= 0; cat_no
< NCATEGORIES
; ++cat_no
)
105 if (token
== category
[cat_no
].cat_id
)
108 if (cat_no
>= NCATEGORIES
)
109 /* A syntax error occured. No valid category defintion starts. */
111 if (correct_token
!= 0)
112 error (0, 0, gettext ("%s:%Zd: locale category start expected"),
113 locfile_data
.filename
, locfile_data
.line_no
);
115 /* To prevent following errors mark as error case. */
118 /* Synchronization point is the beginning of a new category.
119 Overread all line upto this silently. */
120 ignore_to_eol (0, 0);
124 /* Rest of the line should be empty. */
125 ignore_to_eol (0, 1);
127 /* Perhaps these category is already specified. We simply give a
128 warning and overwrite the values. */
129 if (category
[cat_no
].filled
!= 0)
130 error (0, 0, gettext ("%s:%Zd: multiple definition of locale "
131 "category %s"), locfile_data
.filename
,
132 locfile_data
.line_no
, category
[cat_no
].name
);
134 /* We read the first token because this could be the copy statement. */
135 token
= xlocfile_lex (&ptr
, &len
);
137 if (token
== TOK_COPY
)
138 /* Copying the definitions from an existing locale is requested. */
142 /* Get the name of the locale to copy from. */
143 token
= xlocfile_lex (&ptr
, &len
);
144 if (token
!= TOK_IDENT
&& token
!= TOK_STRING
)
145 /* No name, then mark error and ignore everything upto next
146 start of an category section. */
148 /* To prevent following errors mark as error case. */
151 /* Synchronization point is the beginning of a new category.
152 Overread all line upto this silently. */
153 ignore_to_eol (0, 0);
155 else if ((str
= is_locale_name (cat_no
, ptr
, len
)) != NULL
)
156 /* Yes the name really names an existing locale file. We are
157 returned the complete file name. Store it so that we can
158 copy it in the output phase. */
160 category
[cat_no
].copy_locale
= str
;
161 category
[cat_no
].filled
= 1;
163 ignore_to_eol (0, 1);
166 /* No, the name does not address a valid locale file. Mark
167 error case and ignore rest of category. */
170 memcpy (tmp
, ptr
, len
);
172 error (0, 0, gettext ("%s:%Zd: invalid locale `%s' in copy "
173 "statement"), locfile_data
.filename
,
174 locfile_data
.line_no
, tmp
);
176 ignore_to_eol (0, 0);
179 /* This should END as the next token. */
180 token
= xlocfile_lex (&ptr
, &len
);
182 if (token
== TOK_END
)
183 /* This is the end of the category. */
185 token
= xlocfile_lex (&ptr
, &len
);
187 if (token
!= category
[cat_no
].cat_id
)
188 /* Wrong category name after END. */
190 error (0, 0, gettext ("%s:%Zd: category `%s' does not "
191 "end with `END %s'"),
192 locfile_data
.filename
, locfile_data
.line_no
,
193 category
[cat_no
].name
, category
[cat_no
].name
);
194 ignore_to_eol (0, 0);
197 ignore_to_eol (0, 1);
202 /* No END following copy. Give error while not in error case. */
204 if (correct_token
!= 0)
205 error (0, 0, gettext ("%s:%Zd: `copy' must be sole rule"),
206 locfile_data
.filename
, locfile_data
.line_no
);
208 ignore_to_eol (0, 0);
214 /* Now it's time to mark as mentioned in the locale file. */
215 category
[cat_no
].filled
= 1;
217 if (category
[cat_no
].infct
!= NULL
)
218 /* The category needs a special input handling. */
220 category
[cat_no
].infct(token
);
224 /* Now process the given items. */
229 if (token
== TOK_END
)
230 /* This is the end of the category. */
232 token
= xlocfile_lex (&ptr
, &len
);
234 if (token
!= category
[cat_no
].cat_id
)
236 error (0, 0, gettext ("%s:%Zd: category `%s' does not end "
238 locfile_data
.filename
, locfile_data
.line_no
,
239 category
[cat_no
].name
, category
[cat_no
].name
);
240 ignore_to_eol (0, 0);
243 ignore_to_eol (0, 1);
245 /* Start next category. */
249 /* All other lines should describe valid items of the category. */
250 for (item_no
= 0; item_no
< category
[cat_no
].number
; ++item_no
)
251 if (category
[cat_no
].item_desc
[item_no
].item_id
== token
)
254 if (item_no
>= category
[cat_no
].number
)
255 /* This is not a valid item of the category. */
258 ignore_to_eol (0, 0);
260 token
= xlocfile_lex (&ptr
, &len
);
262 /* And process next item. */
266 /* Test whether already a value is defined. */
267 if (category
[cat_no
].item_value
[item_no
] != NULL
)
268 error (0, 0, gettext ("%s:%Zd: category item `%s' already "
270 locfile_data
.filename
, locfile_data
.line_no
,
271 category
[cat_no
].item_desc
[item_no
].name
);
273 switch (category
[cat_no
].item_desc
[item_no
].value_type
)
276 /* Get next token. This is the argument to the item. */
277 token
= xlocfile_lex (&ptr
, &len
);
279 if (token
!= TOK_STRING
)
282 category
[cat_no
].item_value
[item_no
] = strdup (ptr
);
283 ignore_to_eol (0, ptr
!= NULL
);
286 /* This is a difficult case. The number of strings in
287 the array may vary. But for now its only necessary
288 with ALT_DIGITS from LC_TIME. This item is the last
289 so be can solve it by storing the number of string in
290 the first place and the string indeces following
295 if (category
[cat_no
].item_value
[item_no
] != NULL
)
296 buffer
= (char **) category
[cat_no
].item_value
[item_no
];
298 buffer
= (char **) xmalloc (
299 sizeof (char *) * category
[cat_no
].item_desc
[item_no
].max
);
301 category
[cat_no
].item_value
[item_no
] = (char *) buffer
;
303 /* As explained we may need a place to store the real number
305 if (category
[cat_no
].item_desc
[item_no
].min
306 != category
[cat_no
].item_desc
[item_no
].max
)
312 token
= xlocfile_lex (&ptr
, &len
);
313 if (token
!= TOK_STRING
)
319 if (cnt
>= category
[cat_no
].item_desc
[item_no
].max
)
321 error (0, 0, gettext ("%s:%Zd: too many elements "
323 locfile_data
.filename
, locfile_data
.line_no
,
324 category
[cat_no
].item_desc
[item_no
].name
);
328 buffer
[cnt
++] = strdup (ptr
);
330 token
= locfile_lex (&ptr
, &len
);
332 while (token
== TOK_CHAR
&& len
== ';');
334 ignore_to_eol (token
, ptr
!= NULL
);
336 if (cnt
< category
[cat_no
].item_desc
[item_no
].min
)
337 error (0, 0, gettext ("%s:%Zd: too few elements for item "
339 locfile_data
.filename
, locfile_data
.line_no
,
340 category
[cat_no
].item_desc
[item_no
].name
);
342 if (category
[cat_no
].item_desc
[item_no
].min
343 != category
[cat_no
].item_desc
[item_no
].max
)
344 *(int *) category
[cat_no
].item_value
[item_no
] = cnt
;
350 category
[cat_no
].item_value
[item_no
] = (char *) xmalloc (
352 ok
= get_byte (category
[cat_no
].item_value
[item_no
]);
353 ignore_to_eol (0, ok
);
364 buffer
= (char *) xmalloc ((maxsize
= 30));
367 while ((ok
= get_byte (&byte
)))
370 buffer
= (char *) xmalloc ((maxsize
*= 2));
372 buffer
[cnt
++] = byte
;
374 token
= locfile_lex (&ptr
, &len
);
375 if (token
!= TOK_CHAR
|| len
!= ';')
380 category
[cat_no
].item_value
[item_no
] = buffer
;
381 ignore_to_eol (token
, ok
);
385 error (5, 0, gettext ("internal error in %s, line %u"),
386 __FUNCTION__
, __LINE__
);
390 /* Get next token. */
391 token
= xlocfile_lex (&ptr
, &len
);
397 /* Check given values for categories for consistency. */
399 categories_check (void)
403 for (cat_no
= 0; cat_no
< NCATEGORIES
; ++cat_no
)
404 if (category
[cat_no
].copy_locale
== NULL
)
405 if (category
[cat_no
].filled
!= 0)
406 if (category
[cat_no
].checkfct
)
407 category
[cat_no
].checkfct();
412 for (item_no
= 0; item_no
< category
[cat_no
].number
; ++item_no
)
413 if (category
[cat_no
].item_value
[item_no
] == NULL
)
417 /* If the item is defined in the standard is it an error to
418 have it not defined. */
419 errcode
= category
[cat_no
].item_desc
[item_no
].status
== std
422 error (errcode
, 0, gettext ("item `%s' of category `%s' "
424 category
[cat_no
].item_desc
[item_no
].name
,
425 category
[cat_no
].name
);
429 error (0, 0, gettext ("category `%s' not defined"),
430 category
[cat_no
].name
);
434 /* Write out the binary representation of the category data which can be
435 loaded by setlocale(1). */
437 categories_write (void)
445 struct obstack obstk
;
448 #define obstack_chunk_alloc xmalloc
449 #define obstack_chunk_free free
450 obstack_init (&obstk
);
452 for (cat_no
= 0; cat_no
< NCATEGORIES
; ++cat_no
)
456 if (category
[cat_no
].copy_locale
!= NULL
)
457 /* Simply copy the addressed locale file of the specified
458 category. Please note that this is tried before the distinction
459 between categories which need special handling is made. */
463 /* Open source file. */
464 source
= open (category
[cat_no
].copy_locale
, O_RDONLY
);
466 error (0, 0, gettext ("cannot copy locale definition file `%s'"),
467 category
[cat_no
].copy_locale
);
470 /* Construct file name of output file and open for writing. */
471 char path
[strlen (output_path
)
472 + strlen(category
[cat_no
].name
) + 1];
476 t
= stpcpy (path
, output_path
);
477 strcpy (t
, category
[cat_no
].name
);
479 dest
= creat (path
, 0666);
481 error (0, 0, gettext ("cannot open output file `%s': %m"),
488 /* Copy the files. */
491 size
= read (source
, buffer
, BUFSIZ
);
492 write (dest
, buffer
, size
);
499 puts (category
[cat_no
].name
);
508 if (category
[cat_no
].outfct
)
509 result
= category
[cat_no
].outfct();
515 int item_no
, len
, slen
, cnt
;
518 /* Count number of elements. */
519 for (item_no
= 0; item_no
< category
[cat_no
].number
; ++item_no
)
521 switch (category
[cat_no
].item_desc
[item_no
].value_type
)
529 elems
+= category
[cat_no
].item_desc
[item_no
].max
;
532 error (5, 0, gettext ("internal error in %s, line %u"),
533 __FUNCTION__
, __LINE__
);
538 /* We now have the number of elements. We build the structure
539 and a helper structure for writing all out. */
540 len
= sizeof (struct locale_file
) + elems
* sizeof (int);
541 data
= obstack_alloc (&obstk
, len
);
542 iov
= obstack_alloc (&obstk
, (elems
+ 1) * sizeof (struct iovec
));
544 data
->magic
= LIMAGIC (cat_no
);
546 iov
[0].iov_base
= data
;
547 iov
[0].iov_len
= len
;
550 for (item_no
= 0; item_no
< category
[cat_no
].number
; ++item_no
)
551 if (category
[cat_no
].item_value
[item_no
] == NULL
)
553 switch (category
[cat_no
].item_desc
[item_no
].value_type
)
558 data
->idx
[cnt
] = len
;
559 ++len
; /* We reserve one single byte for this entry. */
560 iov
[1 + cnt
].iov_base
= (char *) "";
561 iov
[1 + cnt
].iov_len
= 1;
569 max
= category
[cat_no
].item_desc
[item_no
].max
;
571 for (nstr
= 0; nstr
< max
; ++nstr
)
573 data
->idx
[cnt
] = len
;
575 iov
[1 + cnt
].iov_base
= (char *) "";
576 iov
[1 + cnt
].iov_len
= 1;
583 switch (category
[cat_no
].item_desc
[item_no
].value_type
)
587 data
->idx
[cnt
] = len
;
588 slen
= strlen (category
[cat_no
].item_value
[item_no
]) + 1;
590 iov
[1 + cnt
].iov_base
= category
[cat_no
].item_value
[item_no
];
591 iov
[1 + cnt
].iov_len
= slen
;
595 data
->idx
[cnt
] = len
;
598 iov
[1 + cnt
].iov_base
= category
[cat_no
].item_value
[item_no
];
599 iov
[1 + cnt
].iov_len
= slen
;
607 if (category
[cat_no
].item_desc
[item_no
].min
608 == category
[cat_no
].item_desc
[item_no
].max
)
610 nstr
= category
[cat_no
].item_desc
[item_no
].min
;
611 first
= (char **) category
[cat_no
].item_value
[item_no
];
615 nstr
= *(int *) category
[cat_no
].item_value
[item_no
];
617 ((char **) category
[cat_no
].item_value
[item_no
]) + 1;
622 data
->idx
[cnt
] = len
;
625 slen
= strlen (*first
) + 1;
626 iov
[1 + cnt
].iov_base
= *first
;
631 iov
[1 + cnt
].iov_base
= (char *) "";
634 iov
[1 + cnt
].iov_len
= slen
;
639 while (nact
< category
[cat_no
].item_desc
[item_no
].max
)
641 data
->idx
[cnt
] = len
;
643 iov
[1 + cnt
].iov_base
= (char *) "";
644 iov
[1 + cnt
].iov_len
= 1;
654 assert (cnt
<= elems
);
656 /* Construct the output filename from the argument given to
657 localedef on the command line. */
658 path
= (char *) obstack_alloc (&obstk
, strlen (output_path
) +
659 2 * strlen (category
[cat_no
].name
) + 5);
660 t
= stpcpy (path
, output_path
);
661 strcpy (t
, category
[cat_no
].name
);
663 fd
= creat (path
, 0666);
667 /* Check whether it failed because the named file is a directory.
668 In that case we use the file .../LC_xxx/SYS_LC_xxx, as the
669 loading functions of the C Library do. */
672 if (stat (path
, &st
) == 0 && S_ISDIR (st
.st_mode
))
674 stpcpy (stpcpy (strchr (path
, '\0'), "/SYS_"),
675 category
[cat_no
].name
);
676 fd
= creat (path
, 0666);
682 error (0, 0, gettext ("cannot open output file `%s': %m"),
688 if (writev (fd
, iov
, cnt
+ 1) == -1)
690 error (0, 0, gettext ("cannot write output file `%s': %m"),
695 if (elems
==0) write(fd
, &elems
, 10);
699 /* The old data is not needed anymore, but keep the obstack
701 obstack_free (&obstk
, data
);
705 puts (category
[cat_no
].name
);
707 /* Now the whole obstack can be removed. */
708 obstack_free (&obstk
, NULL
);
712 /* Get the representation of a number. This is a positive integer or
713 the number -1 which is handled as a special symbol by the scanner. */
715 get_byte (char *byte_ptr
)
721 token
= locfile_lex (&ptr
, &len
);
722 if (token
!= TOK_NUMBER
&& token
!= TOK_MINUS1
)
723 /* None of the valid number format. */
725 error (0, 0, gettext ("%s:%Zd: number expected"),
726 locfile_data
.filename
, locfile_data
.line_no
);
731 if (token
== TOK_MINUS1
)
733 *byte_ptr
= CHAR_MAX
;
738 /* The value of the numbers has to be less than CHAR_MAX. This is
739 ok for the information they have to express. */
741 error (0, 0, gettext ("%s:%Zd: invalid number"),
742 locfile_data
.filename
, locfile_data
.line_no
);
752 /* Test whether the string STR with length LEN is the name of an existing
753 locale and whether a file for category CAT_NO is found in this directory.
754 This categories are looked for in the system locale definition file
756 Return the complete file name for the category file. */
758 is_locale_name (int cat_no
, const char *str
, int len
)
760 static char **locale_names
= NULL
;
761 static int max_count
= 0;
762 static int locale_count
= 0;
767 if (locale_names
== NULL
)
768 /* Read in the list of all available locales. */
771 struct dirent
*dirent
;
773 /* LOCALE_NAMES is not NULL anymore, but LOCALE_COUNT == 0. */
776 dir
= opendir (LOCALE_PATH
);
779 error (1, errno
, gettext ("cannot read locale directory `%s'"),
785 /* Now we can look for all files in the directory. */
786 while ((dirent
= readdir (dir
)) != NULL
)
787 if (strcmp (dirent
->d_name
, ".") != 0
788 && strcmp (dirent
->d_name
, "..") != 0)
791 locale_names
= (char **) xmalloc ((max_count
= 10)
793 else if (locale_count
>= max_count
)
794 locale_names
= (char **) xrealloc (locale_names
,
797 locale_names
[locale_count
++] = strdup (dirent
->d_name
);
802 for (cnt
= 0; cnt
< locale_count
; ++cnt
)
803 if (strncmp (str
, locale_names
[cnt
], len
) == 0
804 && locale_names
[cnt
][len
] == '\0')
807 if (cnt
>= locale_count
)
810 /* Now search for this specific locale file. */
811 asprintf (&fname
, "%s/%s/%s", LOCALE_PATH
, locale_names
[cnt
],
812 category
[cat_no
].name
);
814 fd
= open (fname
, O_RDONLY
);
821 exist
= fstat (fd
, &st
);