xref: /freebsd/lib/libc/stdtime/timelocal.c (revision 37486f035f98e16b7c9b023c66c5fc42a6de1835)
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