Update.
[glibc.git] / locale / lc-time.c
blob203a49be1f4b8fd1bb130263442cbe9febf83b0d
1 /* Define current locale data for LC_TIME category.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <bits/libc-lock.h>
21 #include <endian.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <wchar.h>
26 #include "localeinfo.h"
28 _NL_CURRENT_DEFINE (LC_TIME);
30 /* Some of the functions here must not be used while setlocale is called. */
31 __libc_lock_define (extern, __libc_setlocale_lock)
34 static int era_initialized;
36 static struct era_entry *eras;
37 static size_t num_eras;
38 static int alt_digits_initialized;
39 static const char **alt_digits;
42 static int walt_digits_initialized;
43 static const wchar_t **walt_digits;
46 void
47 _nl_postload_time (void)
49 /* Prepare lazy initialization of `era' and `alt_digits' array. */
50 era_initialized = 0;
51 alt_digits_initialized = 0;
52 walt_digits_initialized = 0;
55 #define ERA_DATE_CMP(a, b) \
56 (a[0] < b[0] || (a[0] == b[0] && (a[1] < b[1] \
57 || (a[1] == b[1] && a[2] <= b[2]))))
59 static void
60 _nl_init_era_entries (void)
62 size_t cnt;
64 __libc_lock_lock (__libc_setlocale_lock);
66 if (era_initialized == 0)
68 size_t new_num_eras = _NL_CURRENT_WORD (LC_TIME,
69 _NL_TIME_ERA_NUM_ENTRIES);
70 if (new_num_eras == 0)
72 free (eras);
73 eras = NULL;
75 else
77 struct era_entry *new_eras = eras;
79 if (num_eras != new_num_eras)
80 new_eras =
81 (struct era_entry *) realloc (eras,
82 new_num_eras
83 * sizeof (struct era_entry));
84 if (new_eras == NULL)
86 free (eras);
87 num_eras = 0;
88 eras = NULL;
90 else
92 const char *ptr = _NL_CURRENT (LC_TIME, _NL_TIME_ERA_ENTRIES);
93 num_eras = new_num_eras;
94 eras = new_eras;
96 for (cnt = 0; cnt < num_eras; ++cnt)
98 const char *base_ptr = ptr;
99 memcpy ((void *) (eras + cnt), (const void *) ptr,
100 sizeof (uint32_t) * 8);
102 if (ERA_DATE_CMP(eras[cnt].start_date,
103 eras[cnt].stop_date))
104 if (eras[cnt].direction == (uint32_t) '+')
105 eras[cnt].absolute_direction = 1;
106 else
107 eras[cnt].absolute_direction = -1;
108 else
109 if (eras[cnt].direction == (uint32_t) '+')
110 eras[cnt].absolute_direction = -1;
111 else
112 eras[cnt].absolute_direction = 1;
114 /* Skip numeric values. */
115 ptr += sizeof (uint32_t) * 8;
117 /* Set and skip era name. */
118 eras[cnt].era_name = ptr;
119 ptr = strchr (ptr, '\0') + 1;
121 /* Set and skip era format. */
122 eras[cnt].era_format = ptr;
123 ptr = strchr (ptr, '\0') + 1;
125 ptr += 3 - (((ptr - (const char *) base_ptr) + 3) & 3);
127 /* Set and skip wide era name. */
128 eras[cnt].era_wname = (wchar_t *) ptr;
129 ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);
131 /* Set and skip wide era format. */
132 eras[cnt].era_wformat = (wchar_t *) ptr;
133 ptr = (char *) (wcschr ((wchar_t *) ptr, L'\0') + 1);
138 era_initialized = 1;
141 __libc_lock_unlock (__libc_setlocale_lock);
145 struct era_entry *
146 _nl_get_era_entry (const struct tm *tp)
148 struct era_entry *result;
149 int32_t tdate[3];
150 size_t cnt;
152 tdate[0] = tp->tm_year;
153 tdate[1] = tp->tm_mon;
154 tdate[2] = tp->tm_mday;
156 if (era_initialized == 0)
157 _nl_init_era_entries ();
159 /* Now compare date with the available eras. */
160 for (cnt = 0; cnt < num_eras; ++cnt)
161 if ((ERA_DATE_CMP(eras[cnt].start_date, tdate)
162 && ERA_DATE_CMP(tdate, eras[cnt].stop_date))
163 || (ERA_DATE_CMP(eras[cnt].stop_date, tdate)
164 && ERA_DATE_CMP(tdate, eras[cnt].start_date)))
165 break;
167 result = cnt < num_eras ? &eras[cnt] : NULL;
169 return result;
173 struct era_entry *
174 _nl_select_era_entry (int cnt)
176 if (era_initialized == 0)
177 _nl_init_era_entries ();
179 return &eras[cnt];
183 const char *
184 _nl_get_alt_digit (unsigned int number)
186 const char *result;
188 __libc_lock_lock (__libc_setlocale_lock);
190 if (alt_digits_initialized == 0)
192 alt_digits_initialized = 1;
194 if (alt_digits == NULL)
195 alt_digits = malloc (100 * sizeof (const char *));
197 if (alt_digits != NULL)
199 const char *ptr = _NL_CURRENT (LC_TIME, ALT_DIGITS);
200 size_t cnt;
202 if (alt_digits != NULL)
203 for (cnt = 0; cnt < 100; ++cnt)
205 alt_digits[cnt] = ptr;
207 /* Skip digit format. */
208 ptr = strchr (ptr, '\0') + 1;
213 result = alt_digits != NULL && number < 100 ? alt_digits[number] : NULL;
215 __libc_lock_unlock (__libc_setlocale_lock);
217 return result;
221 const wchar_t *
222 _nl_get_walt_digit (unsigned int number)
224 const wchar_t *result;
226 __libc_lock_lock (__libc_setlocale_lock);
228 if (walt_digits_initialized == 0)
230 walt_digits_initialized = 1;
232 if (walt_digits == NULL)
233 walt_digits = malloc (100 * sizeof (const uint32_t *));
235 if (walt_digits != NULL)
237 const wchar_t *ptr = _NL_CURRENT_WSTR (LC_TIME, _NL_WALT_DIGITS);
238 size_t cnt;
240 for (cnt = 0; cnt < 100; ++cnt)
242 walt_digits[cnt] = ptr;
244 /* Skip digit format. */
245 ptr = wcschr (ptr, L'\0') + 1;
250 result = walt_digits != NULL && number < 100 ? walt_digits[number] : NULL;
252 __libc_lock_unlock (__libc_setlocale_lock);
254 return (wchar_t *) result;
259 _nl_parse_alt_digit (const char **strp)
261 const char *str = *strp;
262 int result = -1;
263 size_t cnt;
264 size_t maxlen = 0;
266 __libc_lock_lock (__libc_setlocale_lock);
268 if (alt_digits_initialized == 0)
270 alt_digits_initialized = 1;
272 if (alt_digits == NULL)
273 alt_digits = malloc (100 * sizeof (const char *));
275 if (alt_digits != NULL)
277 const char *ptr = _NL_CURRENT (LC_TIME, ALT_DIGITS);
279 if (alt_digits != NULL)
280 for (cnt = 0; cnt < 100; ++cnt)
282 alt_digits[cnt] = ptr;
284 /* Skip digit format. */
285 ptr = strchr (ptr, '\0') + 1;
290 /* Matching is not unambiguos. The alternative digits could be like
291 I, II, III, ... and the first one is a substring of the second
292 and third. Therefore we must keep on searching until we found
293 the longest possible match. Note that this is not specified in
294 the standard. */
295 for (cnt = 0; cnt < 100; ++cnt)
297 size_t len = strlen (alt_digits[cnt]);
299 if (len > maxlen && strncmp (alt_digits[cnt], str, len) == 0)
301 maxlen = len;
302 result = (int) cnt;
306 __libc_lock_unlock (__libc_setlocale_lock);
308 if (result != -1)
309 *strp += maxlen;
311 return result;
315 static void
316 free_mem (void)
318 free (alt_digits);
319 free (walt_digits);
321 text_set_element (__libc_subfreeres, free_mem);