]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/programs/ld-time.c
Update to 2.1.x development version
[thirdparty/glibc.git] / locale / programs / ld-time.c
CommitLineData
5290baf0 1/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
6d52618b 2 This file is part of the GNU C Library.
5290baf0 3 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
19bc17a9 4
6d52618b
UD
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.
19bc17a9 9
6d52618b
UD
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.
19bc17a9 14
6d52618b
UD
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. */
19bc17a9
RM
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <langinfo.h>
25#include <string.h>
26
27/* Undefine following line in production version. */
28/* #define NDEBUG 1 */
29#include <assert.h>
c4029823 30#include <stdlib.h>
19bc17a9
RM
31
32#include "locales.h"
33#include "localeinfo.h"
34#include "stringtrans.h"
35
c4029823
UD
36#define SWAPU32(w) \
37 (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
38
19bc17a9
RM
39
40void *xmalloc (size_t __n);
ec4b0518 41void *xrealloc (void *__p, size_t __n);
19bc17a9
RM
42
43
c4029823
UD
44/* Entry describing an entry of the era specification. */
45struct era_data
46{
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;
53};
54
55
19bc17a9
RM
56/* The real definition of the struct for the LC_TIME locale. */
57struct locale_time_t
58{
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;
ec4b0518 73 const char **era;
c4029823 74 u_int32_t cur_num_era;
19bc17a9
RM
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];
c4029823
UD
80 u_int32_t cur_num_alt_digits;
81
82 struct era_data *era_entries;
83 struct era_data *era_entries_ob;
19bc17a9
RM
84};
85
86
87void
88time_startup (struct linereader *lr, struct localedef_t *locale,
89 struct charset_t *charset)
90{
91 struct locale_time_t *time;
92
93 /* It is important that we always use UCS1 encoding for strings now. */
94 encoding_method = ENC_UCS1;
95
96 locale->categories[LC_TIME].time = time =
97 (struct locale_time_t *) xmalloc (sizeof (struct locale_time_t));
98
99 memset (time, '\0', sizeof (struct locale_time_t));
100}
101
102
103void
104time_finish (struct localedef_t *locale)
105{
106 struct locale_time_t *time = locale->categories[LC_TIME].time;
107
108#define TESTARR_ELEM(cat, max) \
c84142e8 109 if (time->cur_num_##cat == 0 && !be_quiet) \
19bc17a9
RM
110 error (0, 0, _("field `%s' in category `%s' not defined"), \
111 #cat, "LC_TIME"); \
c84142e8 112 else if (time->cur_num_##cat != max && !be_quiet) \
19bc17a9
RM
113 error (0, 0, _("field `%s' in category `%s' has not enough values"), \
114 #cat, "LC_TIME")
115
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);
121
122#define TEST_ELEM(cat) \
c84142e8 123 if (time->cat == NULL && !be_quiet) \
19bc17a9
RM
124 error (0, 0, _("field `%s' in category `%s' not defined"), \
125 #cat, "LC_TIME")
126
127 TEST_ELEM (d_t_fmt);
128 TEST_ELEM (d_fmt);
129 TEST_ELEM (t_fmt);
130 TEST_ELEM (t_fmt_ampm);
c4029823
UD
131
132 /* Now process the era entries. */
133 if (time->cur_num_era != 0)
134 {
135 const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
136 31, 31, 30, 31 ,30, 31 };
137 size_t idx;
138
139 time->era_entries =
140 (struct era_data *) xmalloc (time->cur_num_era
141 * sizeof (struct era_data));
142
143 for (idx = 0; idx < time->cur_num_era; ++idx)
144 {
145 size_t era_len = strlen (time->era[idx]);
146 char *str = xmalloc ((era_len + 1 + 3) & ~3);
147 char *endp;
148
149 memcpy (str, time->era[idx], era_len + 1);
150
151 /* First character must be + or - for the direction. */
c84142e8 152 if (*str != '+' && *str != '-' && !be_quiet)
c4029823
UD
153 {
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 = '+';
159 }
160 else
161 time->era_entries[idx].direction = *str;
c84142e8 162 if (*++str != ':' && !be_quiet)
c4029823
UD
163 {
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, ":");
168 }
169 else
170 ++str;
171
172 /* Now the offset year. */
173 time->era_entries[idx].offset = strtol (str, &endp, 10);
c84142e8 174 if (endp == str && !be_quiet)
c4029823
UD
175 {
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, ":");
180 }
c84142e8 181 else if (*endp != ':' && !be_quiet)
c4029823
UD
182 {
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, ":");
187 }
188 else
189 str = endp + 1;
190
191 /* Next is the starting date in ISO format. */
192 if (strncmp (str, "-*", 2) == 0)
193 {
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;
200 }
201 else if (strncmp (str, "+*", 2) == 0)
202 {
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;
209 }
210 else
211 {
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;
218
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;
225
226 time->era_entries[idx].start_date[2] = strtol (str, &endp, 10);
c84142e8 227 if (endp == str && !be_quiet)
c4029823
UD
228 {
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, ":");
234 }
c84142e8 235 else if (*endp != ':' && !be_quiet)
c4029823
UD
236 {
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, ":");
242 }
243 else
244 {
245 str = endp + 1;
246
247 /* Check for valid value. */
c84142e8
UD
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)
c4029823
UD
257 error (0, 0, _("starting date is illegal in"
258 " string %d in `era' field in"
259 " category `%s'"),
260 idx + 1, "LC_TIME");
261 }
262 }
263
6d52618b 264 /* Next is the stopping date in ISO format. */
c4029823
UD
265 if (strncmp (str, "-*", 2) == 0)
266 {
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;
273 }
274 else if (strncmp (str, "+*", 2) == 0)
275 {
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;
282 }
283 else
284 {
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;
291
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;
298
299 time->era_entries[idx].stop_date[2] = strtol (str, &endp, 10);
c84142e8 300 if (endp == str && !be_quiet)
c4029823
UD
301 {
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, ":");
307 }
c84142e8 308 else if (*endp != ':' && !be_quiet)
c4029823
UD
309 {
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, ":");
315 }
316 else
317 {
318 str = endp + 1;
319
320 /* Check for valid value. */
c84142e8
UD
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)
c4029823
UD
330 error (0, 0, _("stopping date is illegal in"
331 " string %d in `era' field in"
332 " category `%s'"),
333 idx + 1, "LC_TIME");
334 }
335 }
336
c84142e8 337 if ((str == NULL || *str == '\0') && !be_quiet)
c4029823
UD
338 {
339 error (0, 0, _("missing era name in string %d in `era' field"
5290baf0 340 " in category `%s'"), idx + 1, "LC_TIME");
c4029823
UD
341 time->era_entries[idx].name =
342 time->era_entries[idx].format = "";
343 }
344 else
345 {
346 time->era_entries[idx].name = strsep (&str, ":");
347
c84142e8 348 if ((str == NULL || *str == '\0') && !be_quiet)
c4029823
UD
349 {
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 = "";
355 }
356 else
357 time->era_entries[idx].format = str;
358 }
359 }
360
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));
365
366 for (idx = 0; idx < time->cur_num_era; ++idx)
367 {
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;
388 }
389 }
19bc17a9
RM
390}
391
392
393void
394time_output (struct localedef_t *locale, const char *output_path)
395{
396 struct locale_time_t *time = locale->categories[LC_TIME].time;
397 struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME)
c4029823
UD
398 + time->cur_num_era - 1
399 + time->cur_num_alt_digits - 1
a68b0d31
UD
400 + 1 + (time->cur_num_era * 9 - 1) * 2
401 + (time->cur_num_era == 0)];
19bc17a9 402 struct locale_file data;
7a12c6bb 403 u_int32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)];
19bc17a9
RM
404 size_t cnt, last_idx, num;
405
406 if ((locale->binary & (1 << LC_TIME)) != 0)
407 {
408 iov[0].iov_base = time;
409 iov[0].iov_len = locale->len[LC_TIME];
410
411 write_locale_data (output_path, "LC_TIME", 1, iov);
412
413 return;
414 }
415
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);
420
421 iov[1].iov_base = (void *) idx;
422 iov[1].iov_len = sizeof (idx);
423
424 idx[0] = iov[0].iov_len + iov[1].iov_len;
425
426 /* The ab'days. */
427 for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
428 {
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;
433 }
434
435 /* The days. */
436 for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
437 {
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;
442 }
443
444 /* The ab'mons. */
445 for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
446 {
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;
451 }
452
453 /* The mons. */
454 for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
455 {
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;
460 }
461
462 /* AM/PM. */
463 for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
464 {
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;
469 }
470
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;
475
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;
480
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;
485
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;
ec4b0518 489 last_idx = ++cnt;
19bc17a9 490
ec4b0518 491 idx[1 + last_idx] = idx[last_idx];
c4029823 492 for (num = 0; num < time->cur_num_era; ++num, ++cnt)
ec4b0518
UD
493 {
494 iov[2 + cnt].iov_base = (void *) time->era[num];
495 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
c4029823 496 idx[1 + last_idx] += iov[2 + cnt].iov_len;
ec4b0518
UD
497 }
498 ++last_idx;
19bc17a9
RM
499
500 iov[2 + cnt].iov_base = (void *) (time->era_year ?: "");
501 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
ec4b0518 502 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
19bc17a9 503 ++cnt;
ec4b0518 504 ++last_idx;
19bc17a9
RM
505
506 iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
507 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
ec4b0518
UD
508 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
509 ++cnt;
510 ++last_idx;
19bc17a9
RM
511
512 idx[1 + last_idx] = idx[last_idx];
513 for (num = 0; num < time->cur_num_alt_digits; ++num, ++cnt)
514 {
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;
518 }
519 ++last_idx;
520
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;
c4029823 525 ++last_idx;
19bc17a9 526
c4029823 527 iov[2 + cnt].iov_base = (void *) (time->era_t_fmt ?: "");
19bc17a9 528 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
c4029823 529 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
19bc17a9 530 ++cnt;
c4029823
UD
531 ++last_idx;
532
533
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;
539
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;
545
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;
552
553#if __BYTE_ORDER == __LITTLE_ENDIAN
c4029823
UD
554# define ERA_B1 time->era_entries_ob
555# define ERA_B2 time->era_entries
d68171ed
UD
556#else
557# define ERA_B1 time->era_entries
558# define ERA_B2 time->era_entries_ob
c4029823
UD
559#endif
560 idx[1 + last_idx] = idx[last_idx];
561 for (num = 0; num < time->cur_num_era; ++num)
562 {
563 size_t l;
564
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;
589
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;
595
596 idx[1 + last_idx] += 8 * sizeof (int32_t) + l;
597
598 assert (idx[1 + last_idx] % 4 == 0);
599 }
600 ++last_idx;
601
602 /* idx[1 + last_idx] = idx[last_idx]; */
603 for (num = 0; num < time->cur_num_era; ++num)
604 {
605 size_t l;
606
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;
631
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;
637
638 /* idx[1 + last_idx] += 8 * sizeof (int32_t) + l; */
639 }
640
a68b0d31
UD
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)
646 {
647 static u_int32_t dummy = 0;
648 iov[2 + cnt].iov_base = (void *) &dummy;
649 iov[2 + cnt].iov_len = 4;
650 ++cnt;
651 }
19bc17a9 652
c4029823
UD
653 assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME)
654 + time->cur_num_era - 1
655 + time->cur_num_alt_digits - 1
a68b0d31
UD
656 + 1 + (time->cur_num_era * 9 - 1) * 2
657 + (time->cur_num_era == 0))
c4029823 658 && last_idx + 1 == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
19bc17a9
RM
659
660 write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
661}
662
663
664void
665time_add (struct linereader *lr, struct localedef_t *locale,
666 enum token_t tok, struct token *code,
667 struct charset_t *charset)
668{
669 struct locale_time_t *time = locale->categories[LC_TIME].time;
670
671 switch (tok)
672 {
673#define STRARR_ELEM(cat, max) \
674 case tok_##cat: \
675 if (time->cur_num_##cat >= max) \
036cc82f 676 lr_error (lr, _("\
ba1ffaa1 677too many values for field `%s' in category `%s'"), \
19bc17a9
RM
678 #cat, "LC_TIME"); \
679 else if (code->val.str.start == NULL) \
680 { \
681 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
682 #cat, "LC_TIME"); \
683 time->cat[time->cur_num_##cat++] = ""; \
684 } \
685 else \
ec4b0518 686 time->cat[time->cur_num_##cat++] = code->val.str.start; \
19bc17a9
RM
687 break
688
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);
695
ec4b0518
UD
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
701 {
c4029823
UD
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;
ec4b0518
UD
706 }
707 break;
708
19bc17a9
RM
709#define STR_ELEM(cat) \
710 case tok_##cat: \
711 if (time->cat != NULL) \
712 lr_error (lr, _("\
713field `%s' in category `%s' declared more than once"), \
714 #cat, "LC_TIME"); \
715 else if (code->val.str.start == NULL) \
716 { \
717 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
718 #cat, "LC_TIME"); \
719 time->cat = ""; \
720 } \
721 else \
722 time->cat = code->val.str.start; \
723 break
724
725 STR_ELEM (d_t_fmt);
726 STR_ELEM (d_fmt);
727 STR_ELEM (t_fmt);
728 STR_ELEM (t_fmt_ampm);
19bc17a9
RM
729 STR_ELEM (era_year);
730 STR_ELEM (era_d_t_fmt);
731 STR_ELEM (era_d_fmt);
732 STR_ELEM (era_t_fmt);
733
734 default:
735 assert (! "unknown token in category `LC_TIME': should not happen");
736 }
737}