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 2937486f03SJoerg Wunsch #include <sys/types.h> 3037486f03SJoerg Wunsch #include <sys/stat.h> 3137486f03SJoerg Wunsch #include <sys/syslimits.h> 3237486f03SJoerg Wunsch #include <fcntl.h> 3337486f03SJoerg Wunsch #include <locale.h> 34da3785efSDmitrij Tejblum #include <stddef.h> 3537486f03SJoerg Wunsch #include <stdlib.h> 3637486f03SJoerg Wunsch #include <string.h> 3737486f03SJoerg Wunsch #include "setlocale.h" 3837486f03SJoerg Wunsch #include "timelocal.h" 3937486f03SJoerg Wunsch 40da3785efSDmitrij Tejblum static int split_lines(char *, const char *); 41da3785efSDmitrij Tejblum static void set_from_buf(const char *, int); 42da3785efSDmitrij Tejblum 4337486f03SJoerg Wunsch struct lc_time_T _time_localebuf; 4437486f03SJoerg Wunsch int _time_using_locale; 4537486f03SJoerg Wunsch 46da3785efSDmitrij Tejblum #define LCTIME_SIZE_FULL (sizeof(struct lc_time_T) / sizeof(char *)) 47da3785efSDmitrij Tejblum #define LCTIME_SIZE_1 \ 48da3785efSDmitrij Tejblum (offsetof(struct lc_time_T, alt_month[0]) / sizeof(char *)) 4911cd0d32SAndrey A. Chernov #define LCTIME_SIZE_2 \ 5011cd0d32SAndrey A. Chernov (offsetof(struct lc_time_T, Ex_fmt) / sizeof(char *)) 51da3785efSDmitrij Tejblum 5237486f03SJoerg Wunsch const struct lc_time_T _C_time_locale = { 5337486f03SJoerg Wunsch { 5437486f03SJoerg Wunsch "Jan", "Feb", "Mar", "Apr", "May", "Jun", 5537486f03SJoerg Wunsch "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 5637486f03SJoerg Wunsch }, { 5737486f03SJoerg Wunsch "January", "February", "March", "April", "May", "June", 5837486f03SJoerg Wunsch "July", "August", "September", "October", "November", "December" 5937486f03SJoerg Wunsch }, { 6037486f03SJoerg Wunsch "Sun", "Mon", "Tue", "Wed", 6137486f03SJoerg Wunsch "Thu", "Fri", "Sat" 6237486f03SJoerg Wunsch }, { 6337486f03SJoerg Wunsch "Sunday", "Monday", "Tuesday", "Wednesday", 6437486f03SJoerg Wunsch "Thursday", "Friday", "Saturday" 6537486f03SJoerg Wunsch }, 6637486f03SJoerg Wunsch 6737486f03SJoerg Wunsch /* X_fmt */ 6837486f03SJoerg Wunsch "%H:%M:%S", 6937486f03SJoerg Wunsch 7037486f03SJoerg Wunsch /* 7137486f03SJoerg Wunsch ** x_fmt 7237486f03SJoerg Wunsch ** Since the C language standard calls for 7337486f03SJoerg Wunsch ** "date, using locale's date format," anything goes. 7437486f03SJoerg Wunsch ** Using just numbers (as here) makes Quakers happier; 7537486f03SJoerg Wunsch ** it's also compatible with SVR4. 7637486f03SJoerg Wunsch */ 7737486f03SJoerg Wunsch "%m/%d/%y", 7837486f03SJoerg Wunsch 7937486f03SJoerg Wunsch /* 8037486f03SJoerg Wunsch ** c_fmt (ctime-compatible) 8137486f03SJoerg Wunsch ** Note that 8237486f03SJoerg Wunsch ** "%a %b %d %H:%M:%S %Y" 8337486f03SJoerg Wunsch ** is used by Solaris 2.3. 8437486f03SJoerg Wunsch */ 8511cd0d32SAndrey A. Chernov "%a %Ex %X %Y", 8637486f03SJoerg Wunsch 8737486f03SJoerg Wunsch /* am */ 8837486f03SJoerg Wunsch "AM", 8937486f03SJoerg Wunsch 9037486f03SJoerg Wunsch /* pm */ 9137486f03SJoerg Wunsch "PM", 9237486f03SJoerg Wunsch 9337486f03SJoerg Wunsch /* date_fmt */ 9411cd0d32SAndrey A. Chernov "%a %Ex %X %Z %Y", 95da3785efSDmitrij Tejblum 96da3785efSDmitrij Tejblum { 97da3785efSDmitrij Tejblum "January", "February", "March", "April", "May", "June", 98da3785efSDmitrij Tejblum "July", "August", "September", "October", "November", "December" 9911cd0d32SAndrey A. Chernov }, 10011cd0d32SAndrey A. Chernov 10111cd0d32SAndrey A. Chernov /* Ex_fmt 10211cd0d32SAndrey A. Chernov ** To determine months / day order 10311cd0d32SAndrey A. Chernov */ 10411cd0d32SAndrey A. Chernov "%b %e" 10537486f03SJoerg Wunsch }; 10637486f03SJoerg Wunsch 10737486f03SJoerg Wunsch 10837486f03SJoerg Wunsch int 10937486f03SJoerg Wunsch __time_load_locale(const char *name) 11037486f03SJoerg Wunsch { 11137486f03SJoerg Wunsch static char * locale_buf; 11237486f03SJoerg Wunsch static char locale_buf_C[] = "C"; 113da3785efSDmitrij Tejblum static int num_lines; 11437486f03SJoerg Wunsch 11537486f03SJoerg Wunsch int fd; 11637486f03SJoerg Wunsch char * lbuf; 11737486f03SJoerg Wunsch char * p; 11837486f03SJoerg Wunsch const char * plim; 11937486f03SJoerg Wunsch char filename[PATH_MAX]; 12037486f03SJoerg Wunsch struct stat st; 12137486f03SJoerg Wunsch size_t namesize; 12237486f03SJoerg Wunsch size_t bufsize; 12337486f03SJoerg Wunsch int save_using_locale; 12437486f03SJoerg Wunsch 12537486f03SJoerg Wunsch save_using_locale = _time_using_locale; 12637486f03SJoerg Wunsch _time_using_locale = 0; 12737486f03SJoerg Wunsch 12837486f03SJoerg Wunsch if (name == NULL) 12937486f03SJoerg Wunsch goto no_locale; 13037486f03SJoerg Wunsch 13137486f03SJoerg Wunsch if (!strcmp(name, "C") || !strcmp(name, "POSIX")) 13237486f03SJoerg Wunsch return 0; 13337486f03SJoerg Wunsch 13437486f03SJoerg Wunsch /* 13537486f03SJoerg Wunsch ** If the locale name is the same as our cache, use the cache. 13637486f03SJoerg Wunsch */ 13737486f03SJoerg Wunsch lbuf = locale_buf; 13837486f03SJoerg Wunsch if (lbuf != NULL && strcmp(name, lbuf) == 0) { 139da3785efSDmitrij Tejblum set_from_buf(lbuf, num_lines); 14037486f03SJoerg Wunsch _time_using_locale = 1; 14137486f03SJoerg Wunsch return 0; 14237486f03SJoerg Wunsch } 14337486f03SJoerg Wunsch /* 14437486f03SJoerg Wunsch ** Slurp the locale file into the cache. 14537486f03SJoerg Wunsch */ 14637486f03SJoerg Wunsch namesize = strlen(name) + 1; 14737486f03SJoerg Wunsch 14837486f03SJoerg Wunsch if (!_PathLocale) 14937486f03SJoerg Wunsch goto no_locale; 15037486f03SJoerg Wunsch /* Range checking not needed, 'name' size is limited */ 15137486f03SJoerg Wunsch strcpy(filename, _PathLocale); 15237486f03SJoerg Wunsch strcat(filename, "/"); 15337486f03SJoerg Wunsch strcat(filename, name); 15437486f03SJoerg Wunsch strcat(filename, "/LC_TIME"); 15537486f03SJoerg Wunsch fd = open(filename, O_RDONLY); 15637486f03SJoerg Wunsch if (fd < 0) 15737486f03SJoerg Wunsch goto no_locale; 15837486f03SJoerg Wunsch if (fstat(fd, &st) != 0) 15937486f03SJoerg Wunsch goto bad_locale; 16037486f03SJoerg Wunsch if (st.st_size <= 0) 16137486f03SJoerg Wunsch goto bad_locale; 16237486f03SJoerg Wunsch bufsize = namesize + st.st_size; 16337486f03SJoerg Wunsch locale_buf = NULL; 16437486f03SJoerg Wunsch lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? 165e8420087SWarner Losh malloc(bufsize) : reallocf(lbuf, bufsize); 16637486f03SJoerg Wunsch if (lbuf == NULL) 16737486f03SJoerg Wunsch goto bad_locale; 16837486f03SJoerg Wunsch (void) strcpy(lbuf, name); 16937486f03SJoerg Wunsch p = lbuf + namesize; 17037486f03SJoerg Wunsch plim = p + st.st_size; 17137486f03SJoerg Wunsch if (read(fd, p, (size_t) st.st_size) != st.st_size) 17237486f03SJoerg Wunsch goto bad_lbuf; 17337486f03SJoerg Wunsch if (close(fd) != 0) 17437486f03SJoerg Wunsch goto bad_lbuf; 17537486f03SJoerg Wunsch /* 17637486f03SJoerg Wunsch ** Parse the locale file into localebuf. 17737486f03SJoerg Wunsch */ 17837486f03SJoerg Wunsch if (plim[-1] != '\n') 17937486f03SJoerg Wunsch goto bad_lbuf; 180da3785efSDmitrij Tejblum num_lines = split_lines(p, plim); 181da3785efSDmitrij Tejblum if (num_lines >= LCTIME_SIZE_FULL) 182da3785efSDmitrij Tejblum num_lines = LCTIME_SIZE_FULL; 18311cd0d32SAndrey A. Chernov else if (num_lines >= LCTIME_SIZE_2) 18411cd0d32SAndrey A. Chernov num_lines = LCTIME_SIZE_2; 185da3785efSDmitrij Tejblum else if (num_lines >= LCTIME_SIZE_1) 186da3785efSDmitrij Tejblum num_lines = LCTIME_SIZE_1; 187da3785efSDmitrij Tejblum else 18837486f03SJoerg Wunsch goto reset_locale; 189da3785efSDmitrij Tejblum set_from_buf(lbuf, num_lines); 19037486f03SJoerg Wunsch /* 19137486f03SJoerg Wunsch ** Record the successful parse in the cache. 19237486f03SJoerg Wunsch */ 19337486f03SJoerg Wunsch locale_buf = lbuf; 19437486f03SJoerg Wunsch 19537486f03SJoerg Wunsch _time_using_locale = 1; 19637486f03SJoerg Wunsch return 0; 19737486f03SJoerg Wunsch 19837486f03SJoerg Wunsch reset_locale: 19937486f03SJoerg Wunsch /* 20037486f03SJoerg Wunsch * XXX - This may not be the correct thing to do in this case. 20137486f03SJoerg Wunsch * setlocale() assumes that we left the old locale alone. 20237486f03SJoerg Wunsch */ 20337486f03SJoerg Wunsch locale_buf = locale_buf_C; 20437486f03SJoerg Wunsch _time_localebuf = _C_time_locale; 20537486f03SJoerg Wunsch save_using_locale = 0; 20637486f03SJoerg Wunsch bad_lbuf: 20737486f03SJoerg Wunsch free(lbuf); 20837486f03SJoerg Wunsch bad_locale: 20937486f03SJoerg Wunsch (void) close(fd); 21037486f03SJoerg Wunsch no_locale: 21137486f03SJoerg Wunsch _time_using_locale = save_using_locale; 21237486f03SJoerg Wunsch return -1; 21337486f03SJoerg Wunsch } 214da3785efSDmitrij Tejblum 215da3785efSDmitrij Tejblum static int 216da3785efSDmitrij Tejblum split_lines(char *p, const char *plim) 217da3785efSDmitrij Tejblum { 218da3785efSDmitrij Tejblum int i; 219da3785efSDmitrij Tejblum 220da3785efSDmitrij Tejblum for (i = 0; p < plim; i++) { 221da3785efSDmitrij Tejblum p = strchr(p, '\n'); 222da3785efSDmitrij Tejblum *p++ = '\0'; 223da3785efSDmitrij Tejblum } 224da3785efSDmitrij Tejblum return i; 225da3785efSDmitrij Tejblum } 226da3785efSDmitrij Tejblum 227da3785efSDmitrij Tejblum static void 228da3785efSDmitrij Tejblum set_from_buf(const char *p, int num_lines) 229da3785efSDmitrij Tejblum { 230da3785efSDmitrij Tejblum const char **ap; 231da3785efSDmitrij Tejblum int i; 232da3785efSDmitrij Tejblum 233da3785efSDmitrij Tejblum for (ap = (const char **) &_time_localebuf, i = 0; 234da3785efSDmitrij Tejblum i < num_lines; ++ap, ++i) 235da3785efSDmitrij Tejblum *ap = p += strlen(p) + 1; 236da3785efSDmitrij Tejblum if (num_lines == LCTIME_SIZE_FULL) 237da3785efSDmitrij Tejblum return; 238da3785efSDmitrij Tejblum for (i = 0; i < 12; i++) 239da3785efSDmitrij Tejblum _time_localebuf.alt_month[i] = _time_localebuf.month[i]; 240da3785efSDmitrij Tejblum } 241