1 /* Casefolding mapping for Unicode substrings (locale dependent).
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 UNIT *
27 FUNC (const UNIT *s, size_t n,
/* ![[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 casing_prefix_context_t prefix_context,
29 casing_suffix_context_t suffix_context,
30 const char *iso639_language,
31 uninorm_t nf,
32 UNIT *resultbuf, size_t *lengthp)
33 {
34 /* Implement the three definitions of caseless matching, as described in
35 Unicode 5.0, section "Default caseless matching":
36 - If no normalization is requested, simply apply the casefolding.
37 X -> toCasefold(X).
38 - If canonical normalization is requested, apply it, and apply an NFD
39 before.
40 X -> NFD(toCasefold(NFD(X))).
41 - If compatibility normalization is requested, apply it twice, apply
42 the normalization after each, and apply an NFD before:
43 X -> NFKD(toCasefold(NFKD(toCasefold(NFD(X))))). */
44 if (nf == NULL)
45 /* X -> toCasefold(X) */
46 return U_CASEMAP (s, n, prefix_context, suffix_context, iso639_language,
47 uc_tocasefold, offsetof (struct special_casing_rule, casefold[0]),
48 NULL,
49 resultbuf, lengthp);
50 else
51 {
52 uninorm_t nfd = uninorm_decomposing_form (nf);
53 /* X -> nf(toCasefold(NFD(X))) or
54 X -> nf(toCasefold(nfd(toCasefold(NFD(X))))) */
55 int repeat = (uninorm_is_compat_decomposing (nf) ? 2 : 1);
56 UNIT tmpbuf1[2048 / sizeof (UNIT)];
57 UNIT tmpbuf2[2048 / sizeof (UNIT)];
58 UNIT *tmp1;
59 size_t tmp1_length;
60 UNIT *tmp2;
61 size_t tmp2_length;
62
63 tmp1_length = sizeof (tmpbuf1) / sizeof (UNIT);
64 tmp1 = U_NORMALIZE (UNINORM_NFD, s, n, tmpbuf1, &tmp1_length);
65 if (tmp1 == NULL)
66 /* errno is set here. */
67 return NULL;
68
69 do
70 {
71 tmp2_length = sizeof (tmpbuf2) / sizeof (UNIT);
72 tmp2 = U_CASEMAP (tmp1, tmp1_length,
73 prefix_context, suffix_context, iso639_language,
74 uc_tocasefold, offsetof (struct special_casing_rule, casefold[0]),
75 NULL,
76 tmpbuf2, &tmp2_length);
77 if (tmp2 == NULL)
78 {
79 int saved_errno = errno;
80 if (tmp1 != tmpbuf1)
81 free (tmp1);
82 errno = saved_errno;
83 return NULL;
84 }
85
86 if (tmp1 != tmpbuf1)
87 free (tmp1);
88
89 if (repeat > 1)
90 {
91 tmp1_length = sizeof (tmpbuf1) / sizeof (UNIT);
92 tmp1 = U_NORMALIZE (nfd, tmp2, tmp2_length,
93 tmpbuf1, &tmp1_length);
94 }
95 else
96 /* Last run through this loop. */
97 tmp1 = U_NORMALIZE (nf, tmp2, tmp2_length,
98 resultbuf, lengthp);
99 if (tmp1 == NULL)
100 {
101 int saved_errno = errno;
102 if (tmp2 != tmpbuf2)
103 free (tmp2);
104 errno = saved_errno;
105 return NULL;
106 }
107
108 if (tmp2 != tmpbuf2)
109 free (tmp2);
110 }
111 while (--repeat > 0);
112
113 return tmp1;
114 }
115 }