(LINE_PARSER): Use pointer of correct type for map_v4v6_hostent call.
[glibc/history.git] / locale / programs / ld-time.c
blob31ff6ffe8587384b22ec1fff1960da5e492c52c9
1 /* Copyright (C) 1995, 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>, 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. */
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 && !be_quiet) \
110 error (0, 0, _("field `%s' in category `%s' not defined"), \
111 #cat, "LC_TIME"); \
112 else if (time->cur_num_##cat != max && !be_quiet) \
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 && !be_quiet) \
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 != '-' && !be_quiet)
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 != ':' && !be_quiet)
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 && !be_quiet)
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 != ':' && !be_quiet)
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 && !be_quiet)
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 != ':' && !be_quiet)
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 && !be_quiet)
257 error (0, 0, _("starting date is illegal in"
258 " string %d in `era' field in"
259 " category `%s'"),
260 idx + 1, "LC_TIME");
264 /* Next is the stopping date in ISO format. */
265 if (strncmp (str, "-*", 2) == 0)
267 time->era_entries[idx].stop_date[0] =
268 time->era_entries[idx].stop_date[1] =
269 time->era_entries[idx].stop_date[2] = 0x80000000;
270 if (str[2] != ':')
271 goto garbage_stop_date;
272 str += 3;
274 else if (strncmp (str, "+*", 2) == 0)
276 time->era_entries[idx].stop_date[0] =
277 time->era_entries[idx].stop_date[1] =
278 time->era_entries[idx].stop_date[2] = 0x7fffffff;
279 if (str[2] != ':')
280 goto garbage_stop_date;
281 str += 3;
283 else
285 time->era_entries[idx].stop_date[0] = strtol (str, &endp, 10);
286 if (endp == str || *endp != '/')
287 goto invalid_stop_date;
288 else
289 str = endp + 1;
290 time->era_entries[idx].stop_date[0] -= 1900;
292 time->era_entries[idx].stop_date[1] = strtol (str, &endp, 10);
293 if (endp == str || *endp != '/')
294 goto invalid_stop_date;
295 else
296 str = endp + 1;
297 time->era_entries[idx].stop_date[1] -= 1;
299 time->era_entries[idx].stop_date[2] = strtol (str, &endp, 10);
300 if (endp == str && !be_quiet)
302 invalid_stop_date:
303 error (0, 0, _("illegal stopping date in string %d in"
304 " `era' field in category `%s'"),
305 idx + 1, "LC_TIME");
306 (void) strsep (&str, ":");
308 else if (*endp != ':' && !be_quiet)
310 garbage_stop_date:
311 error (0, 0, _("garbage at end of stopping date in string %d"
312 " in `era' field in category `%s'"),
313 idx + 1, "LC_TIME");
314 (void) strsep (&str, ":");
316 else
318 str = endp + 1;
320 /* Check for valid value. */
321 if ((time->era_entries[idx].stop_date[1] < 0
322 || time->era_entries[idx].stop_date[1] >= 12
323 || time->era_entries[idx].stop_date[2] < 0
324 || (time->era_entries[idx].stop_date[2]
325 > days_per_month[time->era_entries[idx].stop_date[1]])
326 || (time->era_entries[idx].stop_date[1] == 2
327 && time->era_entries[idx].stop_date[2] == 29
328 && !__isleap (time->era_entries[idx].stop_date[0])))
329 && !be_quiet)
330 error (0, 0, _("stopping date is illegal in"
331 " string %d in `era' field in"
332 " category `%s'"),
333 idx + 1, "LC_TIME");
337 if ((str == NULL || *str == '\0') && !be_quiet)
339 error (0, 0, _("missing era name in string %d in `era' field"
340 " in category `%s'"), idx + 1, "LC_TIME");
341 time->era_entries[idx].name =
342 time->era_entries[idx].format = "";
344 else
346 time->era_entries[idx].name = strsep (&str, ":");
348 if ((str == NULL || *str == '\0') && !be_quiet)
350 error (0, 0, _("missing era format in string %d in `era'"
351 " field in category `%s'"),
352 idx + 1, "LC_TIME");
353 time->era_entries[idx].name =
354 time->era_entries[idx].format = "";
356 else
357 time->era_entries[idx].format = str;
361 /* Construct the array for the other byte order. */
362 time->era_entries_ob =
363 (struct era_data *) xmalloc (time->cur_num_era
364 * sizeof (struct era_data));
366 for (idx = 0; idx < time->cur_num_era; ++idx)
368 time->era_entries_ob[idx].direction =
369 SWAPU32 (time->era_entries[idx].direction);
370 time->era_entries_ob[idx].offset =
371 SWAPU32 (time->era_entries[idx].offset);
372 time->era_entries_ob[idx].start_date[0] =
373 SWAPU32 (time->era_entries[idx].start_date[0]);
374 time->era_entries_ob[idx].start_date[1] =
375 SWAPU32 (time->era_entries[idx].start_date[1]);
376 time->era_entries_ob[idx].start_date[2] =
377 SWAPU32 (time->era_entries[idx].stop_date[2]);
378 time->era_entries_ob[idx].stop_date[0] =
379 SWAPU32 (time->era_entries[idx].stop_date[0]);
380 time->era_entries_ob[idx].stop_date[1] =
381 SWAPU32 (time->era_entries[idx].stop_date[1]);
382 time->era_entries_ob[idx].stop_date[2] =
383 SWAPU32 (time->era_entries[idx].stop_date[2]);
384 time->era_entries_ob[idx].name =
385 time->era_entries[idx].name;
386 time->era_entries_ob[idx].format =
387 time->era_entries[idx].format;
393 void
394 time_output (struct localedef_t *locale, const char *output_path)
396 struct locale_time_t *time = locale->categories[LC_TIME].time;
397 struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME)
398 + time->cur_num_era - 1
399 + time->cur_num_alt_digits - 1
400 + 1 + (time->cur_num_era * 9 - 1) * 2
401 + (time->cur_num_era == 0)];
402 struct locale_file data;
403 u_int32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)];
404 size_t cnt, last_idx, num;
406 if ((locale->binary & (1 << LC_TIME)) != 0)
408 iov[0].iov_base = time;
409 iov[0].iov_len = locale->len[LC_TIME];
411 write_locale_data (output_path, "LC_TIME", 1, iov);
413 return;
416 data.magic = LIMAGIC (LC_TIME);
417 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_TIME);
418 iov[0].iov_base = (void *) &data;
419 iov[0].iov_len = sizeof (data);
421 iov[1].iov_base = (void *) idx;
422 iov[1].iov_len = sizeof (idx);
424 idx[0] = iov[0].iov_len + iov[1].iov_len;
426 /* The ab'days. */
427 for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
429 iov[2 + cnt].iov_base =
430 (void *) (time->abday[cnt - _NL_ITEM_INDEX (ABDAY_1)] ?: "");
431 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
432 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
435 /* The days. */
436 for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
438 iov[2 + cnt].iov_base =
439 (void *) (time->day[cnt - _NL_ITEM_INDEX (DAY_1)] ?: "");
440 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
441 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
444 /* The ab'mons. */
445 for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
447 iov[2 + cnt].iov_base =
448 (void *) (time->abmon[cnt - _NL_ITEM_INDEX (ABMON_1)] ?: "");
449 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
450 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
453 /* The mons. */
454 for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
456 iov[2 + cnt].iov_base =
457 (void *) (time->mon[cnt - _NL_ITEM_INDEX (MON_1)] ?: "");
458 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
459 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
462 /* AM/PM. */
463 for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
465 iov[2 + cnt].iov_base =
466 (void *) (time->am_pm[cnt - _NL_ITEM_INDEX (AM_STR)] ?: "");
467 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
468 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
471 iov[2 + cnt].iov_base = (void *) (time->d_t_fmt ?: "");
472 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
473 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
474 ++cnt;
476 iov[2 + cnt].iov_base = (void *) (time->d_fmt ?: "");
477 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
478 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
479 ++cnt;
481 iov[2 + cnt].iov_base = (void *) (time->t_fmt ?: "");
482 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
483 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
484 ++cnt;
486 iov[2 + cnt].iov_base = (void *) (time->t_fmt_ampm ?: "");
487 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
488 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
489 last_idx = ++cnt;
491 idx[1 + last_idx] = idx[last_idx];
492 for (num = 0; num < time->cur_num_era; ++num, ++cnt)
494 iov[2 + cnt].iov_base = (void *) time->era[num];
495 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
496 idx[1 + last_idx] += iov[2 + cnt].iov_len;
498 ++last_idx;
500 iov[2 + cnt].iov_base = (void *) (time->era_year ?: "");
501 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
502 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
503 ++cnt;
504 ++last_idx;
506 iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
507 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
508 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
509 ++cnt;
510 ++last_idx;
512 idx[1 + last_idx] = idx[last_idx];
513 for (num = 0; num < time->cur_num_alt_digits; ++num, ++cnt)
515 iov[2 + cnt].iov_base = (void *) (time->alt_digits[num] ?: "");
516 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
517 idx[1 + last_idx] += iov[2 + cnt].iov_len;
519 ++last_idx;
521 iov[2 + cnt].iov_base = (void *) (time->era_d_t_fmt ?: "");
522 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
523 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
524 ++cnt;
525 ++last_idx;
527 iov[2 + cnt].iov_base = (void *) (time->era_t_fmt ?: "");
528 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
529 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
530 ++cnt;
531 ++last_idx;
534 /* We must align the following data. */
535 iov[2 + cnt].iov_base = (void *) "\0\0";
536 iov[2 + cnt].iov_len = ((idx[last_idx] + 3) & ~3) - idx[last_idx];
537 idx[last_idx] = (idx[last_idx] + 3) & ~3;
538 ++cnt;
540 iov[2 + cnt].iov_base = (void *) &time->cur_num_alt_digits;
541 iov[2 + cnt].iov_len = sizeof (u_int32_t);
542 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
543 ++cnt;
544 ++last_idx;
546 /* The `era' data in usable form. */
547 iov[2 + cnt].iov_base = (void *) &time->cur_num_era;
548 iov[2 + cnt].iov_len = sizeof (u_int32_t);
549 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
550 ++cnt;
551 ++last_idx;
553 #if __BYTE_ORDER == __LITTLE_ENDIAN
554 # define ERA_B1 time->era_entries_ob
555 # define ERA_B2 time->era_entries
556 #else
557 # define ERA_B1 time->era_entries
558 # define ERA_B2 time->era_entries_ob
559 #endif
560 idx[1 + last_idx] = idx[last_idx];
561 for (num = 0; num < time->cur_num_era; ++num)
563 size_t l;
565 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].direction;
566 iov[2 + cnt].iov_len = sizeof (int32_t);
567 ++cnt;
568 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].offset;
569 iov[2 + cnt].iov_len = sizeof (int32_t);
570 ++cnt;
571 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].start_date[0];
572 iov[2 + cnt].iov_len = sizeof (int32_t);
573 ++cnt;
574 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].start_date[1];
575 iov[2 + cnt].iov_len = sizeof (int32_t);
576 ++cnt;
577 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].start_date[2];
578 iov[2 + cnt].iov_len = sizeof (int32_t);
579 ++cnt;
580 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].stop_date[0];
581 iov[2 + cnt].iov_len = sizeof (int32_t);
582 ++cnt;
583 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].stop_date[1];
584 iov[2 + cnt].iov_len = sizeof (int32_t);
585 ++cnt;
586 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].stop_date[2];
587 iov[2 + cnt].iov_len = sizeof (int32_t);
588 ++cnt;
590 l = (strchr (ERA_B1[num].format, '\0') - ERA_B1[num].name) + 1;
591 l = (l + 3) & ~3;
592 iov[2 + cnt].iov_base = (void *) ERA_B1[num].name;
593 iov[2 + cnt].iov_len = l;
594 ++cnt;
596 idx[1 + last_idx] += 8 * sizeof (int32_t) + l;
598 assert (idx[1 + last_idx] % 4 == 0);
600 ++last_idx;
602 /* idx[1 + last_idx] = idx[last_idx]; */
603 for (num = 0; num < time->cur_num_era; ++num)
605 size_t l;
607 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].direction;
608 iov[2 + cnt].iov_len = sizeof (int32_t);
609 ++cnt;
610 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].offset;
611 iov[2 + cnt].iov_len = sizeof (int32_t);
612 ++cnt;
613 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].start_date[0];
614 iov[2 + cnt].iov_len = sizeof (int32_t);
615 ++cnt;
616 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].start_date[1];
617 iov[2 + cnt].iov_len = sizeof (int32_t);
618 ++cnt;
619 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].start_date[2];
620 iov[2 + cnt].iov_len = sizeof (int32_t);
621 ++cnt;
622 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].stop_date[0];
623 iov[2 + cnt].iov_len = sizeof (int32_t);
624 ++cnt;
625 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].stop_date[1];
626 iov[2 + cnt].iov_len = sizeof (int32_t);
627 ++cnt;
628 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].stop_date[2];
629 iov[2 + cnt].iov_len = sizeof (int32_t);
630 ++cnt;
632 l = (strchr (ERA_B2[num].format, '\0') - ERA_B2[num].name) + 1;
633 l = (l + 3) & ~3;
634 iov[2 + cnt].iov_base = (void *) ERA_B2[num].name;
635 iov[2 + cnt].iov_len = l;
636 ++cnt;
638 /* idx[1 + last_idx] += 8 * sizeof (int32_t) + l; */
641 /* We have a problem when no era data is present. In this case the
642 data pointer for _NL_TIME_ERA_ENTRIES_EB and
643 _NL_TIME_ERA_ENTRIES_EL point after the end of the file. So we
644 introduce some dummy data here. */
645 if (time->cur_num_era == 0)
647 static u_int32_t dummy = 0;
648 iov[2 + cnt].iov_base = (void *) &dummy;
649 iov[2 + cnt].iov_len = 4;
650 ++cnt;
653 assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME)
654 + time->cur_num_era - 1
655 + time->cur_num_alt_digits - 1
656 + 1 + (time->cur_num_era * 9 - 1) * 2
657 + (time->cur_num_era == 0))
658 && last_idx + 1 == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
660 write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
664 void
665 time_add (struct linereader *lr, struct localedef_t *locale,
666 enum token_t tok, struct token *code,
667 struct charset_t *charset)
669 struct locale_time_t *time = locale->categories[LC_TIME].time;
671 switch (tok)
673 #define STRARR_ELEM(cat, max) \
674 case tok_##cat: \
675 if (time->cur_num_##cat >= max) \
676 lr_error (lr, _("\
677 too many values for field `%s' in category `%s'"), \
678 #cat, "LC_TIME"); \
679 else if (code->val.str.start == NULL) \
681 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
682 #cat, "LC_TIME"); \
683 time->cat[time->cur_num_##cat++] = ""; \
685 else \
686 time->cat[time->cur_num_##cat++] = code->val.str.start; \
687 break
689 STRARR_ELEM (abday, 7);
690 STRARR_ELEM (day, 7);
691 STRARR_ELEM (abmon, 12);
692 STRARR_ELEM (mon, 12);
693 STRARR_ELEM (am_pm, 2);
694 STRARR_ELEM (alt_digits, 100);
696 case tok_era:
697 if (code->val.str.start == NULL)
698 lr_error (lr, _("unknown character in field `%s' of category `%s'"),
699 "era", "LC_TIME");
700 else
702 ++time->cur_num_era;
703 time->era = xrealloc (time->era,
704 time->cur_num_era * sizeof (char *));
705 time->era[time->cur_num_era - 1] = code->val.str.start;
707 break;
709 #define STR_ELEM(cat) \
710 case tok_##cat: \
711 if (time->cat != NULL) \
712 lr_error (lr, _("\
713 field `%s' in category `%s' declared more than once"), \
714 #cat, "LC_TIME"); \
715 else if (code->val.str.start == NULL) \
717 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
718 #cat, "LC_TIME"); \
719 time->cat = ""; \
721 else \
722 time->cat = code->val.str.start; \
723 break
725 STR_ELEM (d_t_fmt);
726 STR_ELEM (d_fmt);
727 STR_ELEM (t_fmt);
728 STR_ELEM (t_fmt_ampm);
729 STR_ELEM (era_year);
730 STR_ELEM (era_d_t_fmt);
731 STR_ELEM (era_d_fmt);
732 STR_ELEM (era_t_fmt);
734 default:
735 assert (! "unknown token in category `LC_TIME': should not happen");