]>
Commit | Line | Data |
---|---|---|
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 | |
40 | void *xmalloc (size_t __n); | |
ec4b0518 | 41 | void *xrealloc (void *__p, size_t __n); |
19bc17a9 RM |
42 | |
43 | ||
c4029823 UD |
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 | ||
19bc17a9 RM |
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; | |
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 | ||
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) \ | |
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 | ||
393 | void | |
394 | time_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 | ||
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) | |
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 | 677 | too 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, _("\ | |
713 | field `%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 | } |