ldpart.c revision 101498
1/*
2 * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/lib/libc/locale/ldpart.c 101498 2002-08-08 05:51:54Z ache $");
29
30#include "namespace.h"
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <sys/syslimits.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stdlib.h>
37#include <string.h>
38#include <unistd.h>
39#include "un-namespace.h"
40
41#include "setlocale.h"
42#include "ldpart.h"
43
44static int split_lines(char *, const char *);
45
46int
47__part_load_locale(const char *name,
48		int *using_locale,
49		char *locale_buf,
50		const char *category_filename,
51		int locale_buf_size_max,
52		int locale_buf_size_min,
53		const char **dst_localebuf)
54{
55	int		saverr, fd, i, num_lines;
56	char		*lbuf, *p;
57	const char	*plim;
58	char		filename[PATH_MAX];
59	struct stat	st;
60	size_t		namesize, bufsize;
61
62	/* 'name' must be already checked. */
63	if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) {
64		*using_locale = 0;
65		return (_LDP_CACHE);
66	}
67
68	/*
69	 * If the locale name is the same as our cache, use the cache.
70	 */
71	if (locale_buf != NULL && strcmp(name, locale_buf) == 0) {
72		*using_locale = 1;
73		return (_LDP_CACHE);
74	}
75
76	/*
77	 * Slurp the locale file into the cache.
78	 */
79	namesize = strlen(name) + 1;
80
81	/* 'PathLocale' must be already set & checked. */
82	/* Range checking not needed, 'name' size is limited */
83	strcpy(filename, _PathLocale);
84	strcat(filename, "/");
85	strcat(filename, name);
86	strcat(filename, "/");
87	strcat(filename, category_filename);
88	if ((fd = _open(filename, O_RDONLY)) < 0)
89		return (_LDP_ERROR);
90	if (_fstat(fd, &st) != 0)
91		goto bad_locale;
92	if (st.st_size <= 0) {
93		errno = EFTYPE;
94		goto bad_locale;
95	}
96	bufsize = namesize + st.st_size;
97	if ((lbuf = malloc(bufsize)) == NULL) {
98		errno = ENOMEM;
99		goto bad_locale;
100	}
101	(void)strcpy(lbuf, name);
102	p = lbuf + namesize;
103	plim = p + st.st_size;
104	if (_read(fd, p, (size_t) st.st_size) != st.st_size)
105		goto bad_lbuf;
106	/*
107	 * Parse the locale file into localebuf.
108	 */
109	if (plim[-1] != '\n') {
110		errno = EFTYPE;
111		goto bad_lbuf;
112	}
113	num_lines = split_lines(p, plim);
114	if (num_lines >= locale_buf_size_max)
115		num_lines = locale_buf_size_max;
116	else if (num_lines >= locale_buf_size_min)
117		num_lines = locale_buf_size_min;
118	else {
119		errno = EFTYPE;
120		goto bad_lbuf;
121	}
122	(void)_close(fd);
123	/*
124	 * Record the successful parse in the cache.
125	 */
126	if (locale_buf != NULL)
127		free(locale_buf);
128	locale_buf = lbuf;
129	for (p = locale_buf, i = 0; i < num_lines; i++)
130		dst_localebuf[i] = (p += strlen(p) + 1);
131	for (i = num_lines; i < locale_buf_size_max; i++)
132		dst_localebuf[i] = NULL;
133	*using_locale = 1;
134
135	return (_LDP_LOADED);
136
137bad_lbuf:
138	saverr = errno;
139	free(lbuf);
140	errno = saverr;
141bad_locale:
142	saverr = errno;
143	(void)_close(fd);
144	errno = saverr;
145
146	return (_LDP_ERROR);
147}
148
149static int
150split_lines(char *p, const char *plim)
151{
152	int i;
153
154	for (i = 0; p < plim; i++) {
155		p = strchr(p, '\n');
156		*p++ = '\0';
157	}
158	return (i);
159}
160
161