96c58dae933eee9327dc8528cddf42edf7ab0fc5
[pspp] / lib / unicase / u-suffix-context.h
1 /* Case-mapping context of suffix UTF-8/UTF-16/UTF-32 string.
2    Copyright (C) 2009 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   int scc_FINAL_SIGMA = -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 (scc_FINAL_SIGMA < 0)
42         {
43           if (uc_is_cased (uc))
44             scc_FINAL_SIGMA = SCC_FINAL_SIGMA_MASK;
45           else if (!uc_is_case_ignorable (uc))
46             scc_FINAL_SIGMA = 0;
47         }
48
49       if (scc_MORE_ABOVE < 0)
50         {
51           int ccc = uc_combining_class (uc);
52           if (ccc == UC_CCC_A)
53             scc_MORE_ABOVE = SCC_MORE_ABOVE_MASK;
54           else if (ccc == UC_CCC_NR)
55             scc_MORE_ABOVE = 0;
56         }
57
58       if (scc_BEFORE_DOT < 0)
59         {
60           if (uc == 0x0307) /* COMBINING DOT ABOVE */
61             scc_BEFORE_DOT = SCC_BEFORE_DOT_MASK;
62           else
63             {
64               int ccc = uc_combining_class (uc);
65               if (ccc == UC_CCC_A || ccc == UC_CCC_NR)
66                 scc_BEFORE_DOT = 0;
67             }
68         }
69
70       if ((scc_FINAL_SIGMA | scc_MORE_ABOVE | scc_BEFORE_DOT) >= 0)
71         /* All conditions have been determined.  */
72         break;
73
74       s += count;
75     }
76
77   /* For those conditions that have not been determined so far, use the
78      value from the argument context.  */
79   context.bits =
80     (scc_FINAL_SIGMA >= 0
81      ? scc_FINAL_SIGMA
82      : a_context.bits & SCC_FINAL_SIGMA_MASK)
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 }