1 /* Copyright (C) 1995, 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>, 1995.
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. */
33 #include "linereader.h"
34 #include "localedef.h"
35 #include "localeinfo.h"
39 /* Entry describing an entry of the era specification. */
44 int32_t start_date[3];
53 /* The real definition of the struct for the LC_TIME locale. */
57 const uint32_t *wabday[7];
60 const uint32_t *wday[7];
62 const char *abmon[12];
63 const uint32_t *wabmon[12];
66 const uint32_t *wmon[12];
69 const uint32_t *wam_pm[2];
72 const uint32_t *wd_t_fmt;
74 const uint32_t *wd_fmt;
76 const uint32_t *wt_fmt;
77 const char *t_fmt_ampm;
78 const uint32_t *wt_fmt_ampm;
80 const uint32_t **wera;
83 const uint32_t *wera_year;
84 const char *era_d_t_fmt;
85 const uint32_t *wera_d_t_fmt;
86 const char *era_t_fmt;
87 const uint32_t *wera_t_fmt;
88 const char *era_d_fmt;
89 const uint32_t *wera_d_fmt;
90 const char *alt_digits[100];
91 const uint32_t *walt_digits[100];
92 int alt_digits_defined;
93 unsigned char week_ndays;
95 unsigned char week_1stweek;
96 unsigned char first_weekday;
97 unsigned char first_workday;
98 unsigned char cal_direction;
100 const uint32_t *wtimezone;
102 struct era_data *era_entries;
106 /* This constant is used to represent an empty wide character string. */
107 static const uint32_t empty_wstr[1] = { 0 };
111 time_startup (struct linereader *lr, struct localedef_t *locale,
115 locale->categories[LC_TIME].time =
116 (struct locale_time_t *) xcalloc (1, sizeof (struct locale_time_t));
120 lr->translate_strings = 1;
121 lr->return_widestr = 1;
127 time_finish (struct localedef_t *locale, struct charmap_t *charmap)
129 struct locale_time_t *time = locale->categories[LC_TIME].time;
132 /* Now resolve copying and also handle completely missing definitions. */
135 /* First see whether we were supposed to copy. If yes, find the
136 actual definition. */
137 if (locale->copy_name[LC_TIME] != NULL)
139 /* Find the copying locale. This has to happen transitively since
140 the locale we are copying from might also copying another one. */
141 struct localedef_t *from = locale;
144 from = find_locale (LC_TIME, from->copy_name[LC_TIME],
145 from->repertoire_name, charmap);
146 while (from->categories[LC_TIME].time == NULL
147 && from->copy_name[LC_TIME] != NULL);
149 time = locale->categories[LC_TIME].time
150 = from->categories[LC_TIME].time;
153 /* If there is still no definition issue an warning and create an
157 error (0, 0, _("No definition for %s category found"), "LC_TIME");
158 time_startup (NULL, locale, 0);
159 time = locale->categories[LC_TIME].time;
164 #define TESTARR_ELEM(cat) \
165 if (!time->cat##_defined) \
167 if(! be_quiet && ! nothing) \
168 error (0, 0, _("%s: field `%s' not defined"), "LC_TIME", #cat); \
171 TESTARR_ELEM (abday);
173 TESTARR_ELEM (abmon);
175 TESTARR_ELEM (am_pm);
177 #define TEST_ELEM(cat) \
178 if (time->cat == NULL) \
180 if (! be_quiet && ! nothing) \
181 error (0, 0, _("%s: field `%s' not defined"), "LC_TIME", #cat); \
188 /* According to C.Y.Alexis Cheng <alexis@vnet.ibm.com> the T_FMT_AMPM
189 field is optional. */
190 if (time->t_fmt_ampm == NULL)
192 /* Use the 24h format as default. */
193 time->t_fmt_ampm = time->t_fmt;
194 time->wt_fmt_ampm = time->wt_fmt;
197 /* Now process the era entries. */
198 if (time->num_era != 0)
200 const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
201 31, 31, 30, 31 ,30, 31 };
206 (struct era_data *) xmalloc (time->num_era
207 * sizeof (struct era_data));
209 for (idx = 0; idx < time->num_era; ++idx)
211 size_t era_len = strlen (time->era[idx]);
212 char *str = xmalloc ((era_len + 1 + 3) & ~3);
215 memcpy (str, time->era[idx], era_len + 1);
217 /* First character must be + or - for the direction. */
218 if (*str != '+' && *str != '-')
221 error (0, 0, _("%s: direction flag in string %d in `era' field"
222 " is not '+' nor '-'"),
224 /* Default arbitrarily to '+'. */
225 time->era_entries[idx].direction = '+';
228 time->era_entries[idx].direction = *str;
232 error (0, 0, _("%s: direction flag in string %d in `era' field"
233 " is not a single character"),
235 (void) strsep (&str, ":");
240 /* Now the offset year. */
241 time->era_entries[idx].offset = strtol (str, &endp, 10);
245 error (0, 0, _("%s: invalid number for offset in string %d in"
248 (void) strsep (&str, ":");
250 else if (*endp != ':')
253 error (0, 0, _("%s: garbage at end of offset value in"
254 " string %d in `era' field"),
256 (void) strsep (&str, ":");
261 /* Next is the starting date in ISO format. */
262 if (strncmp (str, "-*", 2) == 0)
264 time->era_entries[idx].start_date[0] =
265 time->era_entries[idx].start_date[1] =
266 time->era_entries[idx].start_date[2] = 0x80000000;
268 goto garbage_start_date;
271 else if (strncmp (str, "+*", 2) == 0)
273 time->era_entries[idx].start_date[0] =
274 time->era_entries[idx].start_date[1] =
275 time->era_entries[idx].start_date[2] = 0x7fffffff;
277 goto garbage_start_date;
282 time->era_entries[idx].start_date[0] = strtol (str, &endp, 10);
283 if (endp == str || *endp != '/')
284 goto invalid_start_date;
287 time->era_entries[idx].start_date[0] -= 1900;
289 time->era_entries[idx].start_date[1] = strtol (str, &endp, 10);
290 if (endp == str || *endp != '/')
291 goto invalid_start_date;
294 time->era_entries[idx].start_date[1] -= 1;
296 time->era_entries[idx].start_date[2] = strtol (str, &endp, 10);
301 error (0, 0, _("%s: invalid starting date in string %d in"
304 (void) strsep (&str, ":");
306 else if (*endp != ':')
310 error (0, 0, _("%s: garbage at end of starting date "
311 "in string %d in `era' field "),
313 (void) strsep (&str, ":");
319 /* Check for valid value. */
320 if ((time->era_entries[idx].start_date[1] < 0
321 || time->era_entries[idx].start_date[1] >= 12
322 || time->era_entries[idx].start_date[2] < 0
323 || (time->era_entries[idx].start_date[2]
324 > days_per_month[time->era_entries[idx].start_date[1]])
325 || (time->era_entries[idx].start_date[1] == 2
326 && time->era_entries[idx].start_date[2] == 29
327 && !__isleap (time->era_entries[idx].start_date[0])))
329 error (0, 0, _("%s: starting date is invalid in"
330 " string %d in `era' field"),
335 /* Next is the stopping date in ISO format. */
336 if (strncmp (str, "-*", 2) == 0)
338 time->era_entries[idx].stop_date[0] =
339 time->era_entries[idx].stop_date[1] =
340 time->era_entries[idx].stop_date[2] = 0x80000000;
342 goto garbage_stop_date;
345 else if (strncmp (str, "+*", 2) == 0)
347 time->era_entries[idx].stop_date[0] =
348 time->era_entries[idx].stop_date[1] =
349 time->era_entries[idx].stop_date[2] = 0x7fffffff;
351 goto garbage_stop_date;
356 time->era_entries[idx].stop_date[0] = strtol (str, &endp, 10);
357 if (endp == str || *endp != '/')
358 goto invalid_stop_date;
361 time->era_entries[idx].stop_date[0] -= 1900;
363 time->era_entries[idx].stop_date[1] = strtol (str, &endp, 10);
364 if (endp == str || *endp != '/')
365 goto invalid_stop_date;
368 time->era_entries[idx].stop_date[1] -= 1;
370 time->era_entries[idx].stop_date[2] = strtol (str, &endp, 10);
375 error (0, 0, _("%s: invalid stopping date in string %d in"
378 (void) strsep (&str, ":");
380 else if (*endp != ':')
384 error (0, 0, _("%s: garbage at end of stopping date "
385 "in string %d in `era' field"),
387 (void) strsep (&str, ":");
393 /* Check for valid value. */
394 if ((time->era_entries[idx].stop_date[1] < 0
395 || time->era_entries[idx].stop_date[1] >= 12
396 || time->era_entries[idx].stop_date[2] < 0
397 || (time->era_entries[idx].stop_date[2]
398 > days_per_month[time->era_entries[idx].stop_date[1]])
399 || (time->era_entries[idx].stop_date[1] == 2
400 && time->era_entries[idx].stop_date[2] == 29
401 && !__isleap (time->era_entries[idx].stop_date[0])))
403 error (0, 0, _("%s: stopping date is invalid in"
404 " string %d in `era' field"),
409 if (str == NULL || *str == '\0')
412 error (0, 0, _("%s: missing era name in string %d in `era'"
413 " field"), "LC_TIME", idx + 1);
414 time->era_entries[idx].name =
415 time->era_entries[idx].format = "";
419 time->era_entries[idx].name = strsep (&str, ":");
421 if (str == NULL || *str == '\0')
424 error (0, 0, _("%s: missing era format in string %d"
427 time->era_entries[idx].name =
428 time->era_entries[idx].format = "";
431 time->era_entries[idx].format = str;
434 /* Now generate the wide character name and format. */
435 wstr = wcschr ((wchar_t *) time->wera[idx], L':');/* end direction */
436 wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end offset */
437 wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end start */
438 wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end end */
439 time->era_entries[idx].wname = (uint32_t *) wstr;
440 wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end name */
441 time->era_entries[idx].wformat = (uint32_t *) wstr;
445 if (time->week_ndays == 0)
446 time->week_ndays = 7;
448 if (time->week_1stday == 0)
449 time->week_1stday = 19971130;
451 if (time->week_1stweek > time->week_ndays)
453 %s: third operand for value of field `%s' must not be larger than %d"),
454 "LC_TIME", "week", 7);
456 if (time->first_weekday == '\0')
457 /* The definition does not specify this so the default is used. */
458 time->first_weekday = 1;
459 else if (time->first_weekday > time->week_ndays)
461 %s: values of field `%s' must not be larger than %d"),
462 "LC_TIME", "first_weekday", 7);
464 if (time->first_workday == '\0')
465 /* The definition does not specify this so the default is used. */
466 time->first_workday = 1;
467 else if (time->first_workday > time->week_ndays)
469 %s: values of field `%s' must not be larger than %d"),
470 "LC_TIME", "first_workday", 7);
472 if (time->cal_direction == '\0')
473 /* The definition does not specify this so the default is used. */
474 time->cal_direction = 1;
475 else if (time->cal_direction > 3)
477 %s: values for field `%s' must not be larger than 3"),
478 "LC_TIME", "cal_direction", 3);
480 /* XXX We don't perform any tests on the timezone value since this is
481 simply useless, stupid $&$!@... */
482 if (time->timezone == NULL)
488 time_output (struct localedef_t *locale, struct charmap_t *charmap,
489 const char *output_path)
491 struct locale_time_t *time = locale->categories[LC_TIME].time;
492 struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME)
495 + 1 + time->num_era * 10 - 1];
496 struct locale_file data;
497 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)];
498 size_t cnt, last_idx, num, n;
500 data.magic = LIMAGIC (LC_TIME);
501 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_TIME);
502 iov[0].iov_base = (void *) &data;
503 iov[0].iov_len = sizeof (data);
505 iov[1].iov_base = (void *) idx;
506 iov[1].iov_len = sizeof (idx);
508 idx[0] = iov[0].iov_len + iov[1].iov_len;
511 for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
513 iov[2 + cnt].iov_base =
514 (void *) (time->abday[cnt - _NL_ITEM_INDEX (ABDAY_1)] ?: "");
515 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
516 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
520 for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
522 iov[2 + cnt].iov_base =
523 (void *) (time->day[cnt - _NL_ITEM_INDEX (DAY_1)] ?: "");
524 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
525 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
529 for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
531 iov[2 + cnt].iov_base =
532 (void *) (time->abmon[cnt - _NL_ITEM_INDEX (ABMON_1)] ?: "");
533 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
534 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
538 for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
540 iov[2 + cnt].iov_base =
541 (void *) (time->mon[cnt - _NL_ITEM_INDEX (MON_1)] ?: "");
542 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
543 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
547 for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
549 iov[2 + cnt].iov_base =
550 (void *) (time->am_pm[cnt - _NL_ITEM_INDEX (AM_STR)] ?: "");
551 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
552 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
555 iov[2 + cnt].iov_base = (void *) (time->d_t_fmt ?: "");
556 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
557 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
560 iov[2 + cnt].iov_base = (void *) (time->d_fmt ?: "");
561 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
562 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
565 iov[2 + cnt].iov_base = (void *) (time->t_fmt ?: "");
566 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
567 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
570 iov[2 + cnt].iov_base = (void *) (time->t_fmt_ampm ?: "");
571 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
572 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
575 idx[1 + last_idx] = idx[last_idx];
576 for (num = 0; num < time->num_era; ++num, ++cnt)
578 iov[2 + cnt].iov_base = (void *) time->era[num];
579 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
580 idx[1 + last_idx] += iov[2 + cnt].iov_len;
584 iov[2 + cnt].iov_base = (void *) (time->era_year ?: "");
585 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
586 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
590 iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
591 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
592 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
596 idx[1 + last_idx] = idx[last_idx];
597 for (num = 0; num < 100; ++num, ++cnt)
599 iov[2 + cnt].iov_base = (void *) (time->alt_digits[num] ?: "");
600 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
601 idx[1 + last_idx] += iov[2 + cnt].iov_len;
605 iov[2 + cnt].iov_base = (void *) (time->era_d_t_fmt ?: "");
606 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
607 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
611 iov[2 + cnt].iov_base = (void *) (time->era_t_fmt ?: "");
612 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
613 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
618 /* We must align the following data. */
619 iov[2 + cnt].iov_base = (void *) "\0\0";
620 iov[2 + cnt].iov_len = ((idx[last_idx] + 3) & ~3) - idx[last_idx];
621 idx[last_idx] = (idx[last_idx] + 3) & ~3;
624 /* The `era' data in usable form. */
625 iov[2 + cnt].iov_base = (void *) &time->num_era;
626 iov[2 + cnt].iov_len = sizeof (uint32_t);
627 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
631 idx[1 + last_idx] = idx[last_idx];
632 for (num = 0; num < time->num_era; ++num)
636 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].direction;
637 iov[2 + cnt].iov_len = sizeof (int32_t);
639 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].offset;
640 iov[2 + cnt].iov_len = sizeof (int32_t);
642 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].start_date[0];
643 iov[2 + cnt].iov_len = sizeof (int32_t);
645 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].start_date[1];
646 iov[2 + cnt].iov_len = sizeof (int32_t);
648 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].start_date[2];
649 iov[2 + cnt].iov_len = sizeof (int32_t);
651 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].stop_date[0];
652 iov[2 + cnt].iov_len = sizeof (int32_t);
654 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].stop_date[1];
655 iov[2 + cnt].iov_len = sizeof (int32_t);
657 iov[2 + cnt].iov_base = (void *) &time->era_entries[num].stop_date[2];
658 iov[2 + cnt].iov_len = sizeof (int32_t);
661 l = (strchr (time->era_entries[num].format, '\0')
662 - time->era_entries[num].name) + 1;
664 iov[2 + cnt].iov_base = (void *) time->era_entries[num].name;
665 iov[2 + cnt].iov_len = l;
668 idx[1 + last_idx] += 8 * sizeof (int32_t) + l;
670 assert (idx[1 + last_idx] % 4 == 0);
672 iov[2 + cnt].iov_base = (void *) time->era_entries[num].wname;
673 iov[2 + cnt].iov_len = ((wcschr ((wchar_t *) time->era_entries[num].wformat, L'\0')
674 - (wchar_t *) time->era_entries[num].wname + 1)
675 * sizeof (uint32_t));
676 idx[1 + last_idx] += iov[2 + cnt].iov_len;
681 /* The wide character ab'days. */
682 for (n = 0; n < 7; ++n, ++cnt, ++last_idx)
684 iov[2 + cnt].iov_base =
685 (void *) (time->wabday[n] ?: empty_wstr);
686 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
687 * sizeof (uint32_t));
688 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
691 /* The wide character days. */
692 for (n = 0; n < 7; ++n, ++cnt, ++last_idx)
694 iov[2 + cnt].iov_base =
695 (void *) (time->wday[n] ?: empty_wstr);
696 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
697 * sizeof (uint32_t));
698 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
701 /* The wide character ab'mons. */
702 for (n = 0; n < 12; ++n, ++cnt, ++last_idx)
704 iov[2 + cnt].iov_base =
705 (void *) (time->wabmon[n] ?: empty_wstr);
706 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
707 * sizeof (uint32_t));
708 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
711 /* The wide character mons. */
712 for (n = 0; n < 12; ++n, ++cnt, ++last_idx)
714 iov[2 + cnt].iov_base =
715 (void *) (time->wmon[n] ?: empty_wstr);
716 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
717 * sizeof (uint32_t));
718 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
721 /* Wide character AM/PM. */
722 for (n = 0; n < 2; ++n, ++cnt, ++last_idx)
724 iov[2 + cnt].iov_base =
725 (void *) (time->wam_pm[n] ?: empty_wstr);
726 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
727 * sizeof (uint32_t));
728 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
731 iov[2 + cnt].iov_base = (void *) (time->wd_t_fmt ?: empty_wstr);
732 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
733 * sizeof (uint32_t));
734 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
738 iov[2 + cnt].iov_base = (void *) (time->wd_fmt ?: empty_wstr);
739 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
740 * sizeof (uint32_t));
741 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
745 iov[2 + cnt].iov_base = (void *) (time->wt_fmt ?: empty_wstr);
746 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
747 * sizeof (uint32_t));
748 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
752 iov[2 + cnt].iov_base = (void *) (time->wt_fmt_ampm ?: empty_wstr);
753 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
754 * sizeof (uint32_t));
755 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
759 iov[2 + cnt].iov_base = (void *) (time->wera_year ?: empty_wstr);
760 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
761 * sizeof (uint32_t));
762 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
766 iov[2 + cnt].iov_base = (void *) (time->wera_d_fmt ?: empty_wstr);
767 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
768 * sizeof (uint32_t));
769 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
773 idx[1 + last_idx] = idx[last_idx];
774 for (num = 0; num < 100; ++num, ++cnt)
776 iov[2 + cnt].iov_base = (void *) (time->walt_digits[num]
778 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
779 * sizeof (uint32_t));
780 idx[1 + last_idx] += iov[2 + cnt].iov_len;
784 iov[2 + cnt].iov_base = (void *) (time->wera_d_t_fmt ?: empty_wstr);
785 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
786 * sizeof (uint32_t));
787 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
791 iov[2 + cnt].iov_base = (void *) (time->wera_t_fmt ?: empty_wstr);
792 iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
793 * sizeof (uint32_t));
794 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
798 iov[2 + cnt].iov_base = (void *) &time->week_ndays;
799 iov[2 + cnt].iov_len = 1;
800 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
804 iov[2 + cnt].iov_base = (void *) &time->week_1stday;
805 iov[2 + cnt].iov_len = 1;
806 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
810 iov[2 + cnt].iov_base = (void *) &time->week_1stweek;
811 iov[2 + cnt].iov_len = 1;
812 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
816 iov[2 + cnt].iov_base = (void *) &time->first_weekday;
817 iov[2 + cnt].iov_len = 1;
818 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
822 iov[2 + cnt].iov_base = (void *) &time->first_workday;
823 iov[2 + cnt].iov_len = 1;
824 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
828 iov[2 + cnt].iov_base = (void *) &time->cal_direction;
829 iov[2 + cnt].iov_len = 1;
830 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
834 iov[2 + cnt].iov_base = (void *) time->timezone;
835 iov[2 + cnt].iov_len = strlen (time->timezone) + 1;
839 assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME)
842 + 1 + time->num_era * 10 - 1));
843 assert (last_idx == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
845 write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
849 /* The parser for the LC_TIME section of the locale definition. */
851 time_read (struct linereader *ldfile, struct localedef_t *result,
852 struct charmap_t *charmap, const char *repertoire_name,
855 struct repertoire_t *repertoire = NULL;
856 struct locale_time_t *time;
861 /* Get the repertoire we have to use. */
862 if (repertoire_name != NULL)
863 repertoire = repertoire_read (repertoire_name);
865 /* The rest of the line containing `LC_TIME' must be free. */
866 lr_ignore_rest (ldfile, 1);
871 now = lr_token (ldfile, charmap, repertoire);
874 while (nowtok == tok_eol);
876 /* If we see `copy' now we are almost done. */
877 if (nowtok == tok_copy)
879 handle_copy (ldfile, charmap, repertoire, result, tok_lc_time,
880 LC_TIME, "LC_TIME", ignore_content);
884 /* Prepare the data structures. */
885 time_startup (ldfile, result, ignore_content);
886 time = result->categories[LC_TIME].time;
890 /* Of course we don't proceed beyond the end of file. */
891 if (nowtok == tok_eof)
894 /* Ingore empty lines. */
895 if (nowtok == tok_eol)
897 now = lr_token (ldfile, charmap, repertoire);
904 #define STRARR_ELEM(cat, min, max) \
906 /* Ignore the rest of the line if we don't need the input of \
908 if (ignore_content) \
910 lr_ignore_rest (ldfile, 0); \
914 for (cnt = 0; cnt < max; ++cnt) \
916 now = lr_token (ldfile, charmap, repertoire); \
917 if (now->tok == tok_eol) \
920 lr_error (ldfile, _("%s: too few values for field `%s'"), \
922 if (!ignore_content) \
925 time->cat[cnt] = ""; \
926 time->w##cat[cnt] = empty_wstr; \
928 while (++cnt < max); \
931 else if (now->tok != tok_string) \
933 else if (!ignore_content && (now->val.str.startmb == NULL \
934 || now->val.str.startwc == NULL)) \
936 lr_error (ldfile, _("%s: unknown character in field `%s'"), \
938 time->cat[cnt] = ""; \
939 time->w##cat[cnt] = empty_wstr; \
941 else if (!ignore_content) \
943 time->cat[cnt] = now->val.str.startmb; \
944 time->w##cat[cnt] = now->val.str.startwc; \
947 /* Match the semicolon. */ \
948 now = lr_token (ldfile, charmap, repertoire); \
949 if (now->tok != tok_semicolon && now->tok != tok_eol) \
952 if (now->tok != tok_eol) \
954 while (!ignore_content && cnt < min) \
956 time->cat[cnt] = ""; \
957 time->w##cat[cnt++] = empty_wstr; \
960 if (now->tok == tok_semicolon) \
962 now = lr_token (ldfile, charmap, repertoire); \
963 if (now->tok == tok_eol) \
964 lr_error (ldfile, _("extra trailing semicolon")); \
965 else if (now->tok == tok_string) \
967 lr_error (ldfile, _("\
968 %s: too many values for field `%s'"), \
970 lr_ignore_rest (ldfile, 0); \
978 time->cat##_defined = 1; \
981 STRARR_ELEM (abday, 7, 7);
982 STRARR_ELEM (day, 7, 7);
983 STRARR_ELEM (abmon, 12, 12);
984 STRARR_ELEM (mon, 12, 12);
985 STRARR_ELEM (am_pm, 2, 2);
986 STRARR_ELEM (alt_digits, 0, 100);
989 /* Ignore the rest of the line if we don't need the input of
993 lr_ignore_rest (ldfile, 0);
998 now = lr_token (ldfile, charmap, repertoire);
999 if (now->tok != tok_string)
1001 if (!ignore_content && (now->val.str.startmb == NULL
1002 || now->val.str.startwc == NULL))
1004 lr_error (ldfile, _("%s: unknown character in field `%s'"),
1006 lr_ignore_rest (ldfile, 0);
1009 if (!ignore_content)
1011 time->era = xrealloc (time->era,
1012 (time->num_era + 1) * sizeof (char *));
1013 time->era[time->num_era] = now->val.str.startmb;
1015 time->wera = xrealloc (time->wera,
1018 time->wera[time->num_era++] = now->val.str.startwc;
1020 now = lr_token (ldfile, charmap, repertoire);
1021 if (now->tok != tok_eol && now->tok != tok_semicolon)
1024 while (now->tok == tok_semicolon);
1027 #define STR_ELEM(cat) \
1029 /* Ignore the rest of the line if we don't need the input of \
1031 if (ignore_content) \
1033 lr_ignore_rest (ldfile, 0); \
1037 now = lr_token (ldfile, charmap, repertoire); \
1038 if (now->tok != tok_string) \
1040 else if (time->cat != NULL) \
1041 lr_error (ldfile, _("\
1042 %s: field `%s' declared more than once"), "LC_TIME", #cat); \
1043 else if (!ignore_content && (now->val.str.startmb == NULL \
1044 || now->val.str.startwc == NULL)) \
1046 lr_error (ldfile, _("%s: unknown character in field `%s'"), \
1049 time->w##cat = empty_wstr; \
1051 else if (!ignore_content) \
1053 time->cat = now->val.str.startmb; \
1054 time->w##cat = now->val.str.startwc; \
1061 STR_ELEM (t_fmt_ampm);
1062 STR_ELEM (era_year);
1063 STR_ELEM (era_d_t_fmt);
1064 STR_ELEM (era_d_fmt);
1065 STR_ELEM (era_t_fmt);
1066 STR_ELEM (timezone);
1068 #define INT_ELEM(cat) \
1070 /* Ignore the rest of the line if we don't need the input of \
1072 if (ignore_content) \
1074 lr_ignore_rest (ldfile, 0); \
1078 now = lr_token (ldfile, charmap, repertoire); \
1079 if (now->tok != tok_number) \
1081 else if (time->cat != 0) \
1082 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
1084 else if (!ignore_content) \
1085 time->cat = now->val.num; \
1088 INT_ELEM (first_weekday);
1089 INT_ELEM (first_workday);
1090 INT_ELEM (cal_direction);
1093 /* Ignore the rest of the line if we don't need the input of
1097 lr_ignore_rest (ldfile, 0);
1101 now = lr_token (ldfile, charmap, repertoire);
1102 if (now->tok != tok_number)
1104 time->week_ndays = now->val.num;
1106 now = lr_token (ldfile, charmap, repertoire);
1107 if (now->tok != tok_semicolon)
1110 now = lr_token (ldfile, charmap, repertoire);
1111 if (now->tok != tok_number)
1113 time->week_1stday = now->val.num;
1115 now = lr_token (ldfile, charmap, repertoire);
1116 if (now->tok != tok_semicolon)
1119 now = lr_token (ldfile, charmap, repertoire);
1120 if (now->tok != tok_number)
1122 time->week_1stweek = now->val.num;
1124 lr_ignore_rest (ldfile, 1);
1128 /* Next we assume `LC_TIME'. */
1129 now = lr_token (ldfile, charmap, repertoire);
1130 if (now->tok == tok_eof)
1132 if (now->tok == tok_eol)
1133 lr_error (ldfile, _("%s: incomplete `END' line"), "LC_TIME");
1134 else if (now->tok != tok_lc_time)
1135 lr_error (ldfile, _("\
1136 %1$s: definition does not end with `END %1$s'"), "LC_TIME");
1137 lr_ignore_rest (ldfile, now->tok == tok_lc_time);
1142 SYNTAX_ERROR (_("%s: syntax error"), "LC_TIME");
1145 /* Prepare for the next round. */
1146 now = lr_token (ldfile, charmap, repertoire);
1150 /* When we come here we reached the end of the file. */
1151 lr_error (ldfile, _("%s: premature end of file"), "LC_TIME");