2 * Copyright (c) 1997 FreeBSD Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/lib/libc/stdtime/timelocal.c,v 1.8.2.2 2000/10/26 16:21:35 ache Exp $
29 #include <sys/types.h>
31 #include <sys/syslimits.h>
38 #include "setlocale.h"
39 #include "timelocal.h"
41 static int split_lines(char *, const char *);
42 static void set_from_buf(const char *, int);
44 struct lc_time_T _time_localebuf
;
45 int _time_using_locale
;
47 #define LCTIME_SIZE_FULL (sizeof(struct lc_time_T) / sizeof(char *))
48 #define LCTIME_SIZE_1 \
49 (offsetof(struct lc_time_T, alt_month[0]) / sizeof(char *))
50 #define LCTIME_SIZE_2 \
51 (offsetof(struct lc_time_T, Ef_fmt) / sizeof(char *))
53 const struct lc_time_T _C_time_locale
= {
55 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
56 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
58 "January", "February", "March", "April", "May", "June",
59 "July", "August", "September", "October", "November", "December"
61 "Sun", "Mon", "Tue", "Wed",
64 "Sunday", "Monday", "Tuesday", "Wednesday",
65 "Thursday", "Friday", "Saturday"
73 ** Since the C language standard calls for
74 ** "date, using locale's date format," anything goes.
75 ** Using just numbers (as here) makes Quakers happier;
76 ** it's also compatible with SVR4.
81 ** c_fmt (ctime-compatible)
82 ** Not used, just compatibility placeholder.
96 "January", "February", "March", "April", "May", "June",
97 "July", "August", "September", "October", "November", "December"
101 ** To determine short months / day order
106 ** To determine long months / day order
113 __time_load_locale(const char *name
)
115 static char * locale_buf
;
116 static char locale_buf_C
[] = "C";
117 static int num_lines
;
123 char filename
[PATH_MAX
];
127 int save_using_locale
;
129 save_using_locale
= _time_using_locale
;
130 _time_using_locale
= 0;
135 if (!strcmp(name
, "C") || !strcmp(name
, "POSIX"))
139 ** If the locale name is the same as our cache, use the cache.
142 if (lbuf
!= NULL
&& strcmp(name
, lbuf
) == 0) {
143 set_from_buf(lbuf
, num_lines
);
144 _time_using_locale
= 1;
148 ** Slurp the locale file into the cache.
150 namesize
= strlen(name
) + 1;
154 /* Range checking not needed, 'name' size is limited */
155 strcpy(filename
, _PathLocale
);
156 strcat(filename
, "/");
157 strcat(filename
, name
);
158 strcat(filename
, "/LC_TIME");
159 fd
= open(filename
, O_RDONLY
);
162 if (fstat(fd
, &st
) != 0)
166 bufsize
= namesize
+ st
.st_size
;
168 lbuf
= (lbuf
== NULL
|| lbuf
== locale_buf_C
) ?
169 malloc(bufsize
) : reallocf(lbuf
, bufsize
);
172 (void) strcpy(lbuf
, name
);
174 plim
= p
+ st
.st_size
;
175 if (read(fd
, p
, (size_t) st
.st_size
) != st
.st_size
)
180 ** Parse the locale file into localebuf.
182 if (plim
[-1] != '\n')
184 num_lines
= split_lines(p
, plim
);
185 if (num_lines
>= LCTIME_SIZE_FULL
)
186 num_lines
= LCTIME_SIZE_FULL
;
187 else if (num_lines
>= LCTIME_SIZE_2
)
188 num_lines
= LCTIME_SIZE_2
;
189 else if (num_lines
>= LCTIME_SIZE_1
)
190 num_lines
= LCTIME_SIZE_1
;
193 set_from_buf(lbuf
, num_lines
);
195 ** Record the successful parse in the cache.
199 _time_using_locale
= 1;
204 * XXX - This may not be the correct thing to do in this case.
205 * setlocale() assumes that we left the old locale alone.
207 locale_buf
= locale_buf_C
;
208 _time_localebuf
= _C_time_locale
;
209 save_using_locale
= 0;
215 _time_using_locale
= save_using_locale
;
220 split_lines(char *p
, const char *plim
)
224 for (i
= 0; p
< plim
; i
++) {
232 set_from_buf(const char *p
, int num_lines
)
237 for (ap
= (const char **) &_time_localebuf
, i
= 0;
238 i
< num_lines
; ++ap
, ++i
)
239 *ap
= p
+= strlen(p
) + 1;
240 if (num_lines
>= LCTIME_SIZE_2
)
242 for (i
= 0; i
< 12; i
++)
243 _time_localebuf
.alt_month
[i
] = _time_localebuf
.month
[i
];