1/* Casefolding mapping for Unicode substrings (locale dependent).
2   Copyright (C) 2009-2010 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
18UNIT *
19FUNC (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}
108