Update.
[platform/upstream/glibc.git] / locale / lc-time.c
1 /* Define current locale data for LC_TIME category.
2    Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
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 not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
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"
27
28 _NL_CURRENT_DEFINE (LC_TIME);
29
30 /* Some of the functions here must not be used while setlocale is called.  */
31 __libc_lock_define (extern, __libc_setlocale_lock)
32
33
34 static int era_initialized;
35 static struct era_entry **eras;
36 static size_t num_eras;
37
38
39 static int alt_digits_initialized;
40 static const char **alt_digits;
41
42
43 static int walt_digits_initialized;
44 static const wchar_t **walt_digits;
45
46
47 void
48 _nl_postload_time (void)
49 {
50   /* Prepare lazy initialization of `era' and `alt_digits' array.  */
51   era_initialized = 0;
52   alt_digits_initialized = 0;
53   walt_digits_initialized = 0;
54 }
55
56
57 struct era_entry *
58 _nl_get_era_entry (const struct tm *tp)
59 {
60   struct era_entry *result;
61   size_t cnt;
62
63   __libc_lock_lock (__libc_setlocale_lock);
64
65   if (era_initialized == 0)
66     {
67       size_t new_num_eras = _NL_CURRENT_WORD (LC_TIME,
68                                               _NL_TIME_ERA_NUM_ENTRIES);
69
70       if (eras != NULL && new_num_eras == 0)
71         {
72           free (eras);
73           eras = NULL;
74         }
75       else if (new_num_eras != 0)
76         {
77           if (num_eras != new_num_eras)
78             eras = realloc (eras, new_num_eras * sizeof (struct era_entry *));
79
80           if (eras == NULL)
81             num_eras = 0;
82           else
83             {
84               const char *ptr = _NL_CURRENT (LC_TIME, _NL_TIME_ERA_ENTRIES);
85               num_eras = new_num_eras;
86
87               for (cnt = 0; cnt < num_eras; ++cnt)
88                 {
89                   eras[cnt] = (struct era_entry *) ptr;
90
91                   /* Skip numeric values.  */
92                   ptr += sizeof (struct era_entry);
93                   /* Skip era name.  */
94                   ptr = strchr (ptr, '\0') + 1;
95                   /* Skip era format.  */
96                   ptr = strchr (ptr, '\0') + 1;
97
98                   ptr += 3 - (((ptr - (const char *) eras[cnt]) + 3) & 3);
99
100                   /* Skip wide era name.  */
101                   ptr = (char *) wcschr ((wchar_t *) ptr, '\0');
102                   /* Skip wide era format.  */
103                   ptr = (char *) wcschr ((wchar_t *) ptr, '\0');
104                 }
105             }
106         }
107
108       era_initialized = 1;
109     }
110
111   /* Now compare date with the available eras.  */
112   for (cnt = 0; cnt < num_eras; ++cnt)
113     if ((eras[cnt]->start_date[0] < tp->tm_year
114          || (eras[cnt]->start_date[0] == tp->tm_year
115              && (eras[cnt]->start_date[1] < tp->tm_mon
116                  || (eras[cnt]->start_date[1] == tp->tm_mon
117                      && eras[cnt]->start_date[2] <= tp->tm_mday))))
118         && (eras[cnt]->stop_date[0] > tp->tm_year
119             || (eras[cnt]->stop_date[0] == tp->tm_year
120                 && (eras[cnt]->stop_date[1] > tp->tm_mon
121                     || (eras[cnt]->stop_date[1] == tp->tm_mon
122                         && eras[cnt]->stop_date[2] >= tp->tm_mday)))))
123       break;
124
125   result = cnt < num_eras ? eras[cnt] : NULL;
126
127   __libc_lock_unlock (__libc_setlocale_lock);
128
129   return result;
130 }
131
132
133 const char *
134 _nl_get_alt_digit (unsigned int number)
135 {
136   const char *result;
137
138   __libc_lock_lock (__libc_setlocale_lock);
139
140   if (alt_digits_initialized == 0)
141     {
142       alt_digits_initialized = 1;
143
144       if (alt_digits == NULL)
145         alt_digits = malloc (100 * sizeof (const char *));
146
147       if (alt_digits != NULL)
148         {
149           const char *ptr = _NL_CURRENT (LC_TIME, ALT_DIGITS);
150           size_t cnt;
151
152           if (alt_digits != NULL)
153             for (cnt = 0; cnt < 100; ++cnt)
154               {
155                 alt_digits[cnt] = ptr;
156
157                 /* Skip digit format. */
158                 ptr = strchr (ptr, '\0') + 1;
159               }
160         }
161     }
162
163   result = alt_digits != NULL && number < 100 ? alt_digits[number] : NULL;
164
165   __libc_lock_unlock (__libc_setlocale_lock);
166
167   return result;
168 }
169
170
171 const wchar_t *
172 _nl_get_walt_digit (unsigned int number)
173 {
174   const wchar_t *result;
175
176   __libc_lock_lock (__libc_setlocale_lock);
177
178   if (walt_digits_initialized == 0)
179     {
180       walt_digits_initialized = 1;
181
182       if (walt_digits == NULL)
183         walt_digits = malloc (100 * sizeof (const uint32_t *));
184
185       if (walt_digits != NULL)
186         {
187           const wchar_t *ptr = _NL_CURRENT_WSTR (LC_TIME, _NL_WALT_DIGITS);
188           size_t cnt;
189
190           for (cnt = 0; cnt < 100; ++cnt)
191             {
192               walt_digits[cnt] = ptr;
193
194               /* Skip digit format. */
195               ptr = wcschr (ptr, L'\0') + 1;
196             }
197         }
198     }
199
200   result = walt_digits != NULL && number < 100 ? walt_digits[number] : NULL;
201
202   __libc_lock_unlock (__libc_setlocale_lock);
203
204   return (wchar_t *) result;
205 }