bdb76c6035e005f40f0f5c52fce5d461d93ce2bf
[gnulib.git] / lib / unicase / u-suffix-context.h
1 /* Case-mapping context of suffix UTF-8/UTF-16/UTF-32 string.
2    Copyright (C) 2009-2012 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 casing_suffix_context_t
19 FUNC1 (const UNIT *s, size_t n)
20 {
21   return FUNC2 (s, n, unicase_empty_suffix_context);
22 }
23
24 casing_suffix_context_t
25 FUNC2 (const UNIT *s, size_t n, casing_suffix_context_t a_context)
26 {
27   casing_suffix_context_t context;
28   /* Evaluate all three conditions in a single pass through the string S.
29      The three variables are -1 as long as the value of the condition has
30      not been determined.  */
31   ucs4_t first_char_except_ignorable = (ucs4_t)(-1);
32   int scc_MORE_ABOVE = -1;
33   int scc_BEFORE_DOT = -1;
34   const UNIT *s_end = s + n;
35
36   while (s < s_end)
37     {
38       ucs4_t uc;
39       int count = U_MBTOUC_UNSAFE (&uc, s, s_end - s);
40
41       if (first_char_except_ignorable == (ucs4_t)(-1))
42         {
43           if (!uc_is_case_ignorable (uc))
44             first_char_except_ignorable = uc;
45         }
46
47       if (scc_MORE_ABOVE < 0)
48         {
49           int ccc = uc_combining_class (uc);
50           if (ccc == UC_CCC_A)
51             scc_MORE_ABOVE = SCC_MORE_ABOVE_MASK;
52           else if (ccc == UC_CCC_NR)
53             scc_MORE_ABOVE = 0;
54         }
55
56       if (scc_BEFORE_DOT < 0)
57         {
58           if (uc == 0x0307) /* COMBINING DOT ABOVE */
59             scc_BEFORE_DOT = SCC_BEFORE_DOT_MASK;
60           else
61             {
62               int ccc = uc_combining_class (uc);
63               if (ccc == UC_CCC_A || ccc == UC_CCC_NR)
64                 scc_BEFORE_DOT = 0;
65             }
66         }
67
68       if (first_char_except_ignorable != (ucs4_t)(-1)
69           && (scc_MORE_ABOVE | scc_BEFORE_DOT) >= 0)
70         /* All conditions have been determined.  */
71         break;
72
73       s += count;
74     }
75
76   /* For those conditions that have not been determined so far, use the
77      value from the argument context.  */
78   context.first_char_except_ignorable =
79     (first_char_except_ignorable != (ucs4_t)(-1)
80      ? first_char_except_ignorable
81      : a_context.first_char_except_ignorable);
82   context.bits =
83     (scc_MORE_ABOVE >= 0
84      ? scc_MORE_ABOVE
85      : a_context.bits & SCC_MORE_ABOVE_MASK)
86     | (scc_BEFORE_DOT >= 0
87        ? scc_BEFORE_DOT
88        : a_context.bits & SCC_BEFORE_DOT_MASK);
89   return context;
90 }