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