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