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