1 /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
27 /* Undefine following line in production version. */
28 /* #define NDEBUG 1 */
33 #include "localeinfo.h"
34 #include "stringtrans.h"
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. */
49 int32_t start_date
[3];
56 /* The real definition of the struct for the LC_TIME locale. */
63 const char *abmon
[12];
72 const char *t_fmt_ampm
;
74 u_int32_t cur_num_era
;
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
;
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
));
104 time_finish (struct localedef_t
*locale
)
106 struct locale_time_t
*time
= locale
->categories
[LC_TIME
].time
;
108 #define TESTARR_ELEM(cat, max) \
109 if (time->cur_num_##cat == 0) \
110 error (0, 0, _("field `%s' in category `%s' not defined"), \
112 else if (time->cur_num_##cat != max) \
113 error (0, 0, _("field `%s' in category `%s' has not enough values"), \
116 TESTARR_ELEM (abday
, 7);
117 TESTARR_ELEM (day
, 7);
118 TESTARR_ELEM (abmon
, 12);
119 TESTARR_ELEM (mon
, 12);
120 TESTARR_ELEM (am_pm
, 2);
122 #define TEST_ELEM(cat) \
123 if (time->cat == NULL) \
124 error (0, 0, _("field `%s' in category `%s' not defined"), \
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 };
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);
149 memcpy (str
, time
->era
[idx
], era_len
+ 1);
151 /* First character must be + or - for the direction. */
152 if (*str
!= '+' && *str
!= '-')
154 error (0, 0, _("direction flag in string %d in `era' field"
155 " in category `%s' is not '+' nor '-'"),
157 /* Default arbitrarily to '+'. */
158 time
->era_entries
[idx
].direction
= '+';
161 time
->era_entries
[idx
].direction
= *str
;
164 error (0, 0, _("direction flag in string %d in `era' field"
165 " in category `%s' is not a single character"),
167 (void) strsep (&str
, ":");
172 /* Now the offset year. */
173 time
->era_entries
[idx
].offset
= strtol (str
, &endp
, 10);
176 error (0, 0, _("illegal number for offset in string %d in"
177 " `era' field in category `%s'"),
179 (void) strsep (&str
, ":");
181 else if (*endp
!= ':')
183 error (0, 0, _("garbage at end of offset value in string %d in"
184 " `era' field in category `%s'"),
186 (void) strsep (&str
, ":");
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;
198 goto garbage_start_date
;
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;
207 goto garbage_start_date
;
212 time
->era_entries
[idx
].start_date
[0] = strtol (str
, &endp
, 10);
213 if (endp
== str
|| *endp
!= '/')
214 goto invalid_start_date
;
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
;
224 time
->era_entries
[idx
].start_date
[1] -= 1;
226 time
->era_entries
[idx
].start_date
[2] = strtol (str
, &endp
, 10);
230 error (0, 0, _("illegal starting date in string %d in"
231 " `era' field in category `%s'"),
233 (void) strsep (&str
, ":");
235 else if (*endp
!= ':')
238 error (0, 0, _("garbage at end of starting date in string %d"
239 " in `era' field in category `%s'"),
241 (void) strsep (&str
, ":");
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"
263 /* Next is the stoping date in ISO format. */
264 if (strncmp (str
, "-*", 2) == 0)
266 time
->era_entries
[idx
].stop_date
[0] =
267 time
->era_entries
[idx
].stop_date
[1] =
268 time
->era_entries
[idx
].stop_date
[2] = 0x80000000;
270 goto garbage_stop_date
;
273 else if (strncmp (str
, "+*", 2) == 0)
275 time
->era_entries
[idx
].stop_date
[0] =
276 time
->era_entries
[idx
].stop_date
[1] =
277 time
->era_entries
[idx
].stop_date
[2] = 0x7fffffff;
279 goto garbage_stop_date
;
284 time
->era_entries
[idx
].stop_date
[0] = strtol (str
, &endp
, 10);
285 if (endp
== str
|| *endp
!= '/')
286 goto invalid_stop_date
;
289 time
->era_entries
[idx
].stop_date
[0] -= 1900;
291 time
->era_entries
[idx
].stop_date
[1] = strtol (str
, &endp
, 10);
292 if (endp
== str
|| *endp
!= '/')
293 goto invalid_stop_date
;
296 time
->era_entries
[idx
].stop_date
[1] -= 1;
298 time
->era_entries
[idx
].stop_date
[2] = strtol (str
, &endp
, 10);
302 error (0, 0, _("illegal stopping date in string %d in"
303 " `era' field in category `%s'"),
305 (void) strsep (&str
, ":");
307 else if (*endp
!= ':')
310 error (0, 0, _("garbage at end of stopping date in string %d"
311 " in `era' field in category `%s'"),
313 (void) strsep (&str
, ":");
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"
335 if (str
== NULL
|| *str
== '\0')
337 error (0, 0, _("missing era name in string %d in `era' field"
338 "in category `%s'"), idx
+ 1, "LC_TIME");
339 time
->era_entries
[idx
].name
=
340 time
->era_entries
[idx
].format
= "";
344 time
->era_entries
[idx
].name
= strsep (&str
, ":");
346 if (str
== NULL
|| *str
== '\0')
348 error (0, 0, _("missing era format in string %d in `era'"
349 " field in category `%s'"),
351 time
->era_entries
[idx
].name
=
352 time
->era_entries
[idx
].format
= "";
355 time
->era_entries
[idx
].format
= str
;
359 /* Construct the array for the other byte order. */
360 time
->era_entries_ob
=
361 (struct era_data
*) xmalloc (time
->cur_num_era
362 * sizeof (struct era_data
));
364 for (idx
= 0; idx
< time
->cur_num_era
; ++idx
)
366 time
->era_entries_ob
[idx
].direction
=
367 SWAPU32 (time
->era_entries
[idx
].direction
);
368 time
->era_entries_ob
[idx
].offset
=
369 SWAPU32 (time
->era_entries
[idx
].offset
);
370 time
->era_entries_ob
[idx
].start_date
[0] =
371 SWAPU32 (time
->era_entries
[idx
].start_date
[0]);
372 time
->era_entries_ob
[idx
].start_date
[1] =
373 SWAPU32 (time
->era_entries
[idx
].start_date
[1]);
374 time
->era_entries_ob
[idx
].start_date
[2] =
375 SWAPU32 (time
->era_entries
[idx
].stop_date
[2]);
376 time
->era_entries_ob
[idx
].stop_date
[0] =
377 SWAPU32 (time
->era_entries
[idx
].stop_date
[0]);
378 time
->era_entries_ob
[idx
].stop_date
[1] =
379 SWAPU32 (time
->era_entries
[idx
].stop_date
[1]);
380 time
->era_entries_ob
[idx
].stop_date
[2] =
381 SWAPU32 (time
->era_entries
[idx
].stop_date
[2]);
382 time
->era_entries_ob
[idx
].name
=
383 time
->era_entries
[idx
].name
;
384 time
->era_entries_ob
[idx
].format
=
385 time
->era_entries
[idx
].format
;
392 time_output (struct localedef_t
*locale
, const char *output_path
)
394 struct locale_time_t
*time
= locale
->categories
[LC_TIME
].time
;
395 struct iovec iov
[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME
)
396 + time
->cur_num_era
- 1
397 + time
->cur_num_alt_digits
- 1
398 + 1 + (time
->cur_num_era
* 9 - 1) * 2
399 + (time
->cur_num_era
== 0)];
400 struct locale_file data
;
401 u_int32_t idx
[_NL_ITEM_INDEX (_NL_NUM_LC_TIME
)];
402 size_t cnt
, last_idx
, num
;
404 if ((locale
->binary
& (1 << LC_TIME
)) != 0)
406 iov
[0].iov_base
= time
;
407 iov
[0].iov_len
= locale
->len
[LC_TIME
];
409 write_locale_data (output_path
, "LC_TIME", 1, iov
);
414 data
.magic
= LIMAGIC (LC_TIME
);
415 data
.n
= _NL_ITEM_INDEX (_NL_NUM_LC_TIME
);
416 iov
[0].iov_base
= (void *) &data
;
417 iov
[0].iov_len
= sizeof (data
);
419 iov
[1].iov_base
= (void *) idx
;
420 iov
[1].iov_len
= sizeof (idx
);
422 idx
[0] = iov
[0].iov_len
+ iov
[1].iov_len
;
425 for (cnt
= 0; cnt
<= _NL_ITEM_INDEX (ABDAY_7
); ++cnt
)
427 iov
[2 + cnt
].iov_base
=
428 (void *) (time
->abday
[cnt
- _NL_ITEM_INDEX (ABDAY_1
)] ?: "");
429 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
430 idx
[1 + cnt
] = idx
[cnt
] + iov
[2 + cnt
].iov_len
;
434 for (; cnt
<= _NL_ITEM_INDEX (DAY_7
); ++cnt
)
436 iov
[2 + cnt
].iov_base
=
437 (void *) (time
->day
[cnt
- _NL_ITEM_INDEX (DAY_1
)] ?: "");
438 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
439 idx
[1 + cnt
] = idx
[cnt
] + iov
[2 + cnt
].iov_len
;
443 for (; cnt
<= _NL_ITEM_INDEX (ABMON_12
); ++cnt
)
445 iov
[2 + cnt
].iov_base
=
446 (void *) (time
->abmon
[cnt
- _NL_ITEM_INDEX (ABMON_1
)] ?: "");
447 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
448 idx
[1 + cnt
] = idx
[cnt
] + iov
[2 + cnt
].iov_len
;
452 for (; cnt
<= _NL_ITEM_INDEX (MON_12
); ++cnt
)
454 iov
[2 + cnt
].iov_base
=
455 (void *) (time
->mon
[cnt
- _NL_ITEM_INDEX (MON_1
)] ?: "");
456 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
457 idx
[1 + cnt
] = idx
[cnt
] + iov
[2 + cnt
].iov_len
;
461 for (; cnt
<= _NL_ITEM_INDEX (PM_STR
); ++cnt
)
463 iov
[2 + cnt
].iov_base
=
464 (void *) (time
->am_pm
[cnt
- _NL_ITEM_INDEX (AM_STR
)] ?: "");
465 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
466 idx
[1 + cnt
] = idx
[cnt
] + iov
[2 + cnt
].iov_len
;
469 iov
[2 + cnt
].iov_base
= (void *) (time
->d_t_fmt
?: "");
470 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
471 idx
[1 + cnt
] = idx
[cnt
] + iov
[2 + cnt
].iov_len
;
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
;
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
;
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
;
489 idx
[1 + last_idx
] = idx
[last_idx
];
490 for (num
= 0; num
< time
->cur_num_era
; ++num
, ++cnt
)
492 iov
[2 + cnt
].iov_base
= (void *) time
->era
[num
];
493 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
494 idx
[1 + last_idx
] += iov
[2 + cnt
].iov_len
;
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
;
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
;
510 idx
[1 + last_idx
] = idx
[last_idx
];
511 for (num
= 0; num
< time
->cur_num_alt_digits
; ++num
, ++cnt
)
513 iov
[2 + cnt
].iov_base
= (void *) (time
->alt_digits
[num
] ?: "");
514 iov
[2 + cnt
].iov_len
= strlen (iov
[2 + cnt
].iov_base
) + 1;
515 idx
[1 + last_idx
] += iov
[2 + cnt
].iov_len
;
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
;
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
;
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;
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
;
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
;
551 #if __BYTE_ORDER == __LITTLE_ENDIAN
552 # define ERA_B1 time->era_entries_ob
553 # define ERA_B2 time->era_entries
555 # define ERA_B1 time->era_entries
556 # define ERA_B2 time->era_entries_ob
558 idx
[1 + last_idx
] = idx
[last_idx
];
559 for (num
= 0; num
< time
->cur_num_era
; ++num
)
563 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].direction
;
564 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
566 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].offset
;
567 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
569 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].start_date
[0];
570 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
572 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].start_date
[1];
573 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
575 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].start_date
[2];
576 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
578 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].stop_date
[0];
579 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
581 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].stop_date
[1];
582 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
584 iov
[2 + cnt
].iov_base
= (void *) &ERA_B1
[num
].stop_date
[2];
585 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
588 l
= (strchr (ERA_B1
[num
].format
, '\0') - ERA_B1
[num
].name
) + 1;
590 iov
[2 + cnt
].iov_base
= (void *) ERA_B1
[num
].name
;
591 iov
[2 + cnt
].iov_len
= l
;
594 idx
[1 + last_idx
] += 8 * sizeof (int32_t) + l
;
596 assert (idx
[1 + last_idx
] % 4 == 0);
600 /* idx[1 + last_idx] = idx[last_idx]; */
601 for (num
= 0; num
< time
->cur_num_era
; ++num
)
605 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].direction
;
606 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
608 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].offset
;
609 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
611 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].start_date
[0];
612 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
614 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].start_date
[1];
615 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
617 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].start_date
[2];
618 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
620 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].stop_date
[0];
621 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
623 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].stop_date
[1];
624 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
626 iov
[2 + cnt
].iov_base
= (void *) &ERA_B2
[num
].stop_date
[2];
627 iov
[2 + cnt
].iov_len
= sizeof (int32_t);
630 l
= (strchr (ERA_B2
[num
].format
, '\0') - ERA_B2
[num
].name
) + 1;
632 iov
[2 + cnt
].iov_base
= (void *) ERA_B2
[num
].name
;
633 iov
[2 + cnt
].iov_len
= l
;
636 /* idx[1 + last_idx] += 8 * sizeof (int32_t) + l; */
639 /* We have a problem when no era data is present. In this case the
640 data pointer for _NL_TIME_ERA_ENTRIES_EB and
641 _NL_TIME_ERA_ENTRIES_EL point after the end of the file. So we
642 introduce some dummy data here. */
643 if (time
->cur_num_era
== 0)
645 static u_int32_t dummy
= 0;
646 iov
[2 + cnt
].iov_base
= (void *) &dummy
;
647 iov
[2 + cnt
].iov_len
= 4;
651 assert (cnt
== (_NL_ITEM_INDEX (_NL_NUM_LC_TIME
)
652 + time
->cur_num_era
- 1
653 + time
->cur_num_alt_digits
- 1
654 + 1 + (time
->cur_num_era
* 9 - 1) * 2
655 + (time
->cur_num_era
== 0))
656 && last_idx
+ 1 == _NL_ITEM_INDEX (_NL_NUM_LC_TIME
));
658 write_locale_data (output_path
, "LC_TIME", 2 + cnt
, iov
);
663 time_add (struct linereader
*lr
, struct localedef_t
*locale
,
664 enum token_t tok
, struct token
*code
,
665 struct charset_t
*charset
)
667 struct locale_time_t
*time
= locale
->categories
[LC_TIME
].time
;
671 #define STRARR_ELEM(cat, max) \
673 if (time->cur_num_##cat >= max) \
675 too many values for field `%s' in category `%s'"), \
677 else if (code->val.str.start == NULL) \
679 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
681 time->cat[time->cur_num_##cat++] = ""; \
684 time->cat[time->cur_num_##cat++] = code->val.str.start; \
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);
695 if (code
->val
.str
.start
== NULL
)
696 lr_error (lr
, _("unknown character in field `%s' of category `%s'"),
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
;
707 #define STR_ELEM(cat) \
709 if (time->cat != NULL) \
711 field `%s' in category `%s' declared more than once"), \
713 else if (code->val.str.start == NULL) \
715 lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
720 time->cat = code->val.str.start; \
726 STR_ELEM (t_fmt_ampm
);
728 STR_ELEM (era_d_t_fmt
);
729 STR_ELEM (era_d_fmt
);
730 STR_ELEM (era_t_fmt
);
733 assert (! "unknown token in category `LC_TIME': should not happen");