]>
Commit | Line | Data |
---|---|---|
9385eb3d A |
1 | /*- |
2 | * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> | |
3 | * at Electronni Visti IA, Kiev, Ukraine. | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND | |
16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE | |
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
25 | * SUCH DAMAGE. | |
26 | */ | |
27 | ||
28 | #include <sys/cdefs.h> | |
1f2f436a | 29 | __FBSDID("$FreeBSD: src/lib/libc/locale/collate.c,v 1.35 2005/02/27 20:31:13 ru Exp $"); |
9385eb3d A |
30 | |
31 | #include "namespace.h" | |
32 | #include <arpa/inet.h> | |
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | #include <string.h> | |
36 | #include <errno.h> | |
37 | #include <unistd.h> | |
38 | #include <sysexits.h> | |
39 | #include "un-namespace.h" | |
40 | ||
41 | #include "collate.h" | |
42 | #include "setlocale.h" | |
43 | #include "ldpart.h" | |
44 | ||
45 | #include "libc_private.h" | |
46 | ||
47 | int __collate_load_error = 1; | |
48 | int __collate_substitute_nontrivial; | |
49 | ||
50 | u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; | |
51 | struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; | |
52 | struct __collate_st_chain_pri *__collate_chain_pri_table; | |
53 | ||
54 | void __collate_err(int ex, const char *f) __dead2; | |
55 | ||
56 | int | |
57 | __collate_load_tables(const char *encoding) | |
58 | { | |
59 | FILE *fp; | |
60 | int i, saverr, chains; | |
61 | uint32_t u32; | |
62 | char strbuf[STR_LEN], buf[PATH_MAX]; | |
63 | void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table; | |
64 | static char collate_encoding[ENCODING_LEN + 1]; | |
65 | ||
66 | /* 'encoding' must be already checked. */ | |
67 | if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) { | |
68 | __collate_load_error = 1; | |
69 | return (_LDP_CACHE); | |
70 | } | |
71 | ||
72 | /* | |
73 | * If the locale name is the same as our cache, use the cache. | |
74 | */ | |
75 | if (strcmp(encoding, collate_encoding) == 0) { | |
76 | __collate_load_error = 0; | |
77 | return (_LDP_CACHE); | |
78 | } | |
79 | ||
80 | /* | |
81 | * Slurp the locale file into the cache. | |
82 | */ | |
83 | ||
84 | /* 'PathLocale' must be already set & checked. */ | |
85 | /* Range checking not needed, encoding has fixed size */ | |
86 | (void)strcpy(buf, _PathLocale); | |
87 | (void)strcat(buf, "/"); | |
88 | (void)strcat(buf, encoding); | |
89 | (void)strcat(buf, "/LC_COLLATE"); | |
90 | if ((fp = fopen(buf, "r")) == NULL) | |
91 | return (_LDP_ERROR); | |
92 | ||
93 | if (fread(strbuf, sizeof(strbuf), 1, fp) != 1) { | |
94 | saverr = errno; | |
95 | (void)fclose(fp); | |
96 | errno = saverr; | |
97 | return (_LDP_ERROR); | |
98 | } | |
99 | chains = -1; | |
100 | if (strcmp(strbuf, COLLATE_VERSION) == 0) | |
101 | chains = 0; | |
1f2f436a | 102 | else if (strcmp(strbuf, COLLATE_VERSION1_2) == 0) |
9385eb3d A |
103 | chains = 1; |
104 | if (chains < 0) { | |
105 | (void)fclose(fp); | |
106 | errno = EFTYPE; | |
107 | return (_LDP_ERROR); | |
108 | } | |
109 | if (chains) { | |
110 | if (fread(&u32, sizeof(u32), 1, fp) != 1) { | |
111 | saverr = errno; | |
112 | (void)fclose(fp); | |
113 | errno = saverr; | |
114 | return (_LDP_ERROR); | |
115 | } | |
116 | if ((chains = (int)ntohl(u32)) < 1) { | |
117 | (void)fclose(fp); | |
118 | errno = EFTYPE; | |
119 | return (_LDP_ERROR); | |
120 | } | |
121 | } else | |
122 | chains = TABLE_SIZE; | |
123 | ||
124 | if ((TMP_substitute_table = | |
125 | malloc(sizeof(__collate_substitute_table))) == NULL) { | |
126 | saverr = errno; | |
127 | (void)fclose(fp); | |
128 | errno = saverr; | |
129 | return (_LDP_ERROR); | |
130 | } | |
131 | if ((TMP_char_pri_table = | |
132 | malloc(sizeof(__collate_char_pri_table))) == NULL) { | |
133 | saverr = errno; | |
134 | free(TMP_substitute_table); | |
135 | (void)fclose(fp); | |
136 | errno = saverr; | |
137 | return (_LDP_ERROR); | |
138 | } | |
139 | if ((TMP_chain_pri_table = | |
140 | malloc(sizeof(*__collate_chain_pri_table) * chains)) == NULL) { | |
141 | saverr = errno; | |
142 | free(TMP_substitute_table); | |
143 | free(TMP_char_pri_table); | |
144 | (void)fclose(fp); | |
145 | errno = saverr; | |
146 | return (_LDP_ERROR); | |
147 | } | |
148 | ||
149 | #define FREAD(a, b, c, d) \ | |
150 | { \ | |
151 | if (fread(a, b, c, d) != c) { \ | |
152 | saverr = errno; \ | |
153 | free(TMP_substitute_table); \ | |
154 | free(TMP_char_pri_table); \ | |
155 | free(TMP_chain_pri_table); \ | |
156 | (void)fclose(d); \ | |
157 | errno = saverr; \ | |
158 | return (_LDP_ERROR); \ | |
159 | } \ | |
160 | } | |
161 | ||
162 | FREAD(TMP_substitute_table, sizeof(__collate_substitute_table), 1, fp); | |
163 | FREAD(TMP_char_pri_table, sizeof(__collate_char_pri_table), 1, fp); | |
164 | FREAD(TMP_chain_pri_table, | |
165 | sizeof(*__collate_chain_pri_table), chains, fp); | |
166 | (void)fclose(fp); | |
167 | ||
168 | (void)strcpy(collate_encoding, encoding); | |
169 | if (__collate_substitute_table_ptr != NULL) | |
170 | free(__collate_substitute_table_ptr); | |
171 | __collate_substitute_table_ptr = TMP_substitute_table; | |
172 | if (__collate_char_pri_table_ptr != NULL) | |
173 | free(__collate_char_pri_table_ptr); | |
174 | __collate_char_pri_table_ptr = TMP_char_pri_table; | |
1f2f436a A |
175 | for (i = 0; i < UCHAR_MAX + 1; i++) { |
176 | __collate_char_pri_table[i].prim = | |
177 | ntohl(__collate_char_pri_table[i].prim); | |
178 | __collate_char_pri_table[i].sec = | |
179 | ntohl(__collate_char_pri_table[i].sec); | |
180 | } | |
9385eb3d A |
181 | if (__collate_chain_pri_table != NULL) |
182 | free(__collate_chain_pri_table); | |
183 | __collate_chain_pri_table = TMP_chain_pri_table; | |
1f2f436a A |
184 | for (i = 0; i < chains; i++) { |
185 | __collate_chain_pri_table[i].prim = | |
186 | ntohl(__collate_chain_pri_table[i].prim); | |
187 | __collate_chain_pri_table[i].sec = | |
188 | ntohl(__collate_chain_pri_table[i].sec); | |
189 | } | |
9385eb3d A |
190 | __collate_substitute_nontrivial = 0; |
191 | for (i = 0; i < UCHAR_MAX + 1; i++) { | |
192 | if (__collate_substitute_table[i][0] != i || | |
193 | __collate_substitute_table[i][1] != 0) { | |
194 | __collate_substitute_nontrivial = 1; | |
195 | break; | |
196 | } | |
197 | } | |
198 | __collate_load_error = 0; | |
199 | ||
200 | return (_LDP_LOADED); | |
201 | } | |
202 | ||
203 | u_char * | |
1f2f436a | 204 | __collate_substitute(const u_char *s) |
9385eb3d A |
205 | { |
206 | int dest_len, len, nlen; | |
207 | int delta = strlen(s); | |
208 | u_char *dest_str = NULL; | |
209 | ||
210 | if (s == NULL || *s == '\0') | |
211 | return (__collate_strdup("")); | |
212 | delta += delta / 8; | |
213 | dest_str = malloc(dest_len = delta); | |
214 | if (dest_str == NULL) | |
3d9156a7 | 215 | __collate_err(EX_OSERR, __func__); |
9385eb3d A |
216 | len = 0; |
217 | while (*s) { | |
218 | nlen = len + strlen(__collate_substitute_table[*s]); | |
219 | if (dest_len <= nlen) { | |
220 | dest_str = reallocf(dest_str, dest_len = nlen + delta); | |
221 | if (dest_str == NULL) | |
3d9156a7 | 222 | __collate_err(EX_OSERR, __func__); |
9385eb3d A |
223 | } |
224 | (void)strcpy(dest_str + len, __collate_substitute_table[*s++]); | |
225 | len = nlen; | |
226 | } | |
227 | return (dest_str); | |
228 | } | |
229 | ||
230 | void | |
1f2f436a | 231 | __collate_lookup(const u_char *t, int *len, int *prim, int *sec) |
9385eb3d A |
232 | { |
233 | struct __collate_st_chain_pri *p2; | |
234 | ||
235 | *len = 1; | |
236 | *prim = *sec = 0; | |
237 | for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++) { | |
238 | if (*t == p2->str[0] && | |
239 | strncmp(t, p2->str, strlen(p2->str)) == 0) { | |
240 | *len = strlen(p2->str); | |
241 | *prim = p2->prim; | |
242 | *sec = p2->sec; | |
243 | return; | |
244 | } | |
245 | } | |
246 | *prim = __collate_char_pri_table[*t].prim; | |
247 | *sec = __collate_char_pri_table[*t].sec; | |
248 | } | |
249 | ||
250 | u_char * | |
1f2f436a | 251 | __collate_strdup(u_char *s) |
9385eb3d A |
252 | { |
253 | u_char *t = strdup(s); | |
254 | ||
255 | if (t == NULL) | |
3d9156a7 | 256 | __collate_err(EX_OSERR, __func__); |
9385eb3d A |
257 | return (t); |
258 | } | |
259 | ||
260 | void | |
261 | __collate_err(int ex, const char *f) | |
262 | { | |
263 | const char *s; | |
264 | int serrno = errno; | |
265 | ||
266 | s = _getprogname(); | |
267 | _write(STDERR_FILENO, s, strlen(s)); | |
268 | _write(STDERR_FILENO, ": ", 2); | |
269 | s = f; | |
270 | _write(STDERR_FILENO, s, strlen(s)); | |
271 | _write(STDERR_FILENO, ": ", 2); | |
272 | s = strerror(serrno); | |
273 | _write(STDERR_FILENO, s, strlen(s)); | |
274 | _write(STDERR_FILENO, "\n", 1); | |
275 | exit(ex); | |
276 | } | |
277 | ||
278 | #ifdef COLLATE_DEBUG | |
279 | void | |
280 | __collate_print_tables() | |
281 | { | |
282 | int i; | |
283 | struct __collate_st_chain_pri *p2; | |
284 | ||
285 | printf("Substitute table:\n"); | |
286 | for (i = 0; i < UCHAR_MAX + 1; i++) | |
287 | if (i != *__collate_substitute_table[i]) | |
288 | printf("\t'%c' --> \"%s\"\n", i, | |
289 | __collate_substitute_table[i]); | |
290 | printf("Chain priority table:\n"); | |
291 | for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++) | |
292 | printf("\t\"%s\" : %d %d\n", p2->str, p2->prim, p2->sec); | |
293 | printf("Char priority table:\n"); | |
294 | for (i = 0; i < UCHAR_MAX + 1; i++) | |
295 | printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim, | |
296 | __collate_char_pri_table[i].sec); | |
297 | } | |
298 | #endif |