]> git.ipfire.org Git - thirdparty/glibc.git/blob - locale/programs/ld-time.c
update from main archive 961030
[thirdparty/glibc.git] / locale / programs / ld-time.c
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>.
4
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.
9
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.
14
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. */
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>
30 #include <stdlib.h>
31
32 #include "locales.h"
33 #include "localeinfo.h"
34 #include "stringtrans.h"
35
36 #define SWAPU32(w) \
37 (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
38
39
40 void *xmalloc (size_t __n);
41 void *xrealloc (void *__p, size_t __n);
42
43
44 /* Entry describing an entry of the era specification. */
45 struct 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
56 /* The real definition of the struct for the LC_TIME locale. */
57 struct 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;
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;
81
82 struct era_data *era_entries;
83 struct era_data *era_entries_ob;
84 };
85
86
87 void
88 time_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
103 void
104 time_finish (struct localedef_t *locale)
105 {
106 struct locale_time_t *time = locale->categories[LC_TIME].time;
107
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")
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) \
123 if (time->cat == NULL) \
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);
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. */
152 if (*str != '+' && *str != '-')
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;
162 if (*++str != ':')
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);
174 if (endp == str)
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 }
181 else if (*endp != ':')
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);
227 if (endp == str)
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 }
235 else if (*endp != ':')
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. */
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");
260 }
261 }
262
263 /* Next is the stoping date in ISO format. */
264 if (strncmp (str, "-*", 2) == 0)
265 {
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;
272 }
273 else if (strncmp (str, "+*", 2) == 0)
274 {
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;
281 }
282 else
283 {
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;
290
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;
297
298 time->era_entries[idx].stop_date[2] = strtol (str, &endp, 10);
299 if (endp == str)
300 {
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, ":");
306 }
307 else if (*endp != ':')
308 {
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, ":");
314 }
315 else
316 {
317 str = endp + 1;
318
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");
332 }
333 }
334
335 if (str == NULL || *str == '\0')
336 {
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 = "";
341 }
342 else
343 {
344 time->era_entries[idx].name = strsep (&str, ":");
345
346 if (str == NULL || *str == '\0')
347 {
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 = "";
353 }
354 else
355 time->era_entries[idx].format = str;
356 }
357 }
358
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));
363
364 for (idx = 0; idx < time->cur_num_era; ++idx)
365 {
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;
386 }
387 }
388 }
389
390
391 void
392 time_output (struct localedef_t *locale, const char *output_path)
393 {
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;
403
404 if ((locale->binary & (1 << LC_TIME)) != 0)
405 {
406 iov[0].iov_base = time;
407 iov[0].iov_len = locale->len[LC_TIME];
408
409 write_locale_data (output_path, "LC_TIME", 1, iov);
410
411 return;
412 }
413
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);
418
419 iov[1].iov_base = (void *) idx;
420 iov[1].iov_len = sizeof (idx);
421
422 idx[0] = iov[0].iov_len + iov[1].iov_len;
423
424 /* The ab'days. */
425 for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
426 {
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;
431 }
432
433 /* The days. */
434 for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
435 {
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;
440 }
441
442 /* The ab'mons. */
443 for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
444 {
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;
449 }
450
451 /* The mons. */
452 for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
453 {
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;
458 }
459
460 /* AM/PM. */
461 for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
462 {
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;
467 }
468
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;
473
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;
478
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;
483
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;
488
489 idx[1 + last_idx] = idx[last_idx];
490 for (num = 0; num < time->cur_num_era; ++num, ++cnt)
491 {
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;
495 }
496 ++last_idx;
497
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;
503
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;
509
510 idx[1 + last_idx] = idx[last_idx];
511 for (num = 0; num < time->cur_num_alt_digits; ++num, ++cnt)
512 {
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;
516 }
517 ++last_idx;
518
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;
524
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;
530
531
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;
537
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;
543
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;
550
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)
560 {
561 size_t l;
562
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;
587
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;
593
594 idx[1 + last_idx] += 8 * sizeof (int32_t) + l;
595
596 assert (idx[1 + last_idx] % 4 == 0);
597 }
598 ++last_idx;
599
600 /* idx[1 + last_idx] = idx[last_idx]; */
601 for (num = 0; num < time->cur_num_era; ++num)
602 {
603 size_t l;
604
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;
629
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;
635
636 /* idx[1 + last_idx] += 8 * sizeof (int32_t) + l; */
637 }
638
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)
644 {
645 static u_int32_t dummy = 0;
646 iov[2 + cnt].iov_base = (void *) &dummy;
647 iov[2 + cnt].iov_len = 4;
648 ++cnt;
649 }
650
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));
657
658 write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
659 }
660
661
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)
666 {
667 struct locale_time_t *time = locale->categories[LC_TIME].time;
668
669 switch (tok)
670 {
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 `%s'"), \
676 #cat, "LC_TIME"); \
677 else if (code->val.str.start == NULL) \
678 { \
679 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
680 #cat, "LC_TIME"); \
681 time->cat[time->cur_num_##cat++] = ""; \
682 } \
683 else \
684 time->cat[time->cur_num_##cat++] = code->val.str.start; \
685 break
686
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);
693
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
699 {
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;
704 }
705 break;
706
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) \
714 { \
715 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
716 #cat, "LC_TIME"); \
717 time->cat = ""; \
718 } \
719 else \
720 time->cat = code->val.str.start; \
721 break
722
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);
731
732 default:
733 assert (! "unknown token in category `LC_TIME': should not happen");
734 }
735 }