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