New module 'unicase/ulc-casecoll'.
[gnulib.git] / lib / unicase / u-casefold.h
1 /* Casefolding mapping for Unicode strings (locale dependent).
2    Copyright (C) 2009 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2009.
4
5    This program is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Lesser General Public License as published
7    by the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 UNIT *
19 FUNC (const UNIT *s, size_t n, const char *iso639_language,
20       uninorm_t nf,
21       UNIT *resultbuf, size_t *lengthp)
22 {
23   /* Implement the three definitions of caseless matching, as described in
24      Unicode 5.0, section "Default caseless matching":
25        - If no normalization is requested, simply apply the casefolding.
26            X -> toCasefold(X).
27        - If canonical normalization is requested, apply it, and apply an NFD
28          before.
29            X -> NFD(toCasefold(NFD(X))).
30        - If compatibility normalization is requested, apply it twice, apply
31          the normalization after each, and apply an NFD before:
32            X -> NFKD(toCasefold(NFKD(toCasefold(NFD(X))))).  */
33   if (nf == NULL)
34     /* X -> toCasefold(X) */
35     return U_CASEMAP (s, n, iso639_language,
36                       uc_tocasefold, offsetof (struct special_casing_rule, casefold[0]),
37                       NULL,
38                       resultbuf, lengthp);
39   else
40     {
41       uninorm_t nfd = uninorm_decomposing_form (nf);
42       /* X -> nf(toCasefold(NFD(X))) or
43          X -> nf(toCasefold(nfd(toCasefold(NFD(X)))))  */
44       int repeat = (uninorm_is_compat_decomposing (nf) ? 2 : 1);
45       UNIT tmpbuf1[2048 / sizeof (UNIT)];
46       UNIT tmpbuf2[2048 / sizeof (UNIT)];
47       UNIT *tmp1;
48       size_t tmp1_length;
49       UNIT *tmp2;
50       size_t tmp2_length;
51
52       tmp1_length = sizeof (tmpbuf1) / sizeof (UNIT);
53       tmp1 = U_NORMALIZE (UNINORM_NFD, s, n, tmpbuf1, &tmp1_length);
54       if (tmp1 == NULL)
55         /* errno is set here.  */
56         return NULL;
57
58       do
59         {
60           tmp2_length = sizeof (tmpbuf2) / sizeof (UNIT);
61           tmp2 = U_CASEMAP (tmp1, tmp1_length, iso639_language,
62                             uc_tocasefold, offsetof (struct special_casing_rule, casefold[0]),
63                             NULL,
64                             tmpbuf2, &tmp2_length);
65           if (tmp2 == NULL)
66             {
67               int saved_errno = errno;
68               if (tmp1 != tmpbuf1)
69                 free (tmp1);
70               errno = saved_errno;
71               return NULL;
72             }
73
74           if (tmp1 != tmpbuf1)
75             free (tmp1);
76
77           if (repeat > 1)
78             {
79               tmp1_length = sizeof (tmpbuf1) / sizeof (UNIT);
80               tmp1 = U_NORMALIZE (nfd, tmp2, tmp2_length,
81                                   tmpbuf1, &tmp1_length);
82             }
83           else
84             /* Last run through this loop.  */
85             tmp1 = U_NORMALIZE (nf, tmp2, tmp2_length,
86                                 resultbuf, lengthp);
87           if (tmp1 == NULL)
88             {
89               int saved_errno = errno;
90               if (tmp2 != tmpbuf2)
91                 free (tmp2);
92               errno = saved_errno;
93               return NULL;
94             }
95
96           if (tmp2 != tmpbuf2)
97             free (tmp2);
98         }
99       while (--repeat > 0);
100
101       return tmp1;
102     }
103 }