137486f03SJoerg Wunsch /*- 237486f03SJoerg Wunsch * Copyright (c) 1997 FreeBSD Inc. 337486f03SJoerg Wunsch * All rights reserved. 437486f03SJoerg Wunsch * 537486f03SJoerg Wunsch * Redistribution and use in source and binary forms, with or without 637486f03SJoerg Wunsch * modification, are permitted provided that the following conditions 737486f03SJoerg Wunsch * are met: 837486f03SJoerg Wunsch * 1. Redistributions of source code must retain the above copyright 937486f03SJoerg Wunsch * notice, this list of conditions and the following disclaimer. 1037486f03SJoerg Wunsch * 2. Redistributions in binary form must reproduce the above copyright 1137486f03SJoerg Wunsch * notice, this list of conditions and the following disclaimer in the 1237486f03SJoerg Wunsch * documentation and/or other materials provided with the distribution. 1337486f03SJoerg Wunsch * 1437486f03SJoerg Wunsch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1537486f03SJoerg Wunsch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1637486f03SJoerg Wunsch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1737486f03SJoerg Wunsch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1837486f03SJoerg Wunsch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1937486f03SJoerg Wunsch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2037486f03SJoerg Wunsch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2137486f03SJoerg Wunsch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2237486f03SJoerg Wunsch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2337486f03SJoerg Wunsch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2437486f03SJoerg Wunsch * SUCH DAMAGE. 2537486f03SJoerg Wunsch * 267f3dea24SPeter Wemm * $FreeBSD$ 2737486f03SJoerg Wunsch */ 2837486f03SJoerg Wunsch 29d201fe46SDaniel Eischen #include "namespace.h" 3037486f03SJoerg Wunsch #include <sys/types.h> 3137486f03SJoerg Wunsch #include <sys/stat.h> 3237486f03SJoerg Wunsch #include <sys/syslimits.h> 3337486f03SJoerg Wunsch #include <fcntl.h> 3437486f03SJoerg Wunsch #include <locale.h> 35da3785efSDmitrij Tejblum #include <stddef.h> 3637486f03SJoerg Wunsch #include <stdlib.h> 3737486f03SJoerg Wunsch #include <string.h> 38d201fe46SDaniel Eischen #include <unistd.h> 39d201fe46SDaniel Eischen #include "un-namespace.h" 40d201fe46SDaniel Eischen 4137486f03SJoerg Wunsch #include "setlocale.h" 4237486f03SJoerg Wunsch #include "timelocal.h" 4337486f03SJoerg Wunsch 44da3785efSDmitrij Tejblum static int split_lines(char *, const char *); 45da3785efSDmitrij Tejblum static void set_from_buf(const char *, int); 46da3785efSDmitrij Tejblum 4718f3e1e4SAlexey Zelkin static struct lc_time_T _time_localebuf; 4818f3e1e4SAlexey Zelkin static int _time_using_locale; 4937486f03SJoerg Wunsch 50da3785efSDmitrij Tejblum #define LCTIME_SIZE_FULL (sizeof(struct lc_time_T) / sizeof(char *)) 51da3785efSDmitrij Tejblum #define LCTIME_SIZE_1 \ 52da3785efSDmitrij Tejblum (offsetof(struct lc_time_T, alt_month[0]) / sizeof(char *)) 5311cd0d32SAndrey A. Chernov #define LCTIME_SIZE_2 \ 54c63a4303SAndrey A. Chernov (offsetof(struct lc_time_T, Ef_fmt) / sizeof(char *)) 55da3785efSDmitrij Tejblum 5618f3e1e4SAlexey Zelkin static const struct lc_time_T _C_time_locale = { 5737486f03SJoerg Wunsch { 5837486f03SJoerg Wunsch "Jan", "Feb", "Mar", "Apr", "May", "Jun", 5937486f03SJoerg Wunsch "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 6037486f03SJoerg Wunsch }, { 6137486f03SJoerg Wunsch "January", "February", "March", "April", "May", "June", 6237486f03SJoerg Wunsch "July", "August", "September", "October", "November", "December" 6337486f03SJoerg Wunsch }, { 6437486f03SJoerg Wunsch "Sun", "Mon", "Tue", "Wed", 6537486f03SJoerg Wunsch "Thu", "Fri", "Sat" 6637486f03SJoerg Wunsch }, { 6737486f03SJoerg Wunsch "Sunday", "Monday", "Tuesday", "Wednesday", 6837486f03SJoerg Wunsch "Thursday", "Friday", "Saturday" 6937486f03SJoerg Wunsch }, 7037486f03SJoerg Wunsch 7137486f03SJoerg Wunsch /* X_fmt */ 7237486f03SJoerg Wunsch "%H:%M:%S", 7337486f03SJoerg Wunsch 7437486f03SJoerg Wunsch /* 7537486f03SJoerg Wunsch ** x_fmt 7637486f03SJoerg Wunsch ** Since the C language standard calls for 7737486f03SJoerg Wunsch ** "date, using locale's date format," anything goes. 7837486f03SJoerg Wunsch ** Using just numbers (as here) makes Quakers happier; 7937486f03SJoerg Wunsch ** it's also compatible with SVR4. 8037486f03SJoerg Wunsch */ 8137486f03SJoerg Wunsch "%m/%d/%y", 8237486f03SJoerg Wunsch 8337486f03SJoerg Wunsch /* 8437486f03SJoerg Wunsch ** c_fmt (ctime-compatible) 85aabf7d45SAndrey A. Chernov ** Not used, just compatibility placeholder. 8637486f03SJoerg Wunsch */ 87aabf7d45SAndrey A. Chernov NULL, 8837486f03SJoerg Wunsch 8937486f03SJoerg Wunsch /* am */ 9037486f03SJoerg Wunsch "AM", 9137486f03SJoerg Wunsch 9237486f03SJoerg Wunsch /* pm */ 9337486f03SJoerg Wunsch "PM", 9437486f03SJoerg Wunsch 9537486f03SJoerg Wunsch /* date_fmt */ 96c63a4303SAndrey A. Chernov "%a %Ef %X %Z %Y", 97da3785efSDmitrij Tejblum 98da3785efSDmitrij Tejblum { 99da3785efSDmitrij Tejblum "January", "February", "March", "April", "May", "June", 100da3785efSDmitrij Tejblum "July", "August", "September", "October", "November", "December" 10111cd0d32SAndrey A. Chernov }, 10211cd0d32SAndrey A. Chernov 103c63a4303SAndrey A. Chernov /* Ef_fmt 104c63a4303SAndrey A. Chernov ** To determine short months / day order 10511cd0d32SAndrey A. Chernov */ 106c63a4303SAndrey A. Chernov "%b %e", 107c63a4303SAndrey A. Chernov 108c63a4303SAndrey A. Chernov /* EF_fmt 109c63a4303SAndrey A. Chernov ** To determine long months / day order 110c63a4303SAndrey A. Chernov */ 111c63a4303SAndrey A. Chernov "%B %e" 11237486f03SJoerg Wunsch }; 11337486f03SJoerg Wunsch 11418f3e1e4SAlexey Zelkin struct lc_time_T * 11518f3e1e4SAlexey Zelkin __get_current_time_locale(void) { 11618f3e1e4SAlexey Zelkin return (_time_using_locale 11718f3e1e4SAlexey Zelkin ? &_time_localebuf 11818f3e1e4SAlexey Zelkin : (struct lc_time_T *)&_C_time_locale); 11918f3e1e4SAlexey Zelkin } 12037486f03SJoerg Wunsch 12137486f03SJoerg Wunsch int 12237486f03SJoerg Wunsch __time_load_locale(const char *name) 12337486f03SJoerg Wunsch { 12437486f03SJoerg Wunsch static char * locale_buf; 12537486f03SJoerg Wunsch static char locale_buf_C[] = "C"; 126da3785efSDmitrij Tejblum static int num_lines; 12737486f03SJoerg Wunsch 12837486f03SJoerg Wunsch int fd; 12937486f03SJoerg Wunsch char * lbuf; 13037486f03SJoerg Wunsch char * p; 13137486f03SJoerg Wunsch const char * plim; 13237486f03SJoerg Wunsch char filename[PATH_MAX]; 13337486f03SJoerg Wunsch struct stat st; 13437486f03SJoerg Wunsch size_t namesize; 13537486f03SJoerg Wunsch size_t bufsize; 13637486f03SJoerg Wunsch int save_using_locale; 13737486f03SJoerg Wunsch 13837486f03SJoerg Wunsch save_using_locale = _time_using_locale; 13937486f03SJoerg Wunsch _time_using_locale = 0; 14037486f03SJoerg Wunsch 14137486f03SJoerg Wunsch if (name == NULL) 14237486f03SJoerg Wunsch goto no_locale; 14337486f03SJoerg Wunsch 14437486f03SJoerg Wunsch if (!strcmp(name, "C") || !strcmp(name, "POSIX")) 14537486f03SJoerg Wunsch return 0; 14637486f03SJoerg Wunsch 14737486f03SJoerg Wunsch /* 14837486f03SJoerg Wunsch ** If the locale name is the same as our cache, use the cache. 14937486f03SJoerg Wunsch */ 15037486f03SJoerg Wunsch lbuf = locale_buf; 15137486f03SJoerg Wunsch if (lbuf != NULL && strcmp(name, lbuf) == 0) { 152da3785efSDmitrij Tejblum set_from_buf(lbuf, num_lines); 15337486f03SJoerg Wunsch _time_using_locale = 1; 15437486f03SJoerg Wunsch return 0; 15537486f03SJoerg Wunsch } 15637486f03SJoerg Wunsch /* 15737486f03SJoerg Wunsch ** Slurp the locale file into the cache. 15837486f03SJoerg Wunsch */ 15937486f03SJoerg Wunsch namesize = strlen(name) + 1; 16037486f03SJoerg Wunsch 16137486f03SJoerg Wunsch if (!_PathLocale) 16237486f03SJoerg Wunsch goto no_locale; 16337486f03SJoerg Wunsch /* Range checking not needed, 'name' size is limited */ 16437486f03SJoerg Wunsch strcpy(filename, _PathLocale); 16537486f03SJoerg Wunsch strcat(filename, "/"); 16637486f03SJoerg Wunsch strcat(filename, name); 16737486f03SJoerg Wunsch strcat(filename, "/LC_TIME"); 1689233c4d9SJason Evans fd = _open(filename, O_RDONLY); 16937486f03SJoerg Wunsch if (fd < 0) 17037486f03SJoerg Wunsch goto no_locale; 171d201fe46SDaniel Eischen if (_fstat(fd, &st) != 0) 17237486f03SJoerg Wunsch goto bad_locale; 17337486f03SJoerg Wunsch if (st.st_size <= 0) 17437486f03SJoerg Wunsch goto bad_locale; 17537486f03SJoerg Wunsch bufsize = namesize + st.st_size; 17637486f03SJoerg Wunsch locale_buf = NULL; 17737486f03SJoerg Wunsch lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? 178e8420087SWarner Losh malloc(bufsize) : reallocf(lbuf, bufsize); 17937486f03SJoerg Wunsch if (lbuf == NULL) 18037486f03SJoerg Wunsch goto bad_locale; 18137486f03SJoerg Wunsch (void) strcpy(lbuf, name); 18237486f03SJoerg Wunsch p = lbuf + namesize; 18337486f03SJoerg Wunsch plim = p + st.st_size; 1849233c4d9SJason Evans if (_read(fd, p, (size_t) st.st_size) != st.st_size) 18537486f03SJoerg Wunsch goto bad_lbuf; 1869233c4d9SJason Evans if (_close(fd) != 0) 18737486f03SJoerg Wunsch goto bad_lbuf; 18837486f03SJoerg Wunsch /* 18937486f03SJoerg Wunsch ** Parse the locale file into localebuf. 19037486f03SJoerg Wunsch */ 19137486f03SJoerg Wunsch if (plim[-1] != '\n') 19237486f03SJoerg Wunsch goto bad_lbuf; 193da3785efSDmitrij Tejblum num_lines = split_lines(p, plim); 194da3785efSDmitrij Tejblum if (num_lines >= LCTIME_SIZE_FULL) 195da3785efSDmitrij Tejblum num_lines = LCTIME_SIZE_FULL; 19611cd0d32SAndrey A. Chernov else if (num_lines >= LCTIME_SIZE_2) 19711cd0d32SAndrey A. Chernov num_lines = LCTIME_SIZE_2; 198da3785efSDmitrij Tejblum else if (num_lines >= LCTIME_SIZE_1) 199da3785efSDmitrij Tejblum num_lines = LCTIME_SIZE_1; 200da3785efSDmitrij Tejblum else 20137486f03SJoerg Wunsch goto reset_locale; 202da3785efSDmitrij Tejblum set_from_buf(lbuf, num_lines); 20337486f03SJoerg Wunsch /* 20437486f03SJoerg Wunsch ** Record the successful parse in the cache. 20537486f03SJoerg Wunsch */ 20637486f03SJoerg Wunsch locale_buf = lbuf; 20737486f03SJoerg Wunsch 20837486f03SJoerg Wunsch _time_using_locale = 1; 20937486f03SJoerg Wunsch return 0; 21037486f03SJoerg Wunsch 21137486f03SJoerg Wunsch reset_locale: 21237486f03SJoerg Wunsch /* 21337486f03SJoerg Wunsch * XXX - This may not be the correct thing to do in this case. 21437486f03SJoerg Wunsch * setlocale() assumes that we left the old locale alone. 21537486f03SJoerg Wunsch */ 21637486f03SJoerg Wunsch locale_buf = locale_buf_C; 21737486f03SJoerg Wunsch _time_localebuf = _C_time_locale; 21837486f03SJoerg Wunsch save_using_locale = 0; 21937486f03SJoerg Wunsch bad_lbuf: 22037486f03SJoerg Wunsch free(lbuf); 22137486f03SJoerg Wunsch bad_locale: 2229233c4d9SJason Evans (void)_close(fd); 22337486f03SJoerg Wunsch no_locale: 22437486f03SJoerg Wunsch _time_using_locale = save_using_locale; 22537486f03SJoerg Wunsch return -1; 22637486f03SJoerg Wunsch } 227da3785efSDmitrij Tejblum 228da3785efSDmitrij Tejblum static int 229da3785efSDmitrij Tejblum split_lines(char *p, const char *plim) 230da3785efSDmitrij Tejblum { 231da3785efSDmitrij Tejblum int i; 232da3785efSDmitrij Tejblum 233da3785efSDmitrij Tejblum for (i = 0; p < plim; i++) { 234da3785efSDmitrij Tejblum p = strchr(p, '\n'); 235da3785efSDmitrij Tejblum *p++ = '\0'; 236da3785efSDmitrij Tejblum } 237da3785efSDmitrij Tejblum return i; 238da3785efSDmitrij Tejblum } 239da3785efSDmitrij Tejblum 240da3785efSDmitrij Tejblum static void 241da3785efSDmitrij Tejblum set_from_buf(const char *p, int num_lines) 242da3785efSDmitrij Tejblum { 243da3785efSDmitrij Tejblum const char **ap; 244da3785efSDmitrij Tejblum int i; 245da3785efSDmitrij Tejblum 246da3785efSDmitrij Tejblum for (ap = (const char **) &_time_localebuf, i = 0; 247da3785efSDmitrij Tejblum i < num_lines; ++ap, ++i) 248da3785efSDmitrij Tejblum *ap = p += strlen(p) + 1; 249849c64f5SAndrey A. Chernov if (num_lines >= LCTIME_SIZE_2) 250da3785efSDmitrij Tejblum return; 251da3785efSDmitrij Tejblum for (i = 0; i < 12; i++) 252da3785efSDmitrij Tejblum _time_localebuf.alt_month[i] = _time_localebuf.month[i]; 253da3785efSDmitrij Tejblum } 254