(categories_write): Fix two bugs with handling string arrays. If writing a locale...
[glibc.git] / locale / locfile-parse.c
blob000374f2c556405cf1c4fc7f41580bf2b02f5874
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. */
18 #include <assert.h>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <langinfo.h>
22 #include <libintl.h>
23 #include <limits.h>
24 #include <obstack.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/uio.h>
32 #include "localedef.h"
33 #include "localeinfo.h"
34 #include "token.h"
36 /* We don't have these constants defined because we don't use them. Give
37 default values. */
38 #define CTYPE_MB_CUR_MIN 0
39 #define CTYPE_MB_CUR_MAX 0
40 #define CTYPE_HASH_SIZE 0
41 #define CTYPE_HASH_LAYERS 0
42 #define CTYPE_CLASS 0
43 #define CTYPE_TOUPPER_EB 0
44 #define CTYPE_TOLOWER_EB 0
45 #define CTYPE_TOUPPER_EL 0
46 #define CTYPE_TOLOWER_EL 0
49 /* We have all categories defined in `categories.def'. Now construct
50 the description and data structure used for all categories. */
51 #define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
52 struct cat_item category##_desc[] = \
53 { \
54 NO_PAREN items \
55 }; \
57 char *category##_values[NELEMS (category##_desc) - 1] = { NULL, };
58 #include "categories.def"
59 #undef DEFINE_CATEGORY
61 struct category category[] =
63 #define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
64 [category] = { _NL_NUM_##category, name, NELEMS (category##_desc) - 1, \
65 category##_desc, category##_values, in, check, out },
66 #include "categories.def"
67 #undef DEFINE_CATEGORY
69 #define NCATEGORIES NELEMS (category)
72 #define SYNTAX_ERROR \
73 error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
74 locfile_data.filename, locfile_data.line_no)
77 /* Prototypes for local functions. */
78 static int get_byte (char *byte_ptr);
79 static char *is_locale_name (int cat_no, const char *str, int len);
82 /* Read a locale definition file FILE. The format is defined in
83 POSIX.2 2.5.3. */
84 void
85 locfile_read (const char *fname)
87 /* Pointer to text of last token. */
88 char *ptr;
89 /* Length of last token (or if NUMBER the value itself). */
90 int len;
91 /* The last returned token. */
92 int token;
93 /* For error correction we remember whether the last token was correct. */
94 int correct_token = 1;
96 /* Open the desired input file on stdin. */
97 locfile_open (fname);
99 while ((token = locfile_lex (&ptr, &len)) != 0)
101 int cat_no;
103 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
104 if (token == category[cat_no].cat_id)
105 break;
107 if (cat_no >= NCATEGORIES)
108 /* A syntax error occured. No valid category defintion starts. */
110 if (correct_token != 0)
111 error (0, 0, gettext ("%s:%Zd: locale category start expected"),
112 locfile_data.filename, locfile_data.line_no);
114 /* To prevent following errors mark as error case. */
115 correct_token = 0;
117 /* Synchronization point is the beginning of a new category.
118 Overread all line upto this silently. */
119 ignore_to_eol (0, 0);
120 continue;
123 /* Rest of the line should be empty. */
124 ignore_to_eol (0, 1);
126 /* Perhaps these category is already specified. We simply give a
127 warning and overwrite the values. */
128 if (category[cat_no].filled != 0)
129 error (0, 0, gettext ("%s:%Zd: multiple definition of locale "
130 "category %s"), locfile_data.filename,
131 locfile_data.line_no, category[cat_no].name);
133 /* We read the first token because this could be the copy statement. */
134 token = xlocfile_lex (&ptr, &len);
136 if (token == TOK_COPY)
137 /* Copying the definitions from an existing locale is requested. */
139 char *str;
141 /* Get the name of the locale to copy from. */
142 token = xlocfile_lex (&ptr, &len);
143 if (token != TOK_IDENT && token != TOK_STRING)
144 /* No name, then mark error and ignore everything upto next
145 start of an category section. */
147 /* To prevent following errors mark as error case. */
148 correct_token = 0;
150 /* Synchronization point is the beginning of a new category.
151 Overread all line upto this silently. */
152 ignore_to_eol (0, 0);
154 else if ((str = is_locale_name (cat_no, ptr, len)) != NULL)
155 /* Yes the name really names an existing locale file. We are
156 returned the complete file name. Store it so that we can
157 copy it in the output phase. */
159 category[cat_no].copy_locale = str;
160 category[cat_no].filled = 1;
162 ignore_to_eol (0, 1);
164 else
165 /* No, the name does not address a valid locale file. Mark
166 error case and ignore rest of category. */
168 char tmp[len + 1];
169 memcpy (tmp, ptr, len);
170 tmp[len] = '\0';
171 error (0, 0, gettext ("%s:%Zd: invalid locale `%s' in copy "
172 "statement"), locfile_data.filename,
173 locfile_data.line_no, tmp);
174 correct_token = 0;
175 ignore_to_eol (0, 0);
178 /* This should END as the next token. */
179 token = xlocfile_lex (&ptr, &len);
181 if (token == TOK_END)
182 /* This is the end of the category. */
184 token = xlocfile_lex (&ptr, &len);
186 if (token != category[cat_no].cat_id)
187 /* Wrong category name after END. */
189 error (0, 0, gettext ("%s:%Zd: category `%s' does not "
190 "end with `END %s'"),
191 locfile_data.filename, locfile_data.line_no,
192 category[cat_no].name, category[cat_no].name);
193 ignore_to_eol (0, 0);
195 else
196 ignore_to_eol (0, 1);
198 correct_token = 1;
200 else
201 /* No END following copy. Give error while not in error case. */
203 if (correct_token != 0)
204 error (0, 0, gettext ("%s:%Zd: `copy' must be sole rule"),
205 locfile_data.filename, locfile_data.line_no);
206 correct_token = 0;
207 ignore_to_eol (0, 0);
210 continue;
213 /* Now it's time to mark as mentioned in the locale file. */
214 category[cat_no].filled = 1;
216 if (category[cat_no].infct != NULL)
217 /* The category needs a special input handling. */
219 category[cat_no].infct(token);
220 continue;
223 /* Now process the given items. */
224 while (1)
226 int item_no;
228 if (token == TOK_END)
229 /* This is the end of the category. */
231 token = xlocfile_lex (&ptr, &len);
233 if (token != category[cat_no].cat_id)
235 error (0, 0, gettext ("%s:%Zd: category `%s' does not end "
236 "with `END %s'"),
237 locfile_data.filename, locfile_data.line_no,
238 category[cat_no].name, category[cat_no].name);
239 ignore_to_eol (0, 0);
241 else
242 ignore_to_eol (0, 1);
244 /* Start next category. */
245 break;
248 /* All other lines should describe valid items of the category. */
249 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
250 if (category[cat_no].item_desc[item_no].item_id == token)
251 break;
253 if (item_no >= category[cat_no].number)
254 /* This is not a valid item of the category. */
256 SYNTAX_ERROR;
257 ignore_to_eol (0, 0);
259 token = xlocfile_lex (&ptr, &len);
261 /* And process next item. */
262 continue;
265 /* Test whether already a value is defined. */
266 if (category[cat_no].item_value[item_no] != NULL)
267 error (0, 0, gettext ("%s:%Zd: category item `%s' already "
268 "defined"),
269 locfile_data.filename, locfile_data.line_no,
270 category[cat_no].item_desc[item_no].name);
272 switch (category[cat_no].item_desc[item_no].value_type)
274 case string:
275 /* Get next token. This is the argument to the item. */
276 token = xlocfile_lex (&ptr, &len);
278 if (token != TOK_STRING)
279 SYNTAX_ERROR;
280 else
281 category[cat_no].item_value[item_no] = strdup (ptr);
282 ignore_to_eol (0, ptr != NULL);
283 break;
284 case stringarray:
285 /* This is a difficult case. The number of strings in
286 the array may vary. But for now its only necessary
287 with ALT_DIGITS from LC_TIME. This item is the last
288 so be can solve it by storing the number of string in
289 the first place and the string indeces following
290 that. */
292 int cnt;
293 char **buffer;
294 if (category[cat_no].item_value[item_no] != NULL)
295 buffer = (char **) category[cat_no].item_value[item_no];
296 else
297 buffer = (char **) xmalloc (
298 sizeof (char *) * category[cat_no].item_desc[item_no].max);
300 category[cat_no].item_value[item_no] = (char *) buffer;
302 /* As explained we may need a place to store the real number
303 of strings. */
304 if (category[cat_no].item_desc[item_no].min
305 != category[cat_no].item_desc[item_no].max)
306 ++buffer;
308 cnt = 0;
311 token = xlocfile_lex (&ptr, &len);
312 if (token != TOK_STRING)
314 SYNTAX_ERROR;
315 break;
318 if (cnt >= category[cat_no].item_desc[item_no].max)
320 error (0, 0, gettext ("%s:%Zd: too many elements "
321 "for item `%s`"),
322 locfile_data.filename, locfile_data.line_no,
323 category[cat_no].item_desc[item_no].name);
324 break;
327 buffer[cnt++] = strdup (ptr);
329 token = locfile_lex (&ptr, &len);
331 while (token == TOK_CHAR && len == ';');
333 ignore_to_eol (token, ptr != NULL);
335 if (cnt < category[cat_no].item_desc[item_no].min)
336 error (0, 0, gettext ("%s:%Zd: too few elements for item "
337 "`%s'"),
338 locfile_data.filename, locfile_data.line_no,
339 category[cat_no].item_desc[item_no].name);
341 if (category[cat_no].item_desc[item_no].min
342 != category[cat_no].item_desc[item_no].max)
343 *(int *) category[cat_no].item_value[item_no] = cnt;
345 break;
346 case byte:
348 int ok;
349 category[cat_no].item_value[item_no] = (char *) xmalloc (
350 __alignof__ (char));
351 ok = get_byte (category[cat_no].item_value[item_no]);
352 ignore_to_eol (0, ok);
354 break;
355 case bytearray:
357 char *buffer;
358 int maxsize;
359 int cnt;
360 char byte;
361 int ok;
363 buffer = (char *) xmalloc ((maxsize = 30));
364 cnt = 0;
366 while ((ok = get_byte (&byte)))
368 if (cnt >= maxsize)
369 buffer = (char *) xmalloc ((maxsize *= 2));
371 buffer[cnt++] = byte;
373 token = locfile_lex (&ptr, &len);
374 if (token != TOK_CHAR || len != ';')
375 break;
378 buffer[cnt] = '\0';
379 category[cat_no].item_value[item_no] = buffer;
380 ignore_to_eol (token, ok);
382 break;
383 default:
384 error (5, 0, gettext ("internal error in %s, line %u"),
385 __FUNCTION__, __LINE__);
386 /* NOTREACHED */
389 /* Get next token. */
390 token = xlocfile_lex (&ptr, &len);
391 } /* while (1) */
396 /* Check given values for categories for consistency. */
397 void
398 categories_check (void)
400 int cat_no;
402 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
403 if (category[cat_no].copy_locale == NULL)
404 if (category[cat_no].filled != 0)
405 if (category[cat_no].checkfct)
406 category[cat_no].checkfct();
407 else
409 int item_no;
411 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
412 if (category[cat_no].item_value[item_no] == NULL)
414 int errcode;
416 /* If the item is defined in the standard is it an error to
417 have it not defined. */
418 errcode = category[cat_no].item_desc[item_no].status == std
419 ? 5 : 0;
421 error (errcode, 0, gettext ("item `%s' of category `%s' "
422 "undefined"),
423 category[cat_no].item_desc[item_no].name,
424 category[cat_no].name);
427 else
428 error (0, 0, gettext ("category `%s' not defined"),
429 category[cat_no].name);
433 /* Write out the binary representation of the category data which can be
434 loaded by setlocale(1). */
435 void
436 categories_write (void)
438 struct locale_file
440 int magic;
441 int n;
442 int idx[0];
443 } *data;
444 struct obstack obstk;
445 int cat_no;
447 #define obstack_chunk_alloc xmalloc
448 #define obstack_chunk_free free
449 obstack_init (&obstk);
451 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
453 int result = 0;
455 if (category[cat_no].copy_locale != NULL)
456 /* Simply copy the addressed locale file of the specified
457 category. Please note that this is tried before the distinction
458 between categories which need special handling is made. */
460 int source;
462 /* Open source file. */
463 source = open (category[cat_no].copy_locale, O_RDONLY);
464 if (source < 0)
465 error (0, 0, gettext ("cannot copy locale definition file `%s'"),
466 category[cat_no].copy_locale);
467 else
469 /* Construct file name of output file and open for writing. */
470 char path[strlen (output_path)
471 + strlen(category[cat_no].name) + 1];
472 int dest;
473 char *t;
475 t = stpcpy (path, output_path);
476 strcpy (t, category[cat_no].name);
478 dest = creat (path, 0666);
479 if (dest == -1)
480 error (0, 0, gettext ("cannot open output file `%s': %m"),
481 path);
482 else
484 char buffer[BUFSIZ];
485 int size;
487 /* Copy the files. */
490 size = read (source, buffer, BUFSIZ);
491 write (dest, buffer, size);
493 while (size > 0);
495 close (dest);
497 /* Show success. */
498 puts (category[cat_no].name);
500 close (source);
503 /* Next category. */
504 continue;
507 if (category[cat_no].outfct)
508 result = category[cat_no].outfct();
509 else
511 char *path, *t;
512 int fd;
513 struct iovec *iov;
514 int item_no, len, slen, cnt;
515 int elems = 0;
517 /* Count number of elements. */
518 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
520 switch (category[cat_no].item_desc[item_no].value_type)
522 case string:
523 case byte:
524 case bytearray:
525 ++elems;
526 break;
527 case stringarray:
528 elems += category[cat_no].item_desc[item_no].max;
529 break;
530 default:
531 error (5, 0, gettext ("internal error in %s, line %u"),
532 __FUNCTION__, __LINE__);
533 /* NOTREACHED */
537 /* We now have the number of elements. We build the structure
538 and a helper structure for writing all out. */
539 len = sizeof (struct locale_file) + elems * sizeof (int);
540 data = obstack_alloc (&obstk, len);
541 iov = obstack_alloc (&obstk, (elems + 1) * sizeof (struct iovec));
543 data->magic = LIMAGIC (cat_no);
544 data->n = elems;
545 iov[0].iov_base = data;
546 iov[0].iov_len = len;
548 cnt = 0;
549 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
550 if (category[cat_no].item_value[item_no] == NULL)
552 switch (category[cat_no].item_desc[item_no].value_type)
554 case string:
555 case byte:
556 case bytearray:
557 data->idx[cnt] = len;
558 ++len; /* We reserve one single byte for this entry. */
559 iov[1 + cnt].iov_base = (char *) "";
560 iov[1 + cnt].iov_len = 1;
561 ++cnt;
562 break;
563 case stringarray:
565 int max;
566 int nstr;
568 max = category[cat_no].item_desc[item_no].max;
570 for (nstr = 0; nstr < max; ++nstr)
572 data->idx[cnt] = len;
573 ++len;
574 iov[1 + cnt].iov_base = "";
575 iov[1 + cnt].iov_len = 1;
576 ++cnt;
581 else
582 switch (category[cat_no].item_desc[item_no].value_type)
584 case string:
585 case bytearray:
586 data->idx[cnt] = len;
587 slen = strlen (category[cat_no].item_value[item_no]) + 1;
588 len += slen;
589 iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
590 iov[1 + cnt].iov_len = slen;
591 ++cnt;
592 break;
593 case byte:
594 data->idx[cnt] = len;
595 slen = 1;
596 len += slen;
597 iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
598 iov[1 + cnt].iov_len = slen;
599 ++cnt;
600 break;
601 case stringarray:
603 int nstr, nact;
604 char **first;
606 if (category[cat_no].item_desc[item_no].min
607 == category[cat_no].item_desc[item_no].max)
609 nstr = category[cat_no].item_desc[item_no].min;
610 first = (char **) category[cat_no].item_value[item_no];
612 else
614 nstr = *(int *) category[cat_no].item_value[item_no];
615 first =
616 ((char **) category[cat_no].item_value[item_no]) + 1;
618 nact = nstr;
619 while (nstr > 0)
621 data->idx[cnt] = len;
622 if (*first != NULL)
624 slen = strlen (*first) + 1;
625 iov[1 + cnt].iov_base = *first;
627 else
629 slen = 1;
630 iov[1 + cnt].iov_base = (char *) "";
632 len += slen;
633 iov[1 + cnt].iov_len = slen;
634 ++cnt;
635 ++first;
636 --nstr;
638 while (nact < category[cat_no].item_desc[item_no].max)
640 data->idx[cnt] = len;
641 len += 1;
642 iov[1 + cnt].iov_base = (char *) "";
643 iov[1 + cnt].iov_len = 1;
644 ++cnt;
645 ++nact;
648 break;
649 default:
650 /* Cannot happen. */
651 break;
653 assert (cnt <= elems);
655 /* Construct the output filename from the argument given to
656 localedef on the command line. */
657 path = (char *) obstack_alloc (&obstk, strlen (output_path) +
658 2 * strlen (category[cat_no].name) + 5);
659 t = stpcpy (path, output_path);
660 strcpy (t, category[cat_no].name);
662 fd = creat (path, 0666);
664 if (fd == -1)
666 /* Check whether it failed because the named file is a directory.
667 In that case we use the file .../LC_xxx/SYS_LC_xxx, as the
668 loading functions of the C Library do. */
669 struct stat st;
671 if (stat (path, &st) == 0 && S_ISDIR (st.st_mode))
673 stpcpy (stpcpy (strchr (path, '\0'), "/SYS_"),
674 category[cat_no].name);
675 fd = creat (path, 0666);
679 if (fd == -1)
681 error (0, 0, gettext ("cannot open output file `%s': %m"),
682 path);
683 result = 1;
685 else
687 if (writev (fd, iov, cnt + 1) == -1)
689 error (0, 0, gettext ("cannot write output file `%s': %m"),
690 path);
691 result = 1;
694 if (elems==0) write(fd, &elems, 10);
696 close (fd);
698 /* The old data is not needed anymore, but keep the obstack
699 intact. */
700 obstack_free (&obstk, data);
703 if (result == 0)
704 puts (category[cat_no].name);
706 /* Now the whole obstack can be removed. */
707 obstack_free (&obstk, NULL);
711 /* Get the representation of a number. This is a positive integer or
712 the number -1 which is handled as a special symbol by the scanner. */
713 static int
714 get_byte (char *byte_ptr)
716 int token;
717 char *ptr;
718 int len;
720 token = locfile_lex (&ptr, &len);
721 if (token != TOK_NUMBER && token != TOK_MINUS1)
722 /* None of the valid number format. */
724 error (0, 0, gettext ("%s:%Zd: number expected"),
725 locfile_data.filename, locfile_data.line_no);
726 *byte_ptr = 0;
727 return 0;
730 if (token == TOK_MINUS1)
732 *byte_ptr = CHAR_MAX;
733 return 1;
736 if (len > CHAR_MAX)
737 /* The value of the numbers has to be less than CHAR_MAX. This is
738 ok for the information they have to express. */
740 error (0, 0, gettext ("%s:%Zd: invalid number"),
741 locfile_data.filename, locfile_data.line_no);
742 *byte_ptr = 0;
743 return 0;
746 *byte_ptr = len;
747 return 1;
751 /* Test whether the string STR with length LEN is the name of an existing
752 locale and whether a file for category CAT_NO is found in this directory.
753 This categories are looked for in the system locale definition file
754 directory.
755 Return the complete file name for the category file. */
756 static char *
757 is_locale_name (int cat_no, const char *str, int len)
759 static char **locale_names = NULL;
760 static int max_count = 0;
761 static int locale_count = 0;
762 int cnt, exist, fd;
763 char *fname;
764 struct stat st;
766 if (locale_names == NULL)
767 /* Read in the list of all available locales. */
769 DIR *dir;
770 struct dirent *dirent;
772 /* LOCALE_NAMES is not NULL anymore, but LOCALE_COUNT == 0. */
773 ++locale_names;
775 dir = opendir (LOCALE_PATH);
776 if (dir == NULL)
778 error (1, errno, gettext ("cannot read locale directory `%s'"),
779 LOCALE_PATH);
781 return NULL;
784 /* Now we can look for all files in the directory. */
785 while ((dirent = readdir (dir)) != NULL)
786 if (strcmp (dirent->d_name, ".") != 0
787 && strcmp (dirent->d_name, "..") != 0)
789 if (max_count == 0)
790 locale_names = (char **) xmalloc ((max_count = 10)
791 * sizeof (char *));
792 else if (locale_count >= max_count)
793 locale_names = (char **) xrealloc (locale_names,
794 (max_count *= 2)
795 * sizeof (char *));
796 locale_names[locale_count++] = strdup (dirent->d_name);
798 closedir (dir);
801 for (cnt = 0; cnt < locale_count; ++cnt)
802 if (strncmp (str, locale_names[cnt], len) == 0
803 && locale_names[cnt][len] == '\0')
804 break;
806 if (cnt >= locale_count)
807 return NULL;
809 /* Now search for this specific locale file. */
810 asprintf (&fname, "%s/%s/%s", LOCALE_PATH, locale_names[cnt],
811 category[cat_no].name);
813 fd = open (fname, O_RDONLY);
814 if (fd < 0)
816 free (fname);
817 return NULL;
820 exist = fstat (fd, &st);
821 close (fd);
823 if (exist < 0)
825 free (fname);
826 return NULL;
829 return fname;
833 * Local Variables:
834 * mode:c
835 * c-basic-offset:2
836 * End: