update from main archive 961001
[glibc.git] / locale / programs / ld-time.c
blob6fcb06979a18b1ac434ecff884e4bd2dfe0d982d
1 /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
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
17 not, 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 <langinfo.h>
25 #include <string.h>
27 /* Undefine following line in production version. */
28 /* #define NDEBUG 1 */
29 #include <assert.h>
30 #include <stdlib.h>
32 #include "locales.h"
33 #include "localeinfo.h"
34 #include "stringtrans.h"
36 #define SWAPU32(w) \
37 (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
40 void *xmalloc (size_t __n);
41 void *xrealloc (void *__p, size_t __n);
44 /* Entry describing an entry of the era specification. */
45 struct era_data
47 int32_t direction;
48 int32_t offset;
49 int32_t start_date[3];
50 int32_t stop_date[3];
51 const char *name;
52 const char *format;
56 /* The real definition of the struct for the LC_TIME locale. */
57 struct locale_time_t
59 const char *abday[7];
60 size_t cur_num_abday;
61 const char *day[7];
62 size_t cur_num_day;
63 const char *abmon[12];
64 size_t cur_num_abmon;
65 const char *mon[12];
66 size_t cur_num_mon;
67 const char *am_pm[2];
68 size_t cur_num_am_pm;
69 const char *d_t_fmt;
70 const char *d_fmt;
71 const char *t_fmt;
72 const char *t_fmt_ampm;
73 const char **era;
74 u_int32_t cur_num_era;
75 const char *era_year;
76 const char *era_d_t_fmt;
77 const char *era_t_fmt;
78 const char *era_d_fmt;
79 const char *alt_digits[100];
80 u_int32_t cur_num_alt_digits;
82 struct era_data *era_entries;
83 struct era_data *era_entries_ob;
87 void
88 time_startup (struct linereader *lr, struct localedef_t *locale,
89 struct charset_t *charset)
91 struct locale_time_t *time;
93 /* It is important that we always use UCS1 encoding for strings now. */
94 encoding_method = ENC_UCS1;
96 locale->categories[LC_TIME].time = time =
97 (struct locale_time_t *) xmalloc (sizeof (struct locale_time_t));
99 memset (time, '\0', sizeof (struct locale_time_t));
103 void
104 time_finish (struct localedef_t *locale)
106 struct locale_time_t *time = locale->categories[LC_TIME].time;
108 #define TESTARR_ELEM(cat, max) \
109 if (time->cur_num_##cat == 0) \
110 error (0, 0, _("field `%s' in category `%s' not defined"), \
111 #cat, "LC_TIME"); \
112 else if (time->cur_num_##cat != max) \
113 error (0, 0, _("field `%s' in category `%s' has not enough values"), \
114 #cat, "LC_TIME")
116 TESTARR_ELEM (abday, 7);
117 TESTARR_ELEM (day, 7);
118 TESTARR_ELEM (abmon, 12);
119 TESTARR_ELEM (mon, 12);
120 TESTARR_ELEM (am_pm, 2);
122 #define TEST_ELEM(cat) \
123 if (time->cat == NULL) \
124 error (0, 0, _("field `%s' in category `%s' not defined"), \
125 #cat, "LC_TIME")
127 TEST_ELEM (d_t_fmt);
128 TEST_ELEM (d_fmt);
129 TEST_ELEM (t_fmt);
130 TEST_ELEM (t_fmt_ampm);
132 /* Now process the era entries. */
133 if (time->cur_num_era != 0)
135 const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
136 31, 31, 30, 31 ,30, 31 };
137 size_t idx;
139 time->era_entries =
140 (struct era_data *) xmalloc (time->cur_num_era
141 * sizeof (struct era_data));
143 for (idx = 0; idx < time->cur_num_era; ++idx)
145 size_t era_len = strlen (time->era[idx]);
146 char *str = xmalloc ((era_len + 1 + 3) & ~3);
147 char *endp;
149 memcpy (str, time->era[idx], era_len + 1);
151 /* First character must be + or - for the direction. */
152 if (*str != '+' && *str != '-')
154 error (0, 0, _("direction flag in string %d in `era' field"
155 " in category `%s' is not '+' nor '-'"),
156 idx + 1, "LC_TIME");
157 /* Default arbitrarily to '+'. */
158 time->era_entries[idx].direction = '+';
160 else
161 time->era_entries[idx].direction = *str;
162 if (*++str != ':')
164 error (0, 0, _("direction flag in string %d in `era' field"
165 " in category `%s' is not a single character"),
166 idx + 1, "LC_TIME");
167 (void) strsep (&str, ":");
169 else
170 ++str;
172 /* Now the offset year. */
173 time->era_entries[idx].offset = strtol (str, &endp, 10);
174 if (endp == str)
176 error (0, 0, _("illegal number for offset in string %d in"
177 " `era' field in category `%s'"),
178 idx + 1, "LC_TIME");
179 (void) strsep (&str, ":");
181 else if (*endp != ':')
183 error (0, 0, _("garbage at end of offset value in string %d in"
184 " `era' field in category `%s'"),
185 idx + 1, "LC_TIME");
186 (void) strsep (&str, ":");
188 else
189 str = endp + 1;
191 /* Next is the starting date in ISO format. */
192 if (strncmp (str, "-*", 2) == 0)
194 time->era_entries[idx].start_date[0] =
195 time->era_entries[idx].start_date[1] =
196 time->era_entries[idx].start_date[2] = 0x80000000;
197 if (str[2] != ':')
198 goto garbage_start_date;
199 str += 3;
201 else if (strncmp (str, "+*", 2) == 0)
203 time->era_entries[idx].start_date[0] =
204 time->era_entries[idx].start_date[1] =
205 time->era_entries[idx].start_date[2] = 0x7fffffff;
206 if (str[2] != ':')
207 goto garbage_start_date;
208 str += 3;
210 else
212 time->era_entries[idx].start_date[0] = strtol (str, &endp, 10);
213 if (endp == str || *endp != '/')
214 goto invalid_start_date;
215 else
216 str = endp + 1;
217 time->era_entries[idx].start_date[0] -= 1900;
219 time->era_entries[idx].start_date[1] = strtol (str, &endp, 10);
220 if (endp == str || *endp != '/')
221 goto invalid_start_date;
222 else
223 str = endp + 1;
224 time->era_entries[idx].start_date[1] -= 1;
226 time->era_entries[idx].start_date[2] = strtol (str, &endp, 10);
227 if (endp == str)
229 invalid_start_date:
230 error (0, 0, _("illegal starting date in string %d in"
231 " `era' field in category `%s'"),
232 idx + 1, "LC_TIME");
233 (void) strsep (&str, ":");
235 else if (*endp != ':')
237 garbage_start_date:
238 error (0, 0, _("garbage at end of starting date in string %d"
239 " in `era' field in category `%s'"),
240 idx + 1, "LC_TIME");
241 (void) strsep (&str, ":");
243 else
245 str = endp + 1;
247 /* Check for valid value. */
248 if (time->era_entries[idx].start_date[1] < 0
249 || time->era_entries[idx].start_date[1] >= 12
250 || time->era_entries[idx].start_date[2] < 0
251 || (time->era_entries[idx].start_date[2]
252 > days_per_month[time->era_entries[idx].start_date[1]])
253 || (time->era_entries[idx].start_date[1] == 2
254 && time->era_entries[idx].start_date[2] == 29
255 && !__isleap (time->era_entries[idx].start_date[0])))
256 error (0, 0, _("starting date is illegal in"
257 " string %d in `era' field in"
258 " category `%s'"),
259 idx + 1, "LC_TIME");
263 /* Next is the stoping date in ISO format. */
264 if (strncmp (str, "-*", 2) == 0)
266 time->era_entries[idx].stop_date[0] =
267 time->era_entries[idx].stop_date[1] =
268 time->era_entries[idx].stop_date[2] = 0x80000000;
269 if (str[2] != ':')
270 goto garbage_stop_date;
271 str += 3;
273 else if (strncmp (str, "+*", 2) == 0)
275 time->era_entries[idx].stop_date[0] =
276 time->era_entries[idx].stop_date[1] =
277 time->era_entries[idx].stop_date[2] = 0x7fffffff;
278 if (str[2] != ':')
279 goto garbage_stop_date;
280 str += 3;
282 else
284 time->era_entries[idx].stop_date[0] = strtol (str, &endp, 10);
285 if (endp == str || *endp != '/')
286 goto invalid_stop_date;
287 else
288 str = endp + 1;
289 time->era_entries[idx].stop_date[0] -= 1900;
291 time->era_entries[idx].stop_date[1] = strtol (str, &endp, 10);
292 if (endp == str || *endp != '/')
293 goto invalid_stop_date;
294 else
295 str = endp + 1;
296 time->era_entries[idx].stop_date[1] -= 1;
298 time->era_entries[idx].stop_date[2] = strtol (str, &endp, 10);
299 if (endp == str)
301 invalid_stop_date:
302 error (0, 0, _("illegal stopping date in string %d in"
303 " `era' field in category `%s'"),
304 idx + 1, "LC_TIME");
305 (void) strsep (&str, ":");
307 else if (*endp != ':')
309 garbage_stop_date:
310 error (0, 0, _("garbage at end of stopping date in string %d"
311 " in `era' field in category `%s'"),
312 idx + 1, "LC_TIME");
313 (void) strsep (&str, ":");
315 else
317 str = endp + 1;
319 /* Check for valid value. */
320 if (time->era_entries[idx].stop_date[1] < 0
321 || time->era_entries[idx].stop_date[1] >= 12
322 || time->era_entries[idx].stop_date[2] < 0
323 || (time->era_entries[idx].stop_date[2]
324 > days_per_month[time->era_entries[idx].stop_date[1]])
325 || (time->era_entries[idx].stop_date[1] == 2
326 && time->era_entries[idx].stop_date[2] == 29
327 && !__isleap (time->era_entries[idx].stop_date[0])))
328 error (0, 0, _("stopping date is illegal in"
329 " string %d in `era' field in"
330 " category `%s'"),
331 idx + 1, "LC_TIME");
335 if (str == NULL || *str == '\0')
337 error (0, 0, _("missing era name in string %d in `era' field"
338 "in category `%s'"), idx + 1, "LC_TIME");
339 time->era_entries[idx].name =
340 time->era_entries[idx].format = "";
342 else
344 time->era_entries[idx].name = strsep (&str, ":");
346 if (str == NULL || *str == '\0')
348 error (0, 0, _("missing era format in string %d in `era'"
349 " field in category `%s'"),
350 idx + 1, "LC_TIME");
351 time->era_entries[idx].name =
352 time->era_entries[idx].format = "";
354 else
355 time->era_entries[idx].format = str;
359 /* Construct the array for the other byte order. */
360 time->era_entries_ob =
361 (struct era_data *) xmalloc (time->cur_num_era
362 * sizeof (struct era_data));
364 for (idx = 0; idx < time->cur_num_era; ++idx)
366 time->era_entries_ob[idx].direction =
367 SWAPU32 (time->era_entries[idx].direction);
368 time->era_entries_ob[idx].offset =
369 SWAPU32 (time->era_entries[idx].offset);
370 time->era_entries_ob[idx].start_date[0] =
371 SWAPU32 (time->era_entries[idx].start_date[0]);
372 time->era_entries_ob[idx].start_date[1] =
373 SWAPU32 (time->era_entries[idx].start_date[1]);
374 time->era_entries_ob[idx].start_date[2] =
375 SWAPU32 (time->era_entries[idx].stop_date[2]);
376 time->era_entries_ob[idx].stop_date[0] =
377 SWAPU32 (time->era_entries[idx].stop_date[0]);
378 time->era_entries_ob[idx].stop_date[1] =
379 SWAPU32 (time->era_entries[idx].stop_date[1]);
380 time->era_entries_ob[idx].stop_date[2] =
381 SWAPU32 (time->era_entries[idx].stop_date[2]);
382 time->era_entries_ob[idx].name =
383 time->era_entries[idx].name;
384 time->era_entries_ob[idx].format =
385 time->era_entries[idx].format;
391 void
392 time_output (struct localedef_t *locale, const char *output_path)
394 struct locale_time_t *time = locale->categories[LC_TIME].time;
395 struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME)
396 + time->cur_num_era - 1
397 + time->cur_num_alt_digits - 1
398 + 1 + (time->cur_num_era * 9 - 1) * 2
399 + (time->cur_num_era == 0)];
400 struct locale_file data;
401 u_int32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)];
402 size_t cnt, last_idx, num;
404 if ((locale->binary & (1 << LC_TIME)) != 0)
406 iov[0].iov_base = time;
407 iov[0].iov_len = locale->len[LC_TIME];
409 write_locale_data (output_path, "LC_TIME", 1, iov);
411 return;
414 data.magic = LIMAGIC (LC_TIME);
415 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_TIME);
416 iov[0].iov_base = (void *) &data;
417 iov[0].iov_len = sizeof (data);
419 iov[1].iov_base = (void *) idx;
420 iov[1].iov_len = sizeof (idx);
422 idx[0] = iov[0].iov_len + iov[1].iov_len;
424 /* The ab'days. */
425 for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
427 iov[2 + cnt].iov_base =
428 (void *) (time->abday[cnt - _NL_ITEM_INDEX (ABDAY_1)] ?: "");
429 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
430 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
433 /* The days. */
434 for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
436 iov[2 + cnt].iov_base =
437 (void *) (time->day[cnt - _NL_ITEM_INDEX (DAY_1)] ?: "");
438 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
439 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
442 /* The ab'mons. */
443 for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
445 iov[2 + cnt].iov_base =
446 (void *) (time->abmon[cnt - _NL_ITEM_INDEX (ABMON_1)] ?: "");
447 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
448 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
451 /* The mons. */
452 for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
454 iov[2 + cnt].iov_base =
455 (void *) (time->mon[cnt - _NL_ITEM_INDEX (MON_1)] ?: "");
456 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
457 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
460 /* AM/PM. */
461 for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
463 iov[2 + cnt].iov_base =
464 (void *) (time->am_pm[cnt - _NL_ITEM_INDEX (AM_STR)] ?: "");
465 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
466 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
469 iov[2 + cnt].iov_base = (void *) (time->d_t_fmt ?: "");
470 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
471 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
472 ++cnt;
474 iov[2 + cnt].iov_base = (void *) (time->d_fmt ?: "");
475 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
476 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
477 ++cnt;
479 iov[2 + cnt].iov_base = (void *) (time->t_fmt ?: "");
480 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
481 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
482 ++cnt;
484 iov[2 + cnt].iov_base = (void *) (time->t_fmt_ampm ?: "");
485 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
486 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
487 last_idx = ++cnt;
489 idx[1 + last_idx] = idx[last_idx];
490 for (num = 0; num < time->cur_num_era; ++num, ++cnt)
492 iov[2 + cnt].iov_base = (void *) time->era[num];
493 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
494 idx[1 + last_idx] += iov[2 + cnt].iov_len;
496 ++last_idx;
498 iov[2 + cnt].iov_base = (void *) (time->era_year ?: "");
499 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
500 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
501 ++cnt;
502 ++last_idx;
504 iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
505 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
506 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
507 ++cnt;
508 ++last_idx;
510 idx[1 + last_idx] = idx[last_idx];
511 for (num = 0; num < time->cur_num_alt_digits; ++num, ++cnt)
513 iov[2 + cnt].iov_base = (void *) (time->alt_digits[num] ?: "");
514 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
515 idx[1 + last_idx] += iov[2 + cnt].iov_len;
517 ++last_idx;
519 iov[2 + cnt].iov_base = (void *) (time->era_d_t_fmt ?: "");
520 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
521 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
522 ++cnt;
523 ++last_idx;
525 iov[2 + cnt].iov_base = (void *) (time->era_t_fmt ?: "");
526 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
527 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
528 ++cnt;
529 ++last_idx;
532 /* We must align the following data. */
533 iov[2 + cnt].iov_base = (void *) "\0\0";
534 iov[2 + cnt].iov_len = ((idx[last_idx] + 3) & ~3) - idx[last_idx];
535 idx[last_idx] = (idx[last_idx] + 3) & ~3;
536 ++cnt;
538 iov[2 + cnt].iov_base = (void *) &time->cur_num_alt_digits;
539 iov[2 + cnt].iov_len = sizeof (u_int32_t);
540 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
541 ++cnt;
542 ++last_idx;
544 /* The `era' data in usable form. */
545 iov[2 + cnt].iov_base = (void *) &time->cur_num_era;
546 iov[2 + cnt].iov_len = sizeof (u_int32_t);
547 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
548 ++cnt;
549 ++last_idx;
551 #if __BYTE_ORDER == __LITTLE_ENDIAN
552 # define ERA_B1 time->era_entries_ob
553 # define ERA_B2 time->era_entries
554 #else
555 # define ERA_B1 time->era_entries
556 # define ERA_B2 time->era_entries_ob
557 #endif
558 idx[1 + last_idx] = idx[last_idx];
559 for (num = 0; num < time->cur_num_era; ++num)
561 size_t l;
563 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].direction;
564 iov[2 + cnt].iov_len = sizeof (int32_t);
565 ++cnt;
566 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].offset;
567 iov[2 + cnt].iov_len = sizeof (int32_t);
568 ++cnt;
569 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].start_date[0];
570 iov[2 + cnt].iov_len = sizeof (int32_t);
571 ++cnt;
572 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].start_date[1];
573 iov[2 + cnt].iov_len = sizeof (int32_t);
574 ++cnt;
575 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].start_date[2];
576 iov[2 + cnt].iov_len = sizeof (int32_t);
577 ++cnt;
578 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].stop_date[0];
579 iov[2 + cnt].iov_len = sizeof (int32_t);
580 ++cnt;
581 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].stop_date[1];
582 iov[2 + cnt].iov_len = sizeof (int32_t);
583 ++cnt;
584 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].stop_date[2];
585 iov[2 + cnt].iov_len = sizeof (int32_t);
586 ++cnt;
588 l = (strchr (ERA_B1[num].format, '\0') - ERA_B1[num].name) + 1;
589 l = (l + 3) & ~3;
590 iov[2 + cnt].iov_base = (void *) ERA_B1[num].name;
591 iov[2 + cnt].iov_len = l;
592 ++cnt;
594 idx[1 + last_idx] += 8 * sizeof (int32_t) + l;
596 assert (idx[1 + last_idx] % 4 == 0);
598 ++last_idx;
600 /* idx[1 + last_idx] = idx[last_idx]; */
601 for (num = 0; num < time->cur_num_era; ++num)
603 size_t l;
605 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].direction;
606 iov[2 + cnt].iov_len = sizeof (int32_t);
607 ++cnt;
608 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].offset;
609 iov[2 + cnt].iov_len = sizeof (int32_t);
610 ++cnt;
611 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].start_date[0];
612 iov[2 + cnt].iov_len = sizeof (int32_t);
613 ++cnt;
614 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].start_date[1];
615 iov[2 + cnt].iov_len = sizeof (int32_t);
616 ++cnt;
617 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].start_date[2];
618 iov[2 + cnt].iov_len = sizeof (int32_t);
619 ++cnt;
620 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].stop_date[0];
621 iov[2 + cnt].iov_len = sizeof (int32_t);
622 ++cnt;
623 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].stop_date[1];
624 iov[2 + cnt].iov_len = sizeof (int32_t);
625 ++cnt;
626 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].stop_date[2];
627 iov[2 + cnt].iov_len = sizeof (int32_t);
628 ++cnt;
630 l = (strchr (ERA_B2[num].format, '\0') - ERA_B2[num].name) + 1;
631 l = (l + 3) & ~3;
632 iov[2 + cnt].iov_base = (void *) ERA_B2[num].name;
633 iov[2 + cnt].iov_len = l;
634 ++cnt;
636 /* idx[1 + last_idx] += 8 * sizeof (int32_t) + l; */
639 /* We have a problem when no era data is present. In this case the
640 data pointer for _NL_TIME_ERA_ENTRIES_EB and
641 _NL_TIME_ERA_ENTRIES_EL point after the end of the file. So we
642 introduce some dummy data here. */
643 if (time->cur_num_era == 0)
645 static u_int32_t dummy = 0;
646 iov[2 + cnt].iov_base = (void *) &dummy;
647 iov[2 + cnt].iov_len = 4;
648 ++cnt;
651 assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME)
652 + time->cur_num_era - 1
653 + time->cur_num_alt_digits - 1
654 + 1 + (time->cur_num_era * 9 - 1) * 2
655 + (time->cur_num_era == 0))
656 && last_idx + 1 == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
658 write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
662 void
663 time_add (struct linereader *lr, struct localedef_t *locale,
664 enum token_t tok, struct token *code,
665 struct charset_t *charset)
667 struct locale_time_t *time = locale->categories[LC_TIME].time;
669 switch (tok)
671 #define STRARR_ELEM(cat, max) \
672 case tok_##cat: \
673 if (time->cur_num_##cat >= max) \
674 lr_error (lr, _("\
675 too many values for field `%s' in category `LC_TIME'"), \
676 #cat, "LC_TIME"); \
677 else if (code->val.str.start == NULL) \
679 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
680 #cat, "LC_TIME"); \
681 time->cat[time->cur_num_##cat++] = ""; \
683 else \
684 time->cat[time->cur_num_##cat++] = code->val.str.start; \
685 break
687 STRARR_ELEM (abday, 7);
688 STRARR_ELEM (day, 7);
689 STRARR_ELEM (abmon, 12);
690 STRARR_ELEM (mon, 12);
691 STRARR_ELEM (am_pm, 2);
692 STRARR_ELEM (alt_digits, 100);
694 case tok_era:
695 if (code->val.str.start == NULL)
696 lr_error (lr, _("unknown character in field `%s' of category `%s'"),
697 "era", "LC_TIME");
698 else
700 ++time->cur_num_era;
701 time->era = xrealloc (time->era,
702 time->cur_num_era * sizeof (char *));
703 time->era[time->cur_num_era - 1] = code->val.str.start;
705 break;
707 #define STR_ELEM(cat) \
708 case tok_##cat: \
709 if (time->cat != NULL) \
710 lr_error (lr, _("\
711 field `%s' in category `%s' declared more than once"), \
712 #cat, "LC_TIME"); \
713 else if (code->val.str.start == NULL) \
715 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
716 #cat, "LC_TIME"); \
717 time->cat = ""; \
719 else \
720 time->cat = code->val.str.start; \
721 break
723 STR_ELEM (d_t_fmt);
724 STR_ELEM (d_fmt);
725 STR_ELEM (t_fmt);
726 STR_ELEM (t_fmt_ampm);
727 STR_ELEM (era_year);
728 STR_ELEM (era_d_t_fmt);
729 STR_ELEM (era_d_fmt);
730 STR_ELEM (era_t_fmt);
732 default:
733 assert (! "unknown token in category `LC_TIME': should not happen");