2 * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
3 * at Electronni Visti IA, Kiev, Ukraine.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD: src/lib/libc/locale/collate.c,v 1.33 2004/09/22 16:56:48 stefanf Exp $");
31 #include "namespace.h"
32 #include <arpa/inet.h>
39 #include "un-namespace.h"
42 #include "setlocale.h"
45 #include "libc_private.h"
47 int __collate_load_error
= 1;
48 int __collate_substitute_nontrivial
;
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
;
54 void __collate_err(int ex
, const char *f
) __dead2
;
57 __collate_load_tables(const char *encoding
)
60 int i
, saverr
, chains
;
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];
66 /* 'encoding' must be already checked. */
67 if (strcmp(encoding
, "C") == 0 || strcmp(encoding
, "POSIX") == 0) {
68 __collate_load_error
= 1;
73 * If the locale name is the same as our cache, use the cache.
75 if (strcmp(encoding
, collate_encoding
) == 0) {
76 __collate_load_error
= 0;
81 * Slurp the locale file into the cache.
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
)
93 if (fread(strbuf
, sizeof(strbuf
), 1, fp
) != 1) {
100 if (strcmp(strbuf
, COLLATE_VERSION
) == 0)
102 else if (strcmp(strbuf
, COLLATE_VERSION1_1
) == 0)
110 if (fread(&u32
, sizeof(u32
), 1, fp
) != 1) {
116 if ((chains
= (int)ntohl(u32
)) < 1) {
124 if ((TMP_substitute_table
=
125 malloc(sizeof(__collate_substitute_table
))) == NULL
) {
131 if ((TMP_char_pri_table
=
132 malloc(sizeof(__collate_char_pri_table
))) == NULL
) {
134 free(TMP_substitute_table
);
139 if ((TMP_chain_pri_table
=
140 malloc(sizeof(*__collate_chain_pri_table
) * chains
)) == NULL
) {
142 free(TMP_substitute_table
);
143 free(TMP_char_pri_table
);
149 #define FREAD(a, b, c, d) \
151 if (fread(a, b, c, d) != c) { \
153 free(TMP_substitute_table); \
154 free(TMP_char_pri_table); \
155 free(TMP_chain_pri_table); \
158 return (_LDP_ERROR); \
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
);
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
;
175 if (__collate_chain_pri_table
!= NULL
)
176 free(__collate_chain_pri_table
);
177 __collate_chain_pri_table
= TMP_chain_pri_table
;
179 __collate_substitute_nontrivial
= 0;
180 for (i
= 0; i
< UCHAR_MAX
+ 1; i
++) {
181 if (__collate_substitute_table
[i
][0] != i
||
182 __collate_substitute_table
[i
][1] != 0) {
183 __collate_substitute_nontrivial
= 1;
187 __collate_load_error
= 0;
189 return (_LDP_LOADED
);
193 __collate_substitute(s
)
196 int dest_len
, len
, nlen
;
197 int delta
= strlen(s
);
198 u_char
*dest_str
= NULL
;
200 if (s
== NULL
|| *s
== '\0')
201 return (__collate_strdup(""));
203 dest_str
= malloc(dest_len
= delta
);
204 if (dest_str
== NULL
)
205 __collate_err(EX_OSERR
, __func__
);
208 nlen
= len
+ strlen(__collate_substitute_table
[*s
]);
209 if (dest_len
<= nlen
) {
210 dest_str
= reallocf(dest_str
, dest_len
= nlen
+ delta
);
211 if (dest_str
== NULL
)
212 __collate_err(EX_OSERR
, __func__
);
214 (void)strcpy(dest_str
+ len
, __collate_substitute_table
[*s
++]);
221 __collate_lookup(t
, len
, prim
, sec
)
223 int *len
, *prim
, *sec
;
225 struct __collate_st_chain_pri
*p2
;
229 for (p2
= __collate_chain_pri_table
; p2
->str
[0] != '\0'; p2
++) {
230 if (*t
== p2
->str
[0] &&
231 strncmp(t
, p2
->str
, strlen(p2
->str
)) == 0) {
232 *len
= strlen(p2
->str
);
238 *prim
= __collate_char_pri_table
[*t
].prim
;
239 *sec
= __collate_char_pri_table
[*t
].sec
;
246 u_char
*t
= strdup(s
);
249 __collate_err(EX_OSERR
, __func__
);
254 __collate_err(int ex
, const char *f
)
260 _write(STDERR_FILENO
, s
, strlen(s
));
261 _write(STDERR_FILENO
, ": ", 2);
263 _write(STDERR_FILENO
, s
, strlen(s
));
264 _write(STDERR_FILENO
, ": ", 2);
265 s
= strerror(serrno
);
266 _write(STDERR_FILENO
, s
, strlen(s
));
267 _write(STDERR_FILENO
, "\n", 1);
273 __collate_print_tables()
276 struct __collate_st_chain_pri
*p2
;
278 printf("Substitute table:\n");
279 for (i
= 0; i
< UCHAR_MAX
+ 1; i
++)
280 if (i
!= *__collate_substitute_table
[i
])
281 printf("\t'%c' --> \"%s\"\n", i
,
282 __collate_substitute_table
[i
]);
283 printf("Chain priority table:\n");
284 for (p2
= __collate_chain_pri_table
; p2
->str
[0] != '\0'; p2
++)
285 printf("\t\"%s\" : %d %d\n", p2
->str
, p2
->prim
, p2
->sec
);
286 printf("Char priority table:\n");
287 for (i
= 0; i
< UCHAR_MAX
+ 1; i
++)
288 printf("\t'%c' : %d %d\n", i
, __collate_char_pri_table
[i
].prim
,
289 __collate_char_pri_table
[i
].sec
);