xref: /freebsd/lib/libc/locale/ldpart.c (revision 76692b80)
190423eceSAlexey Zelkin /*
274f2b975SAlexey Zelkin  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
390423eceSAlexey Zelkin  * All rights reserved.
490423eceSAlexey Zelkin  *
590423eceSAlexey Zelkin  * Redistribution and use in source and binary forms, with or without
690423eceSAlexey Zelkin  * modification, are permitted provided that the following conditions
790423eceSAlexey Zelkin  * are met:
890423eceSAlexey Zelkin  * 1. Redistributions of source code must retain the above copyright
990423eceSAlexey Zelkin  *    notice, this list of conditions and the following disclaimer.
1090423eceSAlexey Zelkin  * 2. Redistributions in binary form must reproduce the above copyright
1190423eceSAlexey Zelkin  *    notice, this list of conditions and the following disclaimer in the
1290423eceSAlexey Zelkin  *    documentation and/or other materials provided with the distribution.
1390423eceSAlexey Zelkin  *
1490423eceSAlexey Zelkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1590423eceSAlexey Zelkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1690423eceSAlexey Zelkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1790423eceSAlexey Zelkin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1890423eceSAlexey Zelkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1990423eceSAlexey Zelkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2090423eceSAlexey Zelkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2190423eceSAlexey Zelkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2290423eceSAlexey Zelkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2390423eceSAlexey Zelkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2490423eceSAlexey Zelkin  * SUCH DAMAGE.
2590423eceSAlexey Zelkin  */
2690423eceSAlexey Zelkin 
27333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
28333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
29333fc21eSDavid E. O'Brien 
307d2cc62bSAlexey Zelkin #include "namespace.h"
3190423eceSAlexey Zelkin #include <sys/types.h>
3290423eceSAlexey Zelkin #include <sys/stat.h>
3390423eceSAlexey Zelkin #include <sys/syslimits.h>
34f75bb0aaSAndrey A. Chernov #include <errno.h>
3590423eceSAlexey Zelkin #include <fcntl.h>
3690423eceSAlexey Zelkin #include <stdlib.h>
3790423eceSAlexey Zelkin #include <string.h>
38278d1a20SDaniel Eischen #include <unistd.h>
39278d1a20SDaniel Eischen #include "un-namespace.h"
4074f2b975SAlexey Zelkin 
4190423eceSAlexey Zelkin #include "setlocale.h"
4290423eceSAlexey Zelkin #include "ldpart.h"
4390423eceSAlexey Zelkin 
4490423eceSAlexey Zelkin static int split_lines(char *, const char *);
4590423eceSAlexey Zelkin 
4690423eceSAlexey Zelkin int
4790423eceSAlexey Zelkin __part_load_locale(const char *name,
4890423eceSAlexey Zelkin 		int *using_locale,
4990423eceSAlexey Zelkin 		char *locale_buf,
50f43a321bSAlexey Zelkin 		const char *category_filename,
51fc38c1e5SAlexey Zelkin 		int locale_buf_size_max,
52fc38c1e5SAlexey Zelkin 		int locale_buf_size_min,
53f75bb0aaSAndrey A. Chernov 		const char **dst_localebuf)
54f75bb0aaSAndrey A. Chernov {
5576692b80SAndrey A. Chernov 	int		saverr, fd, i, num_lines;
5676692b80SAndrey A. Chernov 	char		*lbuf, *p;
5790423eceSAlexey Zelkin 	const char	*plim;
5890423eceSAlexey Zelkin 	char		filename[PATH_MAX];
5990423eceSAlexey Zelkin 	struct stat	st;
6076692b80SAndrey A. Chernov 	size_t		namesize, bufsize;
6190423eceSAlexey Zelkin 
62f75bb0aaSAndrey A. Chernov 	/* 'name' must be already checked. */
6376692b80SAndrey A. Chernov 	if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) {
6476692b80SAndrey A. Chernov 		*using_locale = 0;
6576692b80SAndrey A. Chernov 		return (_LDP_CACHE);
6676692b80SAndrey A. Chernov 	}
6790423eceSAlexey Zelkin 
6890423eceSAlexey Zelkin 	/*
6974f2b975SAlexey Zelkin 	 * If the locale name is the same as our cache, use the cache.
7090423eceSAlexey Zelkin 	 */
7176692b80SAndrey A. Chernov 	if (locale_buf != NULL && strcmp(name, locale_buf) == 0) {
7290423eceSAlexey Zelkin 		*using_locale = 1;
7376692b80SAndrey A. Chernov 		return (_LDP_CACHE);
7490423eceSAlexey Zelkin 	}
75f43a321bSAlexey Zelkin 
7690423eceSAlexey Zelkin 	/*
7774f2b975SAlexey Zelkin 	 * Slurp the locale file into the cache.
7890423eceSAlexey Zelkin 	 */
7990423eceSAlexey Zelkin 	namesize = strlen(name) + 1;
8090423eceSAlexey Zelkin 
81f75bb0aaSAndrey A. Chernov 	/* 'PathLocale' must be already set & checked. */
8290423eceSAlexey Zelkin 	/* Range checking not needed, 'name' size is limited */
8390423eceSAlexey Zelkin 	strcpy(filename, _PathLocale);
8490423eceSAlexey Zelkin 	strcat(filename, "/");
8590423eceSAlexey Zelkin 	strcat(filename, name);
8690423eceSAlexey Zelkin 	strcat(filename, "/");
87f43a321bSAlexey Zelkin 	strcat(filename, category_filename);
8876692b80SAndrey A. Chernov 	if ((fd = _open(filename, O_RDONLY)) < 0)
8976692b80SAndrey A. Chernov 		return (_LDP_ERROR);
903b5b529fSDaniel Eischen 	if (_fstat(fd, &st) != 0)
9190423eceSAlexey Zelkin 		goto bad_locale;
92f75bb0aaSAndrey A. Chernov 	if (st.st_size <= 0) {
93f75bb0aaSAndrey A. Chernov 		errno = EFTYPE;
9490423eceSAlexey Zelkin 		goto bad_locale;
95f75bb0aaSAndrey A. Chernov 	}
9690423eceSAlexey Zelkin 	bufsize = namesize + st.st_size;
9776692b80SAndrey A. Chernov 	if ((lbuf = malloc(bufsize)) == NULL) {
9876692b80SAndrey A. Chernov 		errno = ENOMEM;
9990423eceSAlexey Zelkin 		goto bad_locale;
10076692b80SAndrey A. Chernov 	}
10190423eceSAlexey Zelkin 	(void)strcpy(lbuf, name);
10290423eceSAlexey Zelkin 	p = lbuf + namesize;
10390423eceSAlexey Zelkin 	plim = p + st.st_size;
10490423eceSAlexey Zelkin 	if (_read(fd, p, (size_t) st.st_size) != st.st_size)
10590423eceSAlexey Zelkin 		goto bad_lbuf;
10690423eceSAlexey Zelkin 	/*
10774f2b975SAlexey Zelkin 	 * Parse the locale file into localebuf.
10890423eceSAlexey Zelkin 	 */
109f75bb0aaSAndrey A. Chernov 	if (plim[-1] != '\n') {
110f75bb0aaSAndrey A. Chernov 		errno = EFTYPE;
11190423eceSAlexey Zelkin 		goto bad_lbuf;
112f75bb0aaSAndrey A. Chernov 	}
11390423eceSAlexey Zelkin 	num_lines = split_lines(p, plim);
114fc38c1e5SAlexey Zelkin 	if (num_lines >= locale_buf_size_max)
115fc38c1e5SAlexey Zelkin 		num_lines = locale_buf_size_max;
116fc38c1e5SAlexey Zelkin 	else if (num_lines >= locale_buf_size_min)
117fc38c1e5SAlexey Zelkin 		num_lines = locale_buf_size_min;
118f75bb0aaSAndrey A. Chernov 	else {
119f75bb0aaSAndrey A. Chernov 		errno = EFTYPE;
12076692b80SAndrey A. Chernov 		goto bad_lbuf;
121f75bb0aaSAndrey A. Chernov 	}
12276692b80SAndrey A. Chernov 	(void)_close(fd);
12390423eceSAlexey Zelkin 	/*
124f43a321bSAlexey Zelkin 	 * Record the successful parse in the cache.
12590423eceSAlexey Zelkin 	 */
12676692b80SAndrey A. Chernov 	if (locale_buf != NULL)
12776692b80SAndrey A. Chernov 		free(locale_buf);
12890423eceSAlexey Zelkin 	locale_buf = lbuf;
12976692b80SAndrey A. Chernov 	for (p = locale_buf, i = 0; i < num_lines; i++)
13076692b80SAndrey A. Chernov 		dst_localebuf[i] = (p += strlen(p) + 1);
13176692b80SAndrey A. Chernov 	for (i = num_lines; i < locale_buf_size_max; i++)
13276692b80SAndrey A. Chernov 		dst_localebuf[i] = NULL;
13390423eceSAlexey Zelkin 	*using_locale = 1;
134ecc4c620SAndrey A. Chernov 
13576692b80SAndrey A. Chernov 	return (_LDP_LOADED);
13690423eceSAlexey Zelkin 
13790423eceSAlexey Zelkin bad_lbuf:
138ecc4c620SAndrey A. Chernov 	saverr = errno;
139ecc4c620SAndrey A. Chernov 	free(lbuf);
140ecc4c620SAndrey A. Chernov 	errno = saverr;
14190423eceSAlexey Zelkin bad_locale:
142ecc4c620SAndrey A. Chernov 	saverr = errno;
143ecc4c620SAndrey A. Chernov 	(void)_close(fd);
144ecc4c620SAndrey A. Chernov 	errno = saverr;
145ecc4c620SAndrey A. Chernov 
14676692b80SAndrey A. Chernov 	return (_LDP_ERROR);
14790423eceSAlexey Zelkin }
14890423eceSAlexey Zelkin 
14990423eceSAlexey Zelkin static int
150ecc4c620SAndrey A. Chernov split_lines(char *p, const char *plim)
151ecc4c620SAndrey A. Chernov {
15290423eceSAlexey Zelkin 	int i;
15390423eceSAlexey Zelkin 
15490423eceSAlexey Zelkin 	for (i = 0; p < plim; i++) {
15590423eceSAlexey Zelkin 		p = strchr(p, '\n');
15690423eceSAlexey Zelkin 		*p++ = '\0';
15790423eceSAlexey Zelkin 	}
158ecc4c620SAndrey A. Chernov 	return (i);
15990423eceSAlexey Zelkin }
16090423eceSAlexey Zelkin 
161