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 * 2637486f03SJoerg Wunsch * $Id$ 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> 3437486f03SJoerg Wunsch #include <stdlib.h> 3537486f03SJoerg Wunsch #include <string.h> 3637486f03SJoerg Wunsch #include "setlocale.h" 3737486f03SJoerg Wunsch #include "timelocal.h" 3837486f03SJoerg Wunsch 3937486f03SJoerg Wunsch struct lc_time_T _time_localebuf; 4037486f03SJoerg Wunsch int _time_using_locale; 4137486f03SJoerg Wunsch 4237486f03SJoerg Wunsch const struct lc_time_T _C_time_locale = { 4337486f03SJoerg Wunsch { 4437486f03SJoerg Wunsch "Jan", "Feb", "Mar", "Apr", "May", "Jun", 4537486f03SJoerg Wunsch "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 4637486f03SJoerg Wunsch }, { 4737486f03SJoerg Wunsch "January", "February", "March", "April", "May", "June", 4837486f03SJoerg Wunsch "July", "August", "September", "October", "November", "December" 4937486f03SJoerg Wunsch }, { 5037486f03SJoerg Wunsch "Sun", "Mon", "Tue", "Wed", 5137486f03SJoerg Wunsch "Thu", "Fri", "Sat" 5237486f03SJoerg Wunsch }, { 5337486f03SJoerg Wunsch "Sunday", "Monday", "Tuesday", "Wednesday", 5437486f03SJoerg Wunsch "Thursday", "Friday", "Saturday" 5537486f03SJoerg Wunsch }, 5637486f03SJoerg Wunsch 5737486f03SJoerg Wunsch /* X_fmt */ 5837486f03SJoerg Wunsch "%H:%M:%S", 5937486f03SJoerg Wunsch 6037486f03SJoerg Wunsch /* 6137486f03SJoerg Wunsch ** x_fmt 6237486f03SJoerg Wunsch ** Since the C language standard calls for 6337486f03SJoerg Wunsch ** "date, using locale's date format," anything goes. 6437486f03SJoerg Wunsch ** Using just numbers (as here) makes Quakers happier; 6537486f03SJoerg Wunsch ** it's also compatible with SVR4. 6637486f03SJoerg Wunsch */ 6737486f03SJoerg Wunsch "%m/%d/%y", 6837486f03SJoerg Wunsch 6937486f03SJoerg Wunsch /* 7037486f03SJoerg Wunsch ** c_fmt (ctime-compatible) 7137486f03SJoerg Wunsch ** Note that 7237486f03SJoerg Wunsch ** "%a %b %d %H:%M:%S %Y" 7337486f03SJoerg Wunsch ** is used by Solaris 2.3. 7437486f03SJoerg Wunsch */ 7537486f03SJoerg Wunsch "%a %b %e %X %Y", 7637486f03SJoerg Wunsch 7737486f03SJoerg Wunsch /* am */ 7837486f03SJoerg Wunsch "AM", 7937486f03SJoerg Wunsch 8037486f03SJoerg Wunsch /* pm */ 8137486f03SJoerg Wunsch "PM", 8237486f03SJoerg Wunsch 8337486f03SJoerg Wunsch /* date_fmt */ 8437486f03SJoerg Wunsch "%a %b %e %X %Z %Y" 8537486f03SJoerg Wunsch }; 8637486f03SJoerg Wunsch 8737486f03SJoerg Wunsch 8837486f03SJoerg Wunsch int 8937486f03SJoerg Wunsch __time_load_locale(const char *name) 9037486f03SJoerg Wunsch { 9137486f03SJoerg Wunsch static char * locale_buf; 9237486f03SJoerg Wunsch static char locale_buf_C[] = "C"; 9337486f03SJoerg Wunsch 9437486f03SJoerg Wunsch int fd; 9537486f03SJoerg Wunsch char * lbuf; 9637486f03SJoerg Wunsch char * p; 9737486f03SJoerg Wunsch const char ** ap; 9837486f03SJoerg Wunsch const char * plim; 9937486f03SJoerg Wunsch char filename[PATH_MAX]; 10037486f03SJoerg Wunsch struct stat st; 10137486f03SJoerg Wunsch size_t namesize; 10237486f03SJoerg Wunsch size_t bufsize; 10337486f03SJoerg Wunsch int save_using_locale; 10437486f03SJoerg Wunsch 10537486f03SJoerg Wunsch save_using_locale = _time_using_locale; 10637486f03SJoerg Wunsch _time_using_locale = 0; 10737486f03SJoerg Wunsch 10837486f03SJoerg Wunsch if (name == NULL) 10937486f03SJoerg Wunsch goto no_locale; 11037486f03SJoerg Wunsch 11137486f03SJoerg Wunsch if (!strcmp(name, "C") || !strcmp(name, "POSIX")) 11237486f03SJoerg Wunsch return 0; 11337486f03SJoerg Wunsch 11437486f03SJoerg Wunsch /* 11537486f03SJoerg Wunsch ** If the locale name is the same as our cache, use the cache. 11637486f03SJoerg Wunsch */ 11737486f03SJoerg Wunsch lbuf = locale_buf; 11837486f03SJoerg Wunsch if (lbuf != NULL && strcmp(name, lbuf) == 0) { 11937486f03SJoerg Wunsch p = lbuf; 12037486f03SJoerg Wunsch for (ap = (const char **) &_time_localebuf; 12137486f03SJoerg Wunsch ap < (const char **) (&_time_localebuf + 1); 12237486f03SJoerg Wunsch ++ap) 12337486f03SJoerg Wunsch *ap = p += strlen(p) + 1; 12437486f03SJoerg Wunsch _time_using_locale = 1; 12537486f03SJoerg Wunsch return 0; 12637486f03SJoerg Wunsch } 12737486f03SJoerg Wunsch /* 12837486f03SJoerg Wunsch ** Slurp the locale file into the cache. 12937486f03SJoerg Wunsch */ 13037486f03SJoerg Wunsch namesize = strlen(name) + 1; 13137486f03SJoerg Wunsch 13237486f03SJoerg Wunsch if (!_PathLocale) 13337486f03SJoerg Wunsch goto no_locale; 13437486f03SJoerg Wunsch /* Range checking not needed, 'name' size is limited */ 13537486f03SJoerg Wunsch strcpy(filename, _PathLocale); 13637486f03SJoerg Wunsch strcat(filename, "/"); 13737486f03SJoerg Wunsch strcat(filename, name); 13837486f03SJoerg Wunsch strcat(filename, "/LC_TIME"); 13937486f03SJoerg Wunsch fd = open(filename, O_RDONLY); 14037486f03SJoerg Wunsch if (fd < 0) 14137486f03SJoerg Wunsch goto no_locale; 14237486f03SJoerg Wunsch if (fstat(fd, &st) != 0) 14337486f03SJoerg Wunsch goto bad_locale; 14437486f03SJoerg Wunsch if (st.st_size <= 0) 14537486f03SJoerg Wunsch goto bad_locale; 14637486f03SJoerg Wunsch bufsize = namesize + st.st_size; 14737486f03SJoerg Wunsch locale_buf = NULL; 14837486f03SJoerg Wunsch lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? 14937486f03SJoerg Wunsch malloc(bufsize) : realloc(lbuf, bufsize); 15037486f03SJoerg Wunsch if (lbuf == NULL) 15137486f03SJoerg Wunsch goto bad_locale; 15237486f03SJoerg Wunsch (void) strcpy(lbuf, name); 15337486f03SJoerg Wunsch p = lbuf + namesize; 15437486f03SJoerg Wunsch plim = p + st.st_size; 15537486f03SJoerg Wunsch if (read(fd, p, (size_t) st.st_size) != st.st_size) 15637486f03SJoerg Wunsch goto bad_lbuf; 15737486f03SJoerg Wunsch if (close(fd) != 0) 15837486f03SJoerg Wunsch goto bad_lbuf; 15937486f03SJoerg Wunsch /* 16037486f03SJoerg Wunsch ** Parse the locale file into localebuf. 16137486f03SJoerg Wunsch */ 16237486f03SJoerg Wunsch if (plim[-1] != '\n') 16337486f03SJoerg Wunsch goto bad_lbuf; 16437486f03SJoerg Wunsch for (ap = (const char **) &_time_localebuf; 16537486f03SJoerg Wunsch ap < (const char **) (&_time_localebuf + 1); 16637486f03SJoerg Wunsch ++ap) { 16737486f03SJoerg Wunsch if (p == plim) 16837486f03SJoerg Wunsch goto reset_locale; 16937486f03SJoerg Wunsch *ap = p; 17037486f03SJoerg Wunsch while (*p != '\n') 17137486f03SJoerg Wunsch ++p; 17237486f03SJoerg Wunsch *p++ = '\0'; 17337486f03SJoerg Wunsch } 17437486f03SJoerg Wunsch /* 17537486f03SJoerg Wunsch ** Record the successful parse in the cache. 17637486f03SJoerg Wunsch */ 17737486f03SJoerg Wunsch locale_buf = lbuf; 17837486f03SJoerg Wunsch 17937486f03SJoerg Wunsch _time_using_locale = 1; 18037486f03SJoerg Wunsch return 0; 18137486f03SJoerg Wunsch 18237486f03SJoerg Wunsch reset_locale: 18337486f03SJoerg Wunsch /* 18437486f03SJoerg Wunsch * XXX - This may not be the correct thing to do in this case. 18537486f03SJoerg Wunsch * setlocale() assumes that we left the old locale alone. 18637486f03SJoerg Wunsch */ 18737486f03SJoerg Wunsch locale_buf = locale_buf_C; 18837486f03SJoerg Wunsch _time_localebuf = _C_time_locale; 18937486f03SJoerg Wunsch save_using_locale = 0; 19037486f03SJoerg Wunsch bad_lbuf: 19137486f03SJoerg Wunsch free(lbuf); 19237486f03SJoerg Wunsch bad_locale: 19337486f03SJoerg Wunsch (void) close(fd); 19437486f03SJoerg Wunsch no_locale: 19537486f03SJoerg Wunsch _time_using_locale = save_using_locale; 19637486f03SJoerg Wunsch return -1; 19737486f03SJoerg Wunsch } 198