(_nl_load_locale): Compare result of mmap with MAP_FAILED and not -1.
[kopensolaris-gnu/glibc.git] / locale / lc-time.c
1 /* Define current locale data for LC_TIME category.
2    Copyright (C) 1995, 1996, 1997 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 <stdlib.h>
22 #include <string.h>
23 #include <time.h>
24 #include "localeinfo.h"
25
26 _NL_CURRENT_DEFINE (LC_TIME);
27
28 /* Some of the functions here must not be used while setlocale is called.  */
29 __libc_lock_define (extern, __libc_setlocale_lock)
30
31
32 static int era_initialized;
33 static struct era_entry **eras;
34 static size_t num_eras;
35
36
37 static int alt_digits_initialized;
38 static const char **alt_digits;
39 static size_t num_alt_digits;
40
41
42 void
43 _nl_postload_time (void)
44 {
45   /* Prepare lazy initialization of `era' and `alt_digits' array.  */
46   era_initialized = 0;
47   alt_digits_initialized = 0;
48 }
49
50
51 struct era_entry *
52 _nl_get_era_entry (const struct tm *tp)
53 {
54   struct era_entry *result;
55   size_t cnt;
56
57   __libc_lock_lock (__libc_setlocale_lock);
58
59   if (era_initialized == 0)
60     {
61       size_t new_num_eras = _NL_CURRENT_WORD (LC_TIME,
62                                               _NL_TIME_ERA_NUM_ENTRIES);
63
64       if (eras != NULL && new_num_eras == 0)
65         {
66           free (eras);
67           eras = NULL;
68         }
69       else if (new_num_eras != 0)
70         {
71           if (num_eras != new_num_eras)
72             eras = realloc (eras, new_num_eras * sizeof (struct era_entry *));
73
74           if (eras == NULL)
75             num_eras = 0;
76           else
77             {
78 #if __BYTE_ORDER == __LITTLE_ENDIAN
79               const char *ptr = _NL_CURRENT (LC_TIME, _NL_TIME_ERA_ENTRIES_EL);
80 #else
81               const char *ptr = _NL_CURRENT (LC_TIME, _NL_TIME_ERA_ENTRIES_EB);
82 #endif
83               num_eras = new_num_eras;
84
85               for (cnt = 0; cnt < num_eras; ++cnt)
86                 {
87                   eras[cnt] = (struct era_entry *) ptr;
88
89                   /* Skip numeric values.  */
90                   ptr += sizeof (struct era_entry);
91                   /* Skip era name. */
92                   ptr = strchr (ptr, '\0') + 1;
93                   /* Skip era format. */
94                   ptr = strchr (ptr, '\0') + 1;
95
96                   ptr += 3 - (((ptr - (const char *) eras[cnt]) + 3) & 3);
97                 }
98             }
99         }
100
101       era_initialized = 1;
102     }
103
104   /* Now compare date with the available eras.  */
105   for (cnt = 0; cnt < num_eras; ++cnt)
106     if ((eras[cnt]->start_date[0] < tp->tm_year
107          || (eras[cnt]->start_date[0] == tp->tm_year
108              && (eras[cnt]->start_date[1] < tp->tm_mon
109                  || (eras[cnt]->start_date[1] == tp->tm_mon
110                      && eras[cnt]->start_date[2] <= tp->tm_mday))))
111         && (eras[cnt]->stop_date[0] > tp->tm_year
112             || (eras[cnt]->stop_date[0] == tp->tm_year
113                 && (eras[cnt]->stop_date[1] > tp->tm_mon
114                     || (eras[cnt]->stop_date[1] == tp->tm_mon
115                         && eras[cnt]->stop_date[2] >= tp->tm_mday)))))
116       break;
117
118   result = cnt < num_eras ? eras[cnt] : NULL;
119
120   __libc_lock_unlock (__libc_setlocale_lock);
121
122   return result;
123 }
124
125
126 const char *
127 _nl_get_alt_digit (unsigned int number)
128 {
129   const char *result;
130
131   __libc_lock_lock (__libc_setlocale_lock);
132
133   if (alt_digits_initialized == 0)
134     {
135       size_t new_num_alt_digits = _NL_CURRENT_WORD (LC_TIME,
136                                                     _NL_TIME_NUM_ALT_DIGITS);
137
138       if (alt_digits != NULL && new_num_alt_digits == 0)
139         {
140           free (alt_digits);
141           alt_digits = NULL;
142         }
143       else if (new_num_alt_digits != 0)
144         {
145           if (num_alt_digits != new_num_alt_digits)
146             alt_digits = realloc (alt_digits, (new_num_alt_digits
147                                                * sizeof (const char *)));
148
149           if (alt_digits == NULL)
150             num_alt_digits = 0;
151           else
152             {
153               const char *ptr = _NL_CURRENT (LC_TIME, ALT_DIGITS);
154               size_t cnt;
155
156               num_alt_digits = new_num_alt_digits;
157
158               for (cnt = 0; cnt < num_alt_digits; ++cnt)
159                 {
160                   alt_digits[cnt] = ptr;
161
162                   /* Skip digit format. */
163                   ptr = strchr (ptr, '\0') + 1;
164                 }
165             }
166         }
167
168       alt_digits_initialized = 1;
169     }
170
171   result = number < num_alt_digits ? alt_digits[number] : NULL;
172
173   __libc_lock_unlock (__libc_setlocale_lock);
174
175   return result;
176 }