]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/programs/ld-time.c
Update.
[thirdparty/glibc.git] / locale / programs / ld-time.c
CommitLineData
f76d7052 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999 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>
4360eafd 26#include <libintl.h>
19bc17a9
RM
27
28/* Undefine following line in production version. */
29/* #define NDEBUG 1 */
30#include <assert.h>
c4029823 31#include <stdlib.h>
19bc17a9
RM
32
33#include "locales.h"
34#include "localeinfo.h"
35#include "stringtrans.h"
36
c4029823
UD
37#define SWAPU32(w) \
38 (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
39
19bc17a9 40
880f421f
UD
41extern void *xmalloc (size_t __n);
42extern void *xrealloc (void *__p, size_t __n);
19bc17a9
RM
43
44
c4029823
UD
45/* Entry describing an entry of the era specification. */
46struct era_data
47{
48 int32_t direction;
49 int32_t offset;
50 int32_t start_date[3];
51 int32_t stop_date[3];
52 const char *name;
53 const char *format;
54};
55
56
19bc17a9
RM
57/* The real definition of the struct for the LC_TIME locale. */
58struct locale_time_t
59{
60 const char *abday[7];
61 size_t cur_num_abday;
62 const char *day[7];
63 size_t cur_num_day;
64 const char *abmon[12];
65 size_t cur_num_abmon;
66 const char *mon[12];
67 size_t cur_num_mon;
68 const char *am_pm[2];
69 size_t cur_num_am_pm;
70 const char *d_t_fmt;
71 const char *d_fmt;
72 const char *t_fmt;
73 const char *t_fmt_ampm;
ec4b0518 74 const char **era;
c4029823 75 u_int32_t cur_num_era;
19bc17a9
RM
76 const char *era_year;
77 const char *era_d_t_fmt;
78 const char *era_t_fmt;
79 const char *era_d_fmt;
80 const char *alt_digits[100];
c4029823
UD
81 u_int32_t cur_num_alt_digits;
82
83 struct era_data *era_entries;
84 struct era_data *era_entries_ob;
19bc17a9
RM
85};
86
87
88void
89time_startup (struct linereader *lr, struct localedef_t *locale,
90 struct charset_t *charset)
91{
92 struct locale_time_t *time;
93
816e6eb5
UD
94 /* We have a definition for LC_TIME. */
95 copy_posix.mask &= ~(1 << LC_TIME);
96
19bc17a9
RM
97 /* It is important that we always use UCS1 encoding for strings now. */
98 encoding_method = ENC_UCS1;
99
100 locale->categories[LC_TIME].time = time =
101 (struct locale_time_t *) xmalloc (sizeof (struct locale_time_t));
102
103 memset (time, '\0', sizeof (struct locale_time_t));
104}
105
106
107void
108time_finish (struct localedef_t *locale)
109{
110 struct locale_time_t *time = locale->categories[LC_TIME].time;
111
112#define TESTARR_ELEM(cat, max) \
c84142e8 113 if (time->cur_num_##cat == 0 && !be_quiet) \
f1f0edfe 114 error (0, 0, _("field `%s' in category `%s' undefined"), \
19bc17a9 115 #cat, "LC_TIME"); \
c84142e8 116 else if (time->cur_num_##cat != max && !be_quiet) \
19bc17a9
RM
117 error (0, 0, _("field `%s' in category `%s' has not enough values"), \
118 #cat, "LC_TIME")
119
120 TESTARR_ELEM (abday, 7);
121 TESTARR_ELEM (day, 7);
122 TESTARR_ELEM (abmon, 12);
123 TESTARR_ELEM (mon, 12);
124 TESTARR_ELEM (am_pm, 2);
125
126#define TEST_ELEM(cat) \
c84142e8 127 if (time->cat == NULL && !be_quiet) \
f1f0edfe 128 error (0, 0, _("field `%s' in category `%s' undefined"), \
19bc17a9
RM
129 #cat, "LC_TIME")
130
131 TEST_ELEM (d_t_fmt);
132 TEST_ELEM (d_fmt);
133 TEST_ELEM (t_fmt);
5a97622d
UD
134
135 /* According to C.Y.Alexis Cheng <alexis@vnet.ibm.com> the T_FMT_AMPM
136 field is optional. */
137 if (time->t_fmt_ampm == NULL)
138 /* Use the 24h format as default. */
139 time->t_fmt_ampm = time->t_fmt;
c4029823
UD
140
141 /* Now process the era entries. */
142 if (time->cur_num_era != 0)
143 {
144 const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
145 31, 31, 30, 31 ,30, 31 };
146 size_t idx;
147
148 time->era_entries =
149 (struct era_data *) xmalloc (time->cur_num_era
150 * sizeof (struct era_data));
151
152 for (idx = 0; idx < time->cur_num_era; ++idx)
153 {
154 size_t era_len = strlen (time->era[idx]);
155 char *str = xmalloc ((era_len + 1 + 3) & ~3);
156 char *endp;
157
158 memcpy (str, time->era[idx], era_len + 1);
159
160 /* First character must be + or - for the direction. */
880f421f 161 if (*str != '+' && *str != '-')
c4029823 162 {
880f421f
UD
163 if (!be_quiet)
164 error (0, 0, _("direction flag in string %d in `era' field"
165 " in category `%s' is not '+' nor '-'"),
166 idx + 1, "LC_TIME");
c4029823
UD
167 /* Default arbitrarily to '+'. */
168 time->era_entries[idx].direction = '+';
169 }
170 else
171 time->era_entries[idx].direction = *str;
880f421f 172 if (*++str != ':')
c4029823 173 {
880f421f
UD
174 if (!be_quiet)
175 error (0, 0, _("direction flag in string %d in `era' field"
176 " in category `%s' is not a single character"),
177 idx + 1, "LC_TIME");
c4029823
UD
178 (void) strsep (&str, ":");
179 }
180 else
181 ++str;
182
183 /* Now the offset year. */
184 time->era_entries[idx].offset = strtol (str, &endp, 10);
880f421f 185 if (endp == str)
c4029823 186 {
880f421f
UD
187 if (!be_quiet)
188 error (0, 0, _("illegal number for offset in string %d in"
189 " `era' field in category `%s'"),
190 idx + 1, "LC_TIME");
c4029823
UD
191 (void) strsep (&str, ":");
192 }
880f421f 193 else if (*endp != ':')
c4029823 194 {
880f421f
UD
195 if (!be_quiet)
196 error (0, 0, _("garbage at end of offset value in string %d in"
197 " `era' field in category `%s'"),
198 idx + 1, "LC_TIME");
c4029823
UD
199 (void) strsep (&str, ":");
200 }
201 else
202 str = endp + 1;
203
204 /* Next is the starting date in ISO format. */
205 if (strncmp (str, "-*", 2) == 0)
206 {
207 time->era_entries[idx].start_date[0] =
208 time->era_entries[idx].start_date[1] =
209 time->era_entries[idx].start_date[2] = 0x80000000;
210 if (str[2] != ':')
211 goto garbage_start_date;
212 str += 3;
213 }
214 else if (strncmp (str, "+*", 2) == 0)
215 {
216 time->era_entries[idx].start_date[0] =
217 time->era_entries[idx].start_date[1] =
218 time->era_entries[idx].start_date[2] = 0x7fffffff;
219 if (str[2] != ':')
220 goto garbage_start_date;
221 str += 3;
222 }
223 else
224 {
225 time->era_entries[idx].start_date[0] = strtol (str, &endp, 10);
226 if (endp == str || *endp != '/')
227 goto invalid_start_date;
228 else
229 str = endp + 1;
230 time->era_entries[idx].start_date[0] -= 1900;
231
232 time->era_entries[idx].start_date[1] = strtol (str, &endp, 10);
233 if (endp == str || *endp != '/')
234 goto invalid_start_date;
235 else
236 str = endp + 1;
237 time->era_entries[idx].start_date[1] -= 1;
238
239 time->era_entries[idx].start_date[2] = strtol (str, &endp, 10);
880f421f 240 if (endp == str)
c4029823
UD
241 {
242 invalid_start_date:
880f421f
UD
243 if (!be_quiet)
244 error (0, 0, _("illegal starting date in string %d in"
245 " `era' field in category `%s'"),
246 idx + 1, "LC_TIME");
c4029823
UD
247 (void) strsep (&str, ":");
248 }
880f421f 249 else if (*endp != ':')
c4029823
UD
250 {
251 garbage_start_date:
880f421f
UD
252 if (!be_quiet)
253 error (0, 0, _("garbage at end of starting date "
254 "in string %d in `era' field "
255 "in category `%s'"),
256 idx + 1, "LC_TIME");
c4029823
UD
257 (void) strsep (&str, ":");
258 }
259 else
260 {
261 str = endp + 1;
262
263 /* Check for valid value. */
c84142e8
UD
264 if ((time->era_entries[idx].start_date[1] < 0
265 || time->era_entries[idx].start_date[1] >= 12
266 || time->era_entries[idx].start_date[2] < 0
267 || (time->era_entries[idx].start_date[2]
268 > days_per_month[time->era_entries[idx].start_date[1]])
269 || (time->era_entries[idx].start_date[1] == 2
270 && time->era_entries[idx].start_date[2] == 29
271 && !__isleap (time->era_entries[idx].start_date[0])))
272 && !be_quiet)
c4029823
UD
273 error (0, 0, _("starting date is illegal in"
274 " string %d in `era' field in"
275 " category `%s'"),
276 idx + 1, "LC_TIME");
277 }
278 }
279
6d52618b 280 /* Next is the stopping date in ISO format. */
c4029823
UD
281 if (strncmp (str, "-*", 2) == 0)
282 {
283 time->era_entries[idx].stop_date[0] =
284 time->era_entries[idx].stop_date[1] =
285 time->era_entries[idx].stop_date[2] = 0x80000000;
286 if (str[2] != ':')
287 goto garbage_stop_date;
288 str += 3;
289 }
290 else if (strncmp (str, "+*", 2) == 0)
291 {
292 time->era_entries[idx].stop_date[0] =
293 time->era_entries[idx].stop_date[1] =
294 time->era_entries[idx].stop_date[2] = 0x7fffffff;
295 if (str[2] != ':')
296 goto garbage_stop_date;
297 str += 3;
298 }
299 else
300 {
301 time->era_entries[idx].stop_date[0] = strtol (str, &endp, 10);
302 if (endp == str || *endp != '/')
303 goto invalid_stop_date;
304 else
305 str = endp + 1;
306 time->era_entries[idx].stop_date[0] -= 1900;
307
308 time->era_entries[idx].stop_date[1] = strtol (str, &endp, 10);
309 if (endp == str || *endp != '/')
310 goto invalid_stop_date;
311 else
312 str = endp + 1;
313 time->era_entries[idx].stop_date[1] -= 1;
314
315 time->era_entries[idx].stop_date[2] = strtol (str, &endp, 10);
880f421f 316 if (endp == str)
c4029823
UD
317 {
318 invalid_stop_date:
880f421f
UD
319 if (!be_quiet)
320 error (0, 0, _("illegal stopping date in string %d in"
321 " `era' field in category `%s'"),
322 idx + 1, "LC_TIME");
c4029823
UD
323 (void) strsep (&str, ":");
324 }
880f421f 325 else if (*endp != ':')
c4029823
UD
326 {
327 garbage_stop_date:
880f421f
UD
328 if (!be_quiet)
329 error (0, 0, _("garbage at end of stopping date "
330 "in string %d in `era' field "
331 "in category `%s'"),
332 idx + 1, "LC_TIME");
c4029823
UD
333 (void) strsep (&str, ":");
334 }
335 else
336 {
337 str = endp + 1;
338
339 /* Check for valid value. */
c84142e8
UD
340 if ((time->era_entries[idx].stop_date[1] < 0
341 || time->era_entries[idx].stop_date[1] >= 12
342 || time->era_entries[idx].stop_date[2] < 0
343 || (time->era_entries[idx].stop_date[2]
344 > days_per_month[time->era_entries[idx].stop_date[1]])
345 || (time->era_entries[idx].stop_date[1] == 2
346 && time->era_entries[idx].stop_date[2] == 29
347 && !__isleap (time->era_entries[idx].stop_date[0])))
348 && !be_quiet)
c4029823
UD
349 error (0, 0, _("stopping date is illegal in"
350 " string %d in `era' field in"
351 " category `%s'"),
352 idx + 1, "LC_TIME");
353 }
354 }
355
880f421f 356 if (str == NULL || *str == '\0')
c4029823 357 {
880f421f
UD
358 if (!be_quiet)
359 error (0, 0, _("missing era name in string %d in `era' field"
360 " in category `%s'"), idx + 1, "LC_TIME");
f76d7052
UD
361 /* Make sure that name and format are adjacent strings
362 in memory. */
363 time->era_entries[idx].name = "\0";
364 time->era_entries[idx].format
365 = time->era_entries[idx].name + 1;
c4029823
UD
366 }
367 else
368 {
369 time->era_entries[idx].name = strsep (&str, ":");
370
880f421f 371 if (str == NULL || *str == '\0')
c4029823 372 {
880f421f
UD
373 if (!be_quiet)
374 error (0, 0, _("missing era format in string %d in `era'"
375 " field in category `%s'"),
376 idx + 1, "LC_TIME");
f76d7052
UD
377 /* Make sure that name and format are adjacent strings
378 in memory. */
379 time->era_entries[idx].name = "\0";
380 time->era_entries[idx].format
381 = time->era_entries[idx].name + 1;
c4029823
UD
382 }
383 else
384 time->era_entries[idx].format = str;
385 }
386 }
387
388 /* Construct the array for the other byte order. */
389 time->era_entries_ob =
390 (struct era_data *) xmalloc (time->cur_num_era
391 * sizeof (struct era_data));
392
393 for (idx = 0; idx < time->cur_num_era; ++idx)
394 {
395 time->era_entries_ob[idx].direction =
396 SWAPU32 (time->era_entries[idx].direction);
397 time->era_entries_ob[idx].offset =
398 SWAPU32 (time->era_entries[idx].offset);
399 time->era_entries_ob[idx].start_date[0] =
400 SWAPU32 (time->era_entries[idx].start_date[0]);
401 time->era_entries_ob[idx].start_date[1] =
402 SWAPU32 (time->era_entries[idx].start_date[1]);
403 time->era_entries_ob[idx].start_date[2] =
404 SWAPU32 (time->era_entries[idx].stop_date[2]);
405 time->era_entries_ob[idx].stop_date[0] =
406 SWAPU32 (time->era_entries[idx].stop_date[0]);
407 time->era_entries_ob[idx].stop_date[1] =
408 SWAPU32 (time->era_entries[idx].stop_date[1]);
409 time->era_entries_ob[idx].stop_date[2] =
410 SWAPU32 (time->era_entries[idx].stop_date[2]);
411 time->era_entries_ob[idx].name =
412 time->era_entries[idx].name;
413 time->era_entries_ob[idx].format =
414 time->era_entries[idx].format;
415 }
416 }
19bc17a9
RM
417}
418
419
420void
421time_output (struct localedef_t *locale, const char *output_path)
422{
423 struct locale_time_t *time = locale->categories[LC_TIME].time;
424 struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME)
c4029823
UD
425 + time->cur_num_era - 1
426 + time->cur_num_alt_digits - 1
a68b0d31
UD
427 + 1 + (time->cur_num_era * 9 - 1) * 2
428 + (time->cur_num_era == 0)];
19bc17a9 429 struct locale_file data;
7a12c6bb 430 u_int32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)];
19bc17a9
RM
431 size_t cnt, last_idx, num;
432
433 if ((locale->binary & (1 << LC_TIME)) != 0)
434 {
435 iov[0].iov_base = time;
436 iov[0].iov_len = locale->len[LC_TIME];
437
438 write_locale_data (output_path, "LC_TIME", 1, iov);
439
440 return;
441 }
442
443 data.magic = LIMAGIC (LC_TIME);
444 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_TIME);
445 iov[0].iov_base = (void *) &data;
446 iov[0].iov_len = sizeof (data);
447
448 iov[1].iov_base = (void *) idx;
449 iov[1].iov_len = sizeof (idx);
450
451 idx[0] = iov[0].iov_len + iov[1].iov_len;
452
453 /* The ab'days. */
454 for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
455 {
456 iov[2 + cnt].iov_base =
457 (void *) (time->abday[cnt - _NL_ITEM_INDEX (ABDAY_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 /* The days. */
463 for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
464 {
465 iov[2 + cnt].iov_base =
466 (void *) (time->day[cnt - _NL_ITEM_INDEX (DAY_1)] ?: "");
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 /* The ab'mons. */
472 for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
473 {
474 iov[2 + cnt].iov_base =
475 (void *) (time->abmon[cnt - _NL_ITEM_INDEX (ABMON_1)] ?: "");
476 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
477 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
478 }
479
480 /* The mons. */
481 for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
482 {
483 iov[2 + cnt].iov_base =
484 (void *) (time->mon[cnt - _NL_ITEM_INDEX (MON_1)] ?: "");
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 }
488
489 /* AM/PM. */
490 for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
491 {
492 iov[2 + cnt].iov_base =
493 (void *) (time->am_pm[cnt - _NL_ITEM_INDEX (AM_STR)] ?: "");
494 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
495 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
496 }
497
498 iov[2 + cnt].iov_base = (void *) (time->d_t_fmt ?: "");
499 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
500 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
501 ++cnt;
502
503 iov[2 + cnt].iov_base = (void *) (time->d_fmt ?: "");
504 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
505 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
506 ++cnt;
507
508 iov[2 + cnt].iov_base = (void *) (time->t_fmt ?: "");
509 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
510 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
511 ++cnt;
512
513 iov[2 + cnt].iov_base = (void *) (time->t_fmt_ampm ?: "");
514 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
515 idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
ec4b0518 516 last_idx = ++cnt;
19bc17a9 517
ec4b0518 518 idx[1 + last_idx] = idx[last_idx];
c4029823 519 for (num = 0; num < time->cur_num_era; ++num, ++cnt)
ec4b0518
UD
520 {
521 iov[2 + cnt].iov_base = (void *) time->era[num];
522 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
c4029823 523 idx[1 + last_idx] += iov[2 + cnt].iov_len;
ec4b0518
UD
524 }
525 ++last_idx;
19bc17a9
RM
526
527 iov[2 + cnt].iov_base = (void *) (time->era_year ?: "");
528 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
ec4b0518 529 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
19bc17a9 530 ++cnt;
ec4b0518 531 ++last_idx;
19bc17a9
RM
532
533 iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
534 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
ec4b0518
UD
535 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
536 ++cnt;
537 ++last_idx;
19bc17a9
RM
538
539 idx[1 + last_idx] = idx[last_idx];
540 for (num = 0; num < time->cur_num_alt_digits; ++num, ++cnt)
541 {
542 iov[2 + cnt].iov_base = (void *) (time->alt_digits[num] ?: "");
543 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
544 idx[1 + last_idx] += iov[2 + cnt].iov_len;
545 }
546 ++last_idx;
547
548 iov[2 + cnt].iov_base = (void *) (time->era_d_t_fmt ?: "");
549 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
550 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
551 ++cnt;
c4029823 552 ++last_idx;
19bc17a9 553
c4029823 554 iov[2 + cnt].iov_base = (void *) (time->era_t_fmt ?: "");
19bc17a9 555 iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
c4029823 556 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
19bc17a9 557 ++cnt;
c4029823
UD
558 ++last_idx;
559
560
561 /* We must align the following data. */
562 iov[2 + cnt].iov_base = (void *) "\0\0";
563 iov[2 + cnt].iov_len = ((idx[last_idx] + 3) & ~3) - idx[last_idx];
564 idx[last_idx] = (idx[last_idx] + 3) & ~3;
565 ++cnt;
566
567 iov[2 + cnt].iov_base = (void *) &time->cur_num_alt_digits;
568 iov[2 + cnt].iov_len = sizeof (u_int32_t);
569 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
570 ++cnt;
571 ++last_idx;
572
573 /* The `era' data in usable form. */
574 iov[2 + cnt].iov_base = (void *) &time->cur_num_era;
575 iov[2 + cnt].iov_len = sizeof (u_int32_t);
576 idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
577 ++cnt;
578 ++last_idx;
579
580#if __BYTE_ORDER == __LITTLE_ENDIAN
c4029823
UD
581# define ERA_B1 time->era_entries_ob
582# define ERA_B2 time->era_entries
d68171ed
UD
583#else
584# define ERA_B1 time->era_entries
585# define ERA_B2 time->era_entries_ob
c4029823
UD
586#endif
587 idx[1 + last_idx] = idx[last_idx];
588 for (num = 0; num < time->cur_num_era; ++num)
589 {
590 size_t l;
591
592 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].direction;
593 iov[2 + cnt].iov_len = sizeof (int32_t);
594 ++cnt;
595 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].offset;
596 iov[2 + cnt].iov_len = sizeof (int32_t);
597 ++cnt;
598 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].start_date[0];
f76d7052 599 iov[2 + cnt].iov_len = 3 * sizeof (int32_t);
c4029823
UD
600 ++cnt;
601 iov[2 + cnt].iov_base = (void *) &ERA_B1[num].stop_date[0];
f76d7052 602 iov[2 + cnt].iov_len = 3 * sizeof (int32_t);
c4029823
UD
603 ++cnt;
604
605 l = (strchr (ERA_B1[num].format, '\0') - ERA_B1[num].name) + 1;
606 l = (l + 3) & ~3;
607 iov[2 + cnt].iov_base = (void *) ERA_B1[num].name;
608 iov[2 + cnt].iov_len = l;
609 ++cnt;
610
611 idx[1 + last_idx] += 8 * sizeof (int32_t) + l;
612
613 assert (idx[1 + last_idx] % 4 == 0);
614 }
615 ++last_idx;
616
617 /* idx[1 + last_idx] = idx[last_idx]; */
618 for (num = 0; num < time->cur_num_era; ++num)
619 {
620 size_t l;
621
622 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].direction;
623 iov[2 + cnt].iov_len = sizeof (int32_t);
624 ++cnt;
625 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].offset;
626 iov[2 + cnt].iov_len = sizeof (int32_t);
627 ++cnt;
628 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].start_date[0];
f76d7052 629 iov[2 + cnt].iov_len = 3 * sizeof (int32_t);
c4029823
UD
630 ++cnt;
631 iov[2 + cnt].iov_base = (void *) &ERA_B2[num].stop_date[0];
f76d7052 632 iov[2 + cnt].iov_len = 3 * sizeof (int32_t);
c4029823
UD
633 ++cnt;
634
635 l = (strchr (ERA_B2[num].format, '\0') - ERA_B2[num].name) + 1;
636 l = (l + 3) & ~3;
637 iov[2 + cnt].iov_base = (void *) ERA_B2[num].name;
638 iov[2 + cnt].iov_len = l;
639 ++cnt;
640
641 /* idx[1 + last_idx] += 8 * sizeof (int32_t) + l; */
642 }
643
a68b0d31
UD
644 /* We have a problem when no era data is present. In this case the
645 data pointer for _NL_TIME_ERA_ENTRIES_EB and
646 _NL_TIME_ERA_ENTRIES_EL point after the end of the file. So we
647 introduce some dummy data here. */
648 if (time->cur_num_era == 0)
649 {
650 static u_int32_t dummy = 0;
651 iov[2 + cnt].iov_base = (void *) &dummy;
652 iov[2 + cnt].iov_len = 4;
653 ++cnt;
654 }
19bc17a9 655
c4029823
UD
656 assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME)
657 + time->cur_num_era - 1
658 + time->cur_num_alt_digits - 1
a68b0d31
UD
659 + 1 + (time->cur_num_era * 9 - 1) * 2
660 + (time->cur_num_era == 0))
c4029823 661 && last_idx + 1 == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
19bc17a9
RM
662
663 write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
664}
665
666
667void
668time_add (struct linereader *lr, struct localedef_t *locale,
669 enum token_t tok, struct token *code,
670 struct charset_t *charset)
671{
672 struct locale_time_t *time = locale->categories[LC_TIME].time;
673
674 switch (tok)
675 {
676#define STRARR_ELEM(cat, max) \
677 case tok_##cat: \
678 if (time->cur_num_##cat >= max) \
036cc82f 679 lr_error (lr, _("\
ba1ffaa1 680too many values for field `%s' in category `%s'"), \
19bc17a9
RM
681 #cat, "LC_TIME"); \
682 else if (code->val.str.start == NULL) \
683 { \
684 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
685 #cat, "LC_TIME"); \
686 time->cat[time->cur_num_##cat++] = ""; \
687 } \
688 else \
ec4b0518 689 time->cat[time->cur_num_##cat++] = code->val.str.start; \
19bc17a9
RM
690 break
691
692 STRARR_ELEM (abday, 7);
693 STRARR_ELEM (day, 7);
694 STRARR_ELEM (abmon, 12);
695 STRARR_ELEM (mon, 12);
696 STRARR_ELEM (am_pm, 2);
697 STRARR_ELEM (alt_digits, 100);
698
ec4b0518
UD
699 case tok_era:
700 if (code->val.str.start == NULL)
701 lr_error (lr, _("unknown character in field `%s' of category `%s'"),
702 "era", "LC_TIME");
703 else
704 {
c4029823
UD
705 ++time->cur_num_era;
706 time->era = xrealloc (time->era,
707 time->cur_num_era * sizeof (char *));
708 time->era[time->cur_num_era - 1] = code->val.str.start;
ec4b0518
UD
709 }
710 break;
711
19bc17a9
RM
712#define STR_ELEM(cat) \
713 case tok_##cat: \
714 if (time->cat != NULL) \
715 lr_error (lr, _("\
716field `%s' in category `%s' declared more than once"), \
717 #cat, "LC_TIME"); \
718 else if (code->val.str.start == NULL) \
719 { \
720 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
721 #cat, "LC_TIME"); \
722 time->cat = ""; \
723 } \
724 else \
725 time->cat = code->val.str.start; \
726 break
727
728 STR_ELEM (d_t_fmt);
729 STR_ELEM (d_fmt);
730 STR_ELEM (t_fmt);
731 STR_ELEM (t_fmt_ampm);
19bc17a9
RM
732 STR_ELEM (era_year);
733 STR_ELEM (era_d_t_fmt);
734 STR_ELEM (era_d_fmt);
735 STR_ELEM (era_t_fmt);
736
737 default:
738 assert (! "unknown token in category `LC_TIME': should not happen");
739 }
740}