1 /* Locale dependent transformation for comparison of Unicode strings.
2 Copyright (C) 2009-2021 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2009.
4
5 This file is free software.
6 It is dual-licensed under "the GNU LGPLv3+ or the GNU GPLv2+".
7 You can redistribute it and/or modify it under either
8 - the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version, or
11 - the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2, or (at your option)
13 any later version, or
14 - the same dual license "the GNU LGPLv3+ or the GNU GPLv2+".
15
16 This file is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License and the GNU General Public License
20 for more details.
21
22 You should have received a copy of the GNU Lesser General Public
23 License and of the GNU General Public License along with this
24 program. If not, see <https://www.gnu.org/licenses/>. */
25
26 char *
27 FUNC (const UNIT *s, size_t n, uninorm_t nf,
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
28 char *resultbuf, size_t *lengthp)
29 {
30 UNIT normsbuf[2048 / sizeof (UNIT)];
31 UNIT *norms;
32 size_t norms_length;
33 char convsbuf[2048];
34 char *convs;
35 size_t convs_length;
36 char *result;
37
38 /* Normalize the Unicode string. */
39 norms_length = sizeof (normsbuf) / sizeof (UNIT);
40 norms = U_NORMALIZE (nf, s, n, normsbuf, &norms_length);
41 if (norms == NULL)
42 /* errno is set here. */
43 return NULL;
44
45 /* Convert it to locale encoding. */
46 convs_length = sizeof (convsbuf) - 1;
47 convs = U_CONV_TO_ENCODING (locale_charset (),
48 iconveh_error,
49 norms, norms_length,
50 NULL,
51 convsbuf, &convs_length);
52 if (convs == NULL)
53 {
54 if (norms != normsbuf)
55 {
56 int saved_errno = errno;
57 free (norms);
58 errno = saved_errno;
59 }
60 return NULL;
61 }
62
63 if (norms != normsbuf)
64 free (norms);
65
66 /* Ensure one more byte is available. */
67 if (convs != convsbuf)
68 {
69 char *memory = (char *) realloc (convs, convs_length + 1);
70 if (memory == NULL)
71 {
72 free (convs);
73 errno = ENOMEM;
74 return NULL;
75 }
76 convs = memory;
77 }
78
79 /* Apply locale dependent transformations for comparison. */
80 result = amemxfrm (convs, convs_length, resultbuf, lengthp);
81 if (result == NULL)
82 {
83 if (convs != convsbuf)
84 {
85 int saved_errno = errno;
86 free (convs);
87 errno = saved_errno;
88 }
89 return NULL;
90 }
91
92 if (convs != convsbuf)
93 free (convs);
94 return result;
95 }