xref: /freebsd/lib/libc/locale/collate.c (revision 3c87aa1d3dc1d8dad3efad322852a8e1e76dee55)
1c3d0cca4SAndrey A. Chernov /*-
2c3d0cca4SAndrey A. Chernov  * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
3c3d0cca4SAndrey A. Chernov  *		at Electronni Visti IA, Kiev, Ukraine.
4c3d0cca4SAndrey A. Chernov  *			All rights reserved.
5c3d0cca4SAndrey A. Chernov  *
6*3c87aa1dSDavid Chisnall  * Copyright (c) 2011 The FreeBSD Foundation
7*3c87aa1dSDavid Chisnall  * All rights reserved.
8*3c87aa1dSDavid Chisnall  * Portions of this software were developed by David Chisnall
9*3c87aa1dSDavid Chisnall  * under sponsorship from the FreeBSD Foundation.
10*3c87aa1dSDavid Chisnall  *
11*3c87aa1dSDavid Chisnall  * Copyright (c) 2011 The FreeBSD Foundation
12*3c87aa1dSDavid Chisnall  * All rights reserved.
13*3c87aa1dSDavid Chisnall  * Portions of this software were developed by David Chisnall
14*3c87aa1dSDavid Chisnall  * under sponsorship from the FreeBSD Foundation.
15*3c87aa1dSDavid Chisnall  *
16c3d0cca4SAndrey A. Chernov  * Redistribution and use in source and binary forms, with or without
17c3d0cca4SAndrey A. Chernov  * modification, are permitted provided that the following conditions
18c3d0cca4SAndrey A. Chernov  * are met:
19c3d0cca4SAndrey A. Chernov  * 1. Redistributions of source code must retain the above copyright
20c3d0cca4SAndrey A. Chernov  *    notice, this list of conditions and the following disclaimer.
21c3d0cca4SAndrey A. Chernov  * 2. Redistributions in binary form must reproduce the above copyright
22c3d0cca4SAndrey A. Chernov  *    notice, this list of conditions and the following disclaimer in the
23c3d0cca4SAndrey A. Chernov  *    documentation and/or other materials provided with the distribution.
24c3d0cca4SAndrey A. Chernov  *
25c3d0cca4SAndrey A. Chernov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
26c3d0cca4SAndrey A. Chernov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27c3d0cca4SAndrey A. Chernov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28c3d0cca4SAndrey A. Chernov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
29c3d0cca4SAndrey A. Chernov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30c3d0cca4SAndrey A. Chernov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31c3d0cca4SAndrey A. Chernov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32c3d0cca4SAndrey A. Chernov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33c3d0cca4SAndrey A. Chernov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34c3d0cca4SAndrey A. Chernov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35c3d0cca4SAndrey A. Chernov  * SUCH DAMAGE.
36c3d0cca4SAndrey A. Chernov  */
37c3d0cca4SAndrey A. Chernov 
38333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
39333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
40333fc21eSDavid E. O'Brien 
41d201fe46SDaniel Eischen #include "namespace.h"
42c1417061SAndrey A. Chernov #include <arpa/inet.h>
43c3d0cca4SAndrey A. Chernov #include <stdio.h>
44c3d0cca4SAndrey A. Chernov #include <stdlib.h>
45c3d0cca4SAndrey A. Chernov #include <string.h>
46926f20c9SAndrey A. Chernov #include <errno.h>
47926f20c9SAndrey A. Chernov #include <unistd.h>
48c3d0cca4SAndrey A. Chernov #include <sysexits.h>
49d201fe46SDaniel Eischen #include "un-namespace.h"
50d201fe46SDaniel Eischen 
51c3d0cca4SAndrey A. Chernov #include "collate.h"
5263407d34SAndrey A. Chernov #include "setlocale.h"
5376692b80SAndrey A. Chernov #include "ldpart.h"
54c3d0cca4SAndrey A. Chernov 
554cd01193SMark Murray #include "libc_private.h"
564cd01193SMark Murray 
57*3c87aa1dSDavid Chisnall /*
58*3c87aa1dSDavid Chisnall  * To avoid modifying the original (single-threaded) code too much, we'll just
59*3c87aa1dSDavid Chisnall  * define the old globals as fields inside the table.
60*3c87aa1dSDavid Chisnall  *
61*3c87aa1dSDavid Chisnall  * We also modify the collation table test functions to search the thread-local
62*3c87aa1dSDavid Chisnall  * table first and the global table second.
63*3c87aa1dSDavid Chisnall  */
64*3c87aa1dSDavid Chisnall #define __collate_load_error (table->__collate_load_error)
65*3c87aa1dSDavid Chisnall #define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial)
66*3c87aa1dSDavid Chisnall #define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
67*3c87aa1dSDavid Chisnall #define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
68*3c87aa1dSDavid Chisnall #define __collate_chain_pri_table (table->__collate_chain_pri_table)
6976692b80SAndrey A. Chernov 
70*3c87aa1dSDavid Chisnall 
71*3c87aa1dSDavid Chisnall struct xlocale_collate __xlocale_global_collate = {
72*3c87aa1dSDavid Chisnall 	{{0}, "C"}, 1, 0
73*3c87aa1dSDavid Chisnall };
74*3c87aa1dSDavid Chisnall 
75*3c87aa1dSDavid Chisnall  struct xlocale_collate __xlocale_C_collate = {
76*3c87aa1dSDavid Chisnall 	{{0}, "C"}, 1, 0
77*3c87aa1dSDavid Chisnall };
78c3d0cca4SAndrey A. Chernov 
79eaa86f9dSBruce Evans void __collate_err(int ex, const char *f) __dead2;
80926f20c9SAndrey A. Chernov 
81c3d0cca4SAndrey A. Chernov int
82*3c87aa1dSDavid Chisnall __collate_load_tables_l(const char *encoding, struct xlocale_collate *table);
83*3c87aa1dSDavid Chisnall 
84*3c87aa1dSDavid Chisnall static void
85*3c87aa1dSDavid Chisnall destruct_collate(void *t)
86*3c87aa1dSDavid Chisnall {
87*3c87aa1dSDavid Chisnall 	struct xlocale_collate *table = t;
88*3c87aa1dSDavid Chisnall 	if (__collate_chain_pri_table) {
89*3c87aa1dSDavid Chisnall 		free(__collate_chain_pri_table);
90*3c87aa1dSDavid Chisnall 	}
91*3c87aa1dSDavid Chisnall 	free(t);
92*3c87aa1dSDavid Chisnall }
93*3c87aa1dSDavid Chisnall 
94*3c87aa1dSDavid Chisnall void *
95*3c87aa1dSDavid Chisnall __collate_load(const char *encoding, locale_t unused)
96*3c87aa1dSDavid Chisnall {
97*3c87aa1dSDavid Chisnall 	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
98*3c87aa1dSDavid Chisnall 		return &__xlocale_C_collate;
99*3c87aa1dSDavid Chisnall 	}
100*3c87aa1dSDavid Chisnall 	struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate), 1);
101*3c87aa1dSDavid Chisnall 	table->header.header.destructor = destruct_collate;
102*3c87aa1dSDavid Chisnall 	// FIXME: Make sure that _LDP_CACHE is never returned.  We should be doing
103*3c87aa1dSDavid Chisnall 	// the caching outside of this section
104*3c87aa1dSDavid Chisnall 	if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) {
105*3c87aa1dSDavid Chisnall 		xlocale_release(table);
106*3c87aa1dSDavid Chisnall 		return NULL;
107*3c87aa1dSDavid Chisnall 	}
108*3c87aa1dSDavid Chisnall 	return table;
109*3c87aa1dSDavid Chisnall }
110*3c87aa1dSDavid Chisnall 
111*3c87aa1dSDavid Chisnall /**
112*3c87aa1dSDavid Chisnall  * Load the collation tables for the specified encoding into the global table.
113*3c87aa1dSDavid Chisnall  */
114*3c87aa1dSDavid Chisnall int
11576692b80SAndrey A. Chernov __collate_load_tables(const char *encoding)
116c3d0cca4SAndrey A. Chernov {
117*3c87aa1dSDavid Chisnall 	return __collate_load_tables_l(encoding, &__xlocale_global_collate);
118*3c87aa1dSDavid Chisnall }
119*3c87aa1dSDavid Chisnall 
120*3c87aa1dSDavid Chisnall int
121*3c87aa1dSDavid Chisnall __collate_load_tables_l(const char *encoding, struct xlocale_collate *table)
122*3c87aa1dSDavid Chisnall {
123c3d0cca4SAndrey A. Chernov 	FILE *fp;
1248e52da4dSAndrey A. Chernov 	int i, saverr, chains;
125c1417061SAndrey A. Chernov 	uint32_t u32;
1268e52da4dSAndrey A. Chernov 	char strbuf[STR_LEN], buf[PATH_MAX];
127a2a26d0aSAndrey A. Chernov 	void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table;
128c3d0cca4SAndrey A. Chernov 
12976692b80SAndrey A. Chernov 	/* 'encoding' must be already checked. */
13076692b80SAndrey A. Chernov 	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
131c3d0cca4SAndrey A. Chernov 		__collate_load_error = 1;
13276692b80SAndrey A. Chernov 		return (_LDP_CACHE);
133377da8e8SAndrey A. Chernov 	}
13476692b80SAndrey A. Chernov 
13576692b80SAndrey A. Chernov 	/* 'PathLocale' must be already set & checked. */
136d81a0916SAndrey A. Chernov 	/* Range checking not needed, encoding has fixed size */
137af155bdfSAndrey A. Chernov 	(void)strcpy(buf, _PathLocale);
138af155bdfSAndrey A. Chernov 	(void)strcat(buf, "/");
139af155bdfSAndrey A. Chernov 	(void)strcat(buf, encoding);
140af155bdfSAndrey A. Chernov 	(void)strcat(buf, "/LC_COLLATE");
14176692b80SAndrey A. Chernov 	if ((fp = fopen(buf, "r")) == NULL)
14276692b80SAndrey A. Chernov 		return (_LDP_ERROR);
14376692b80SAndrey A. Chernov 
1448e52da4dSAndrey A. Chernov 	if (fread(strbuf, sizeof(strbuf), 1, fp) != 1) {
1458e52da4dSAndrey A. Chernov 		saverr = errno;
1468e52da4dSAndrey A. Chernov 		(void)fclose(fp);
1478e52da4dSAndrey A. Chernov 		errno = saverr;
1488e52da4dSAndrey A. Chernov 		return (_LDP_ERROR);
1498e52da4dSAndrey A. Chernov 	}
1508e52da4dSAndrey A. Chernov 	chains = -1;
1518e52da4dSAndrey A. Chernov 	if (strcmp(strbuf, COLLATE_VERSION) == 0)
1528e52da4dSAndrey A. Chernov 		chains = 0;
153edc43112SRuslan Ermilov 	else if (strcmp(strbuf, COLLATE_VERSION1_2) == 0)
1548e52da4dSAndrey A. Chernov 		chains = 1;
1558e52da4dSAndrey A. Chernov 	if (chains < 0) {
1568e52da4dSAndrey A. Chernov 		(void)fclose(fp);
1578e52da4dSAndrey A. Chernov 		errno = EFTYPE;
1588e52da4dSAndrey A. Chernov 		return (_LDP_ERROR);
1598e52da4dSAndrey A. Chernov 	}
1608e52da4dSAndrey A. Chernov 	if (chains) {
161c1417061SAndrey A. Chernov 		if (fread(&u32, sizeof(u32), 1, fp) != 1) {
1628e52da4dSAndrey A. Chernov 			saverr = errno;
1638e52da4dSAndrey A. Chernov 			(void)fclose(fp);
1648e52da4dSAndrey A. Chernov 			errno = saverr;
1658e52da4dSAndrey A. Chernov 			return (_LDP_ERROR);
1668e52da4dSAndrey A. Chernov 		}
167c1417061SAndrey A. Chernov 		if ((chains = (int)ntohl(u32)) < 1) {
1688e52da4dSAndrey A. Chernov 			(void)fclose(fp);
1698e52da4dSAndrey A. Chernov 			errno = EFTYPE;
1708e52da4dSAndrey A. Chernov 			return (_LDP_ERROR);
1718e52da4dSAndrey A. Chernov 		}
1728e52da4dSAndrey A. Chernov 	} else
1738e52da4dSAndrey A. Chernov 		chains = TABLE_SIZE;
1748e52da4dSAndrey A. Chernov 
17576692b80SAndrey A. Chernov 	if ((TMP_substitute_table =
17676692b80SAndrey A. Chernov 	     malloc(sizeof(__collate_substitute_table))) == NULL) {
177e34fe8a4SAndrey A. Chernov 		saverr = errno;
1786892b144SAndrey A. Chernov 		(void)fclose(fp);
179e34fe8a4SAndrey A. Chernov 		errno = saverr;
18076692b80SAndrey A. Chernov 		return (_LDP_ERROR);
1811642f84dSAndrey A. Chernov 	}
18276692b80SAndrey A. Chernov 	if ((TMP_char_pri_table =
18376692b80SAndrey A. Chernov 	     malloc(sizeof(__collate_char_pri_table))) == NULL) {
184e34fe8a4SAndrey A. Chernov 		saverr = errno;
18576692b80SAndrey A. Chernov 		free(TMP_substitute_table);
1866892b144SAndrey A. Chernov 		(void)fclose(fp);
187e34fe8a4SAndrey A. Chernov 		errno = saverr;
18876692b80SAndrey A. Chernov 		return (_LDP_ERROR);
18976692b80SAndrey A. Chernov 	}
19076692b80SAndrey A. Chernov 	if ((TMP_chain_pri_table =
1918e52da4dSAndrey A. Chernov 	     malloc(sizeof(*__collate_chain_pri_table) * chains)) == NULL) {
192e34fe8a4SAndrey A. Chernov 		saverr = errno;
19376692b80SAndrey A. Chernov 		free(TMP_substitute_table);
19476692b80SAndrey A. Chernov 		free(TMP_char_pri_table);
19576692b80SAndrey A. Chernov 		(void)fclose(fp);
196e34fe8a4SAndrey A. Chernov 		errno = saverr;
19776692b80SAndrey A. Chernov 		return (_LDP_ERROR);
19876692b80SAndrey A. Chernov 	}
19976692b80SAndrey A. Chernov 
20076692b80SAndrey A. Chernov #define FREAD(a, b, c, d) \
20176692b80SAndrey A. Chernov { \
20276692b80SAndrey A. Chernov 	if (fread(a, b, c, d) != c) { \
20376692b80SAndrey A. Chernov 		saverr = errno; \
20476692b80SAndrey A. Chernov 		free(TMP_substitute_table); \
20576692b80SAndrey A. Chernov 		free(TMP_char_pri_table); \
20676692b80SAndrey A. Chernov 		free(TMP_chain_pri_table); \
20776692b80SAndrey A. Chernov 		(void)fclose(d); \
20876692b80SAndrey A. Chernov 		errno = saverr; \
20976692b80SAndrey A. Chernov 		return (_LDP_ERROR); \
21076692b80SAndrey A. Chernov 	} \
21176692b80SAndrey A. Chernov }
21276692b80SAndrey A. Chernov 
21376692b80SAndrey A. Chernov 	FREAD(TMP_substitute_table, sizeof(__collate_substitute_table), 1, fp);
21476692b80SAndrey A. Chernov 	FREAD(TMP_char_pri_table, sizeof(__collate_char_pri_table), 1, fp);
2158e52da4dSAndrey A. Chernov 	FREAD(TMP_chain_pri_table,
216cbc98d05SAndrey A. Chernov 	      sizeof(*__collate_chain_pri_table), chains, fp);
21776692b80SAndrey A. Chernov 	(void)fclose(fp);
21876692b80SAndrey A. Chernov 
219a2a26d0aSAndrey A. Chernov 	if (__collate_substitute_table_ptr != NULL)
220a2a26d0aSAndrey A. Chernov 		free(__collate_substitute_table_ptr);
221a2a26d0aSAndrey A. Chernov 	__collate_substitute_table_ptr = TMP_substitute_table;
222a2a26d0aSAndrey A. Chernov 	if (__collate_char_pri_table_ptr != NULL)
223a2a26d0aSAndrey A. Chernov 		free(__collate_char_pri_table_ptr);
224a2a26d0aSAndrey A. Chernov 	__collate_char_pri_table_ptr = TMP_char_pri_table;
225edc43112SRuslan Ermilov 	for (i = 0; i < UCHAR_MAX + 1; i++) {
226edc43112SRuslan Ermilov 		__collate_char_pri_table[i].prim =
227edc43112SRuslan Ermilov 		    ntohl(__collate_char_pri_table[i].prim);
228edc43112SRuslan Ermilov 		__collate_char_pri_table[i].sec =
229edc43112SRuslan Ermilov 		    ntohl(__collate_char_pri_table[i].sec);
230edc43112SRuslan Ermilov 	}
2318e52da4dSAndrey A. Chernov 	if (__collate_chain_pri_table != NULL)
2328e52da4dSAndrey A. Chernov 		free(__collate_chain_pri_table);
2338e52da4dSAndrey A. Chernov 	__collate_chain_pri_table = TMP_chain_pri_table;
234edc43112SRuslan Ermilov 	for (i = 0; i < chains; i++) {
235edc43112SRuslan Ermilov 		__collate_chain_pri_table[i].prim =
236edc43112SRuslan Ermilov 		    ntohl(__collate_chain_pri_table[i].prim);
237edc43112SRuslan Ermilov 		__collate_chain_pri_table[i].sec =
238edc43112SRuslan Ermilov 		    ntohl(__collate_chain_pri_table[i].sec);
239edc43112SRuslan Ermilov 	}
240e755fb76SDmitrij Tejblum 	__collate_substitute_nontrivial = 0;
241e755fb76SDmitrij Tejblum 	for (i = 0; i < UCHAR_MAX + 1; i++) {
242e755fb76SDmitrij Tejblum 		if (__collate_substitute_table[i][0] != i ||
243e755fb76SDmitrij Tejblum 		    __collate_substitute_table[i][1] != 0) {
244e755fb76SDmitrij Tejblum 			__collate_substitute_nontrivial = 1;
245e755fb76SDmitrij Tejblum 			break;
246e755fb76SDmitrij Tejblum 		}
247e755fb76SDmitrij Tejblum 	}
24876692b80SAndrey A. Chernov 	__collate_load_error = 0;
249e755fb76SDmitrij Tejblum 
25076692b80SAndrey A. Chernov 	return (_LDP_LOADED);
251c3d0cca4SAndrey A. Chernov }
252c3d0cca4SAndrey A. Chernov 
253c3d0cca4SAndrey A. Chernov u_char *
254*3c87aa1dSDavid Chisnall __collate_substitute(struct xlocale_collate *table, const u_char *s)
255c3d0cca4SAndrey A. Chernov {
25603a7efc2SDmitrij Tejblum 	int dest_len, len, nlen;
257c3d0cca4SAndrey A. Chernov 	int delta = strlen(s);
258926f20c9SAndrey A. Chernov 	u_char *dest_str = NULL;
259c3d0cca4SAndrey A. Chernov 
260926f20c9SAndrey A. Chernov 	if (s == NULL || *s == '\0')
2616892b144SAndrey A. Chernov 		return (__collate_strdup(""));
26203a7efc2SDmitrij Tejblum 	delta += delta / 8;
26303a7efc2SDmitrij Tejblum 	dest_str = malloc(dest_len = delta);
26403a7efc2SDmitrij Tejblum 	if (dest_str == NULL)
265e60b9f51SStefan Farfeleder 		__collate_err(EX_OSERR, __func__);
26603a7efc2SDmitrij Tejblum 	len = 0;
267c3d0cca4SAndrey A. Chernov 	while (*s) {
26803a7efc2SDmitrij Tejblum 		nlen = len + strlen(__collate_substitute_table[*s]);
26903a7efc2SDmitrij Tejblum 		if (dest_len <= nlen) {
27003a7efc2SDmitrij Tejblum 			dest_str = reallocf(dest_str, dest_len = nlen + delta);
271926f20c9SAndrey A. Chernov 			if (dest_str == NULL)
272e60b9f51SStefan Farfeleder 				__collate_err(EX_OSERR, __func__);
273c3d0cca4SAndrey A. Chernov 		}
2746892b144SAndrey A. Chernov 		(void)strcpy(dest_str + len, __collate_substitute_table[*s++]);
27503a7efc2SDmitrij Tejblum 		len = nlen;
276c3d0cca4SAndrey A. Chernov 	}
2776892b144SAndrey A. Chernov 	return (dest_str);
278c3d0cca4SAndrey A. Chernov }
279c3d0cca4SAndrey A. Chernov 
280c3d0cca4SAndrey A. Chernov void
281*3c87aa1dSDavid Chisnall __collate_lookup(struct xlocale_collate *table, const u_char *t, int *len, int *prim, int *sec)
282c3d0cca4SAndrey A. Chernov {
283c3d0cca4SAndrey A. Chernov 	struct __collate_st_chain_pri *p2;
284c3d0cca4SAndrey A. Chernov 
285c3d0cca4SAndrey A. Chernov 	*len = 1;
286c3d0cca4SAndrey A. Chernov 	*prim = *sec = 0;
2878e52da4dSAndrey A. Chernov 	for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++) {
2888e52da4dSAndrey A. Chernov 		if (*t == p2->str[0] &&
2898e52da4dSAndrey A. Chernov 		    strncmp(t, p2->str, strlen(p2->str)) == 0) {
290c3d0cca4SAndrey A. Chernov 			*len = strlen(p2->str);
291c3d0cca4SAndrey A. Chernov 			*prim = p2->prim;
292c3d0cca4SAndrey A. Chernov 			*sec = p2->sec;
293c3d0cca4SAndrey A. Chernov 			return;
294c3d0cca4SAndrey A. Chernov 		}
295c3d0cca4SAndrey A. Chernov 	}
296c3d0cca4SAndrey A. Chernov 	*prim = __collate_char_pri_table[*t].prim;
297c3d0cca4SAndrey A. Chernov 	*sec = __collate_char_pri_table[*t].sec;
298c3d0cca4SAndrey A. Chernov }
299c3d0cca4SAndrey A. Chernov 
300c3d0cca4SAndrey A. Chernov u_char *
301f9b5e461SAlexey Zelkin __collate_strdup(u_char *s)
302c3d0cca4SAndrey A. Chernov {
303926f20c9SAndrey A. Chernov 	u_char *t = strdup(s);
304c3d0cca4SAndrey A. Chernov 
305926f20c9SAndrey A. Chernov 	if (t == NULL)
306e60b9f51SStefan Farfeleder 		__collate_err(EX_OSERR, __func__);
3076892b144SAndrey A. Chernov 	return (t);
308c3d0cca4SAndrey A. Chernov }
309c3d0cca4SAndrey A. Chernov 
310eaa86f9dSBruce Evans void
311eaa86f9dSBruce Evans __collate_err(int ex, const char *f)
312926f20c9SAndrey A. Chernov {
313926f20c9SAndrey A. Chernov 	const char *s;
314926f20c9SAndrey A. Chernov 	int serrno = errno;
315926f20c9SAndrey A. Chernov 
3164cd01193SMark Murray 	s = _getprogname();
3179233c4d9SJason Evans 	_write(STDERR_FILENO, s, strlen(s));
3189233c4d9SJason Evans 	_write(STDERR_FILENO, ": ", 2);
319926f20c9SAndrey A. Chernov 	s = f;
3209233c4d9SJason Evans 	_write(STDERR_FILENO, s, strlen(s));
3219233c4d9SJason Evans 	_write(STDERR_FILENO, ": ", 2);
322926f20c9SAndrey A. Chernov 	s = strerror(serrno);
3239233c4d9SJason Evans 	_write(STDERR_FILENO, s, strlen(s));
3249233c4d9SJason Evans 	_write(STDERR_FILENO, "\n", 1);
325926f20c9SAndrey A. Chernov 	exit(ex);
326926f20c9SAndrey A. Chernov }
327926f20c9SAndrey A. Chernov 
328c3d0cca4SAndrey A. Chernov #ifdef COLLATE_DEBUG
329c3d0cca4SAndrey A. Chernov void
330c3d0cca4SAndrey A. Chernov __collate_print_tables()
331c3d0cca4SAndrey A. Chernov {
332c3d0cca4SAndrey A. Chernov 	int i;
333c3d0cca4SAndrey A. Chernov 	struct __collate_st_chain_pri *p2;
334c3d0cca4SAndrey A. Chernov 
335c3d0cca4SAndrey A. Chernov 	printf("Substitute table:\n");
336c3d0cca4SAndrey A. Chernov 	for (i = 0; i < UCHAR_MAX + 1; i++)
337967a5cb1SAndrey A. Chernov 	    if (i != *__collate_substitute_table[i])
338c3d0cca4SAndrey A. Chernov 		printf("\t'%c' --> \"%s\"\n", i,
339c3d0cca4SAndrey A. Chernov 		       __collate_substitute_table[i]);
340c3d0cca4SAndrey A. Chernov 	printf("Chain priority table:\n");
341cbc98d05SAndrey A. Chernov 	for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++)
342cbc98d05SAndrey A. Chernov 		printf("\t\"%s\" : %d %d\n", p2->str, p2->prim, p2->sec);
343c3d0cca4SAndrey A. Chernov 	printf("Char priority table:\n");
344c3d0cca4SAndrey A. Chernov 	for (i = 0; i < UCHAR_MAX + 1; i++)
345c3d0cca4SAndrey A. Chernov 		printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim,
346c3d0cca4SAndrey A. Chernov 		       __collate_char_pri_table[i].sec);
347c3d0cca4SAndrey A. Chernov }
348c3d0cca4SAndrey A. Chernov #endif
349