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