1 /* Case-mapping context of prefix UTF-8/UTF-16/UTF-32 string. 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 casing_prefix_context_t 27 FUNC1 (const UNIT *s, size_t n) 28 { 29 return FUNC2 (s, n, unicase_empty_prefix_context); 30 } 31 32 casing_prefix_context_t 33 FUNC2 (const UNIT *s, size_t n, casing_prefix_context_t a_context) 34 { 35 #if 0 36 /* Forward iteration. Slow for long strings. */ 37 casing_prefix_context_t context = a_context; 38 const UNIT *s_end = s + n; 39 40 while (s < s_end) 41 { 42 ucs4_t uc; 43 int count = U_MBTOUC_UNSAFE (&uc, s, s_end - s); 44 45 if (!uc_is_case_ignorable (uc)) 46 context.last_char_except_ignorable = uc; 47 48 { 49 int ccc = uc_combining_class (uc); 50 if (ccc == UC_CCC_A || ccc == UC_CCC_NR) 51 context.last_char_normal_or_above = uc; 52 } 53 54 s += count; 55 } 56 57 return context; 58 #else 59 /* Iterate backwards, only as far as needed. */ 60 casing_prefix_context_t context; 61 ucs4_t last_char_except_ignorable = (ucs4_t)(-1); 62 ucs4_t last_char_normal_or_above = (ucs4_t)(-1); 63 const UNIT *p = s + n; 64 65 for (;;) 66 { 67 ucs4_t uc; 68 p = U_PREV (&uc, p, s); 69 if (p == NULL) 70 break; 71 72 if (last_char_except_ignorable == (ucs4_t)(-1)) 73 { 74 if (!uc_is_case_ignorable (uc)) 75 last_char_except_ignorable = uc; 76 } 77 78 if (last_char_normal_or_above == (ucs4_t)(-1)) 79 { 80 int ccc = uc_combining_class (uc); 81 if (ccc == UC_CCC_A || ccc == UC_CCC_NR) 82 last_char_normal_or_above = uc; 83 } 84 85 if (last_char_except_ignorable != (ucs4_t)(-1) 86 && last_char_normal_or_above != (ucs4_t)(-1)) 87 break; 88 } 89 context.last_char_except_ignorable = 90 (last_char_except_ignorable != (ucs4_t)(-1) 91 ? last_char_except_ignorable 92 : a_context.last_char_except_ignorable); 93 context.last_char_normal_or_above = 94 (last_char_normal_or_above != (ucs4_t)(-1) 95 ? last_char_normal_or_above 96 : a_context.last_char_normal_or_above); 97 98 return context; 99 #endif 100 } 101