1 /*
2  * SPDX-FileCopyrightText: 2005 Takuro Ashie
3  * SPDX-FileCopyrightText: 2012-2017 CSSlayer <wengxt@gmail.com>
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  *
7  */
8 
9 #include "key2kana_table.h"
10 
11 // fundamental table
12 static Key2KanaTable romaji_table(("DefaultRomajiTable"),
13                                   fcitx_anthy_romaji_typing_rule);
14 static Key2KanaTable
15     romaji_double_consonant_table(("DefaultRomajiDoubleConsonantTable"),
16                                   fcitx_anthy_romaji_double_consonant_rule);
17 static Key2KanaTable kana_table(("DefaultKanaTable"),
18                                 fcitx_anthy_kana_typing_rule);
19 static Key2KanaTable
20     kana_voiced_consonant_table(("DefaultKanaVoicedConsonantTable"),
21                                 fcitx_anthy_kana_voiced_consonant_rule);
22 static Key2KanaTable nicola_table(("DefaultNICOLATable"),
23                                   fcitx_anthy_nicola_table);
24 
25 // symbols
26 static Key2KanaTable half_symbol_table(("DefaultRomajiHalfSymbolTable"),
27                                        fcitx_anthy_half_symbol_rule);
28 static Key2KanaTable wide_symbol_table(("DefaultRomajiWideSymbolTable"),
29                                        fcitx_anthy_wide_symbol_rule);
30 
31 // numbers
32 static Key2KanaTable half_number_table(("DefaultRomajiHalfNumberTable"),
33                                        fcitx_anthy_half_number_rule);
34 static Key2KanaTable wide_number_table(("DefaultRomajiWideNumberTable"),
35                                        fcitx_anthy_wide_number_rule);
36 
37 // period
38 static Key2KanaTable romaji_ja_period_table(("DefaultRomajiJaPeriodTable"),
39                                             fcitx_anthy_romaji_ja_period_rule);
40 static Key2KanaTable
41     romaji_wide_period_table(("DefaultRomajiWidePeriodTable"),
42                              fcitx_anthy_romaji_wide_period_rule);
43 static Key2KanaTable
44     romaji_half_period_table(("DefaultRomajiHalfPeriodTable"),
45                              fcitx_anthy_romaji_half_period_rule);
46 
47 static Key2KanaTable kana_ja_period_table(("DefaultKanaJaPeriodTable"),
48                                           fcitx_anthy_kana_ja_period_rule);
49 static Key2KanaTable kana_wide_period_table(("DefaultKanaWidePeriodTable"),
50                                             fcitx_anthy_kana_wide_period_rule);
51 static Key2KanaTable kana_half_period_table(("DefaultKanaHalfPeriodTable"),
52                                             fcitx_anthy_kana_half_period_rule);
53 
54 // comma
55 static Key2KanaTable romaji_ja_comma_table(("DefaultRomajiJaCommaTable"),
56                                            fcitx_anthy_romaji_ja_comma_rule);
57 static Key2KanaTable
58     romaji_wide_comma_table(("DefaultRomajiWideCommaTable"),
59                             fcitx_anthy_romaji_wide_comma_rule);
60 static Key2KanaTable
61     romaji_half_comma_table(("DefaultRomajiHalfCommaTable"),
62                             fcitx_anthy_romaji_half_comma_rule);
63 
64 static Key2KanaTable kana_ja_comma_table(("DefaultKanaJaCommaTable"),
65                                          fcitx_anthy_kana_ja_comma_rule);
66 static Key2KanaTable kana_wide_comma_table(("DefaultKanaWideCommaTable"),
67                                            fcitx_anthy_kana_wide_comma_rule);
68 static Key2KanaTable kana_half_comma_table(("DefaultKanaHalfCommaTable"),
69                                            fcitx_anthy_kana_half_comma_rule);
70 
71 // bracket
72 static Key2KanaTable
73     romaji_ja_bracket_table(("DefaultRomajiJaBracketTable"),
74                             fcitx_anthy_romaji_ja_bracket_rule);
75 static Key2KanaTable
76     romaji_wide_bracket_table(("DefaultRomajiWideBracketTable"),
77                               fcitx_anthy_romaji_wide_bracket_rule);
78 
79 static Key2KanaTable kana_ja_bracket_table(("DefaultKanaJaBracketTable"),
80                                            fcitx_anthy_kana_ja_bracket_rule);
81 static Key2KanaTable
82     kana_wide_bracket_table(("DefaultRomajiWideBracketTable"),
83                             fcitx_anthy_kana_wide_bracket_rule);
84 
85 // slash
86 static Key2KanaTable romaji_ja_slash_table(("DefaultRomajiJaSlashTable"),
87                                            fcitx_anthy_romaji_ja_slash_rule);
88 static Key2KanaTable
89     romaji_wide_slash_table(("DefaultRomajiWideSlashTable"),
90                             fcitx_anthy_romaji_wide_slash_rule);
91 
92 static Key2KanaTable kana_ja_slash_table(("DefaultKanaJaSlashTable"),
93                                          fcitx_anthy_kana_ja_slash_rule);
94 static Key2KanaTable kana_wide_slash_table(("DefaultRomajiWideSlashTable"),
95                                            fcitx_anthy_kana_wide_slash_rule);
96 
Key2KanaRule()97 Key2KanaRule::Key2KanaRule() {}
98 
load(std::string sequence,std::vector<std::string> result)99 void Key2KanaRule::load(std::string sequence, std::vector<std::string> result) {
100     sequence_ = std::move(sequence);
101     result_ = std::move(result);
102 }
103 
~Key2KanaRule()104 Key2KanaRule::~Key2KanaRule() {}
105 
sequence() const106 const std::string &Key2KanaRule::sequence() const { return sequence_; }
107 
result(unsigned int idx)108 std::string Key2KanaRule::result(unsigned int idx) {
109     if (idx < result_.size())
110         return result_[idx];
111 
112     return std::string();
113 }
114 
clear()115 void Key2KanaRule::clear() {
116     sequence_ = std::string();
117     result_.clear();
118 }
119 
isEmpty()120 bool Key2KanaRule::isEmpty() {
121     if (!sequence_.empty())
122         return false;
123 
124     if (result_.empty())
125         return true;
126 
127     for (unsigned int i = 0; i < result_.size(); i++) {
128         if (!result_[i].empty())
129             return false;
130     }
131 
132     return true;
133 }
134 
Key2KanaTable(std::string name)135 Key2KanaTable::Key2KanaTable(std::string name) : name_(std::move(name)) {}
136 
Key2KanaTable(std::string name,ConvRule * table)137 Key2KanaTable::Key2KanaTable(std::string name, ConvRule *table)
138     : name_(std::move(name)) {
139     for (unsigned int i = 0; table[i].string; i++) {
140         appendRule(table[i].string ? table[i].string : "",
141                    table[i].result ? table[i].result : "",
142                    table[i].cont ? table[i].cont : "");
143     }
144 }
145 
Key2KanaTable(std::string name,NicolaRule * table)146 Key2KanaTable::Key2KanaTable(std::string name, NicolaRule *table)
147     : name_(std::move(name)) {
148     for (unsigned int i = 0; table[i].key; i++) {
149         appendRule(table[i].key ? table[i].key : "",
150                    table[i].single ? table[i].single : "",
151                    table[i].left_shift ? table[i].left_shift : "",
152                    table[i].right_shift ? table[i].right_shift : "");
153     }
154 }
155 
appendRule(std::string sequence,std::vector<std::string> result)156 void Key2KanaTable::appendRule(std::string sequence,
157                                std::vector<std::string> result) {
158     rules_.emplace_back();
159     rules_.back().load(std::move(sequence), std::move(result));
160 }
161 
appendRule(std::string sequence,std::string result,std::string cont)162 void Key2KanaTable::appendRule(std::string sequence, std::string result,
163                                std::string cont) {
164     std::vector<std::string> list;
165     list.push_back(std::move(result));
166     list.push_back(std::move(cont));
167     appendRule(std::move(sequence), std::move(list));
168 }
169 
appendRule(std::string sequence,std::string normal,std::string left_shift,std::string right_shift)170 void Key2KanaTable::appendRule(std::string sequence, std::string normal,
171                                std::string left_shift,
172                                std::string right_shift) {
173     std::vector<std::string> list;
174     list.push_back(normal);
175     list.push_back(left_shift);
176     list.push_back(right_shift);
177     appendRule(std::move(sequence), std::move(list));
178 }
179 
clear()180 void Key2KanaTable::clear() { rules_.clear(); }
181 
Key2KanaTableSet()182 Key2KanaTableSet::Key2KanaTableSet()
183     : name_(""), fundamentalTable_(nullptr),
184       voicedConsonantTable_(Key2KanaTable("voiced consonant table")),
185       additionalTable_(nullptr), typingMethod_(TypingMethod::ROMAJI),
186       periodStyle_(PeriodStyle::JAPANESE), commaStyle_(CommaStyle::JAPANESE),
187       bracketStyle_(BracketStyle::JAPANESE), slashStyle_(SlashStyle::JAPANESE),
188       useHalfSymbol_(false), useHalfNumber_(false) {
189     setTypingMethod(typingMethod_);
190 }
191 
~Key2KanaTableSet()192 Key2KanaTableSet::~Key2KanaTableSet() {}
193 
setTypingMethod(TypingMethod method,Key2KanaTable * fundamental_table)194 void Key2KanaTableSet::setTypingMethod(TypingMethod method,
195                                        Key2KanaTable *fundamental_table) {
196     typingMethod_ = method;
197     fundamentalTable_ = fundamental_table;
198     resetTables();
199 }
200 
setSymbolHalf(bool half)201 void Key2KanaTableSet::setSymbolHalf(bool half) {
202     useHalfSymbol_ = half;
203     resetTables();
204 }
205 
setNumberHalf(bool half)206 void Key2KanaTableSet::setNumberHalf(bool half) {
207     useHalfNumber_ = half;
208     resetTables();
209 }
210 
setPeriodStyle(PeriodStyle style)211 void Key2KanaTableSet::setPeriodStyle(PeriodStyle style) {
212     periodStyle_ = style;
213     resetTables();
214 }
215 
setCommaStyle(CommaStyle style)216 void Key2KanaTableSet::setCommaStyle(CommaStyle style) {
217     commaStyle_ = style;
218     resetTables();
219 }
220 
setBracketStyle(BracketStyle style)221 void Key2KanaTableSet::setBracketStyle(BracketStyle style) {
222     bracketStyle_ = style;
223     resetTables();
224 }
225 
setSlashStyle(SlashStyle style)226 void Key2KanaTableSet::setSlashStyle(SlashStyle style) {
227     slashStyle_ = style;
228     resetTables();
229 }
230 
create_voiced_consonant_table(Key2KanaTable & table,Key2KanaTable & fund_table)231 static void create_voiced_consonant_table(Key2KanaTable &table,
232                                           Key2KanaTable &fund_table) {
233     table.clear();
234 
235     const std::string sonant_mark = std::string("\xE3\x82\x9B");
236     const std::string half_sonant_mark = std::string("\xE3\x82\x9C");
237     std::vector<std::string> sonant_mark_list;
238     std::vector<std::string> half_sonant_mark_list;
239 
240     Key2KanaRules::iterator it;
241     Key2KanaRules &rules = fund_table.table();
242     for (it = rules.begin(); it != rules.end(); it++) {
243         std::string result = it->result(0);
244         if (result == sonant_mark)
245             sonant_mark_list.push_back(it->sequence());
246         else if (result == half_sonant_mark)
247             half_sonant_mark_list.push_back(it->sequence());
248     }
249 
250     VoicedConsonantRule *templ = fcitx_anthy_voiced_consonant_table;
251 
252     for (unsigned int i = 0; templ[i].string; i++) {
253         if (templ[i].voiced && *templ[i].voiced) {
254             std::vector<std::string>::iterator it;
255             for (it = sonant_mark_list.begin(); it != sonant_mark_list.end();
256                  it++) {
257                 table.appendRule(std::string(templ[i].string) + *it,
258                                  std::string(templ[i].voiced), std::string());
259             }
260         }
261         if (templ[i].half_voiced && *templ[i].half_voiced) {
262             std::vector<std::string>::iterator it;
263             for (it = half_sonant_mark_list.begin();
264                  it != half_sonant_mark_list.end(); it++) {
265                 table.appendRule(std::string(templ[i].string) + *it,
266                                  std::string(templ[i].half_voiced),
267                                  std::string());
268             }
269         }
270     }
271 }
272 
resetTables()273 void Key2KanaTableSet::resetTables() {
274     allTables_.clear();
275 
276     bool is_romaji = typingMethod_ == TypingMethod::ROMAJI;
277     bool is_kana = typingMethod_ == TypingMethod::KANA;
278     bool is_nicola = typingMethod_ == TypingMethod::NICOLA;
279 
280     // symbols table
281     if (useHalfSymbol_)
282         allTables_.push_back(&half_symbol_table);
283     else
284         allTables_.push_back(&wide_symbol_table);
285 
286     // numbers table
287     if (useHalfNumber_)
288         allTables_.push_back(&half_number_table);
289     else
290         allTables_.push_back(&wide_number_table);
291 
292     if (is_romaji || is_kana) {
293         switch (periodStyle_) {
294         case PeriodStyle::JAPANESE:
295             if (is_romaji)
296                 allTables_.push_back(&romaji_ja_period_table);
297             else
298                 allTables_.push_back(&kana_ja_period_table);
299             break;
300         case PeriodStyle::WIDE:
301             if (is_romaji)
302                 allTables_.push_back(&romaji_wide_period_table);
303             else
304                 allTables_.push_back(&kana_wide_period_table);
305             break;
306         case PeriodStyle::HALF:
307             if (is_romaji)
308                 allTables_.push_back(&romaji_half_period_table);
309             else
310                 allTables_.push_back(&kana_half_period_table);
311             break;
312         default:
313             break;
314         }
315     }
316 
317     if (is_romaji || is_kana) {
318         switch (commaStyle_) {
319         case CommaStyle::JAPANESE:
320             if (is_romaji)
321                 allTables_.push_back(&romaji_ja_comma_table);
322             else
323                 allTables_.push_back(&kana_ja_comma_table);
324             break;
325         case CommaStyle::WIDE:
326             if (is_romaji)
327                 allTables_.push_back(&romaji_wide_comma_table);
328             else
329                 allTables_.push_back(&kana_wide_comma_table);
330             break;
331         case CommaStyle::HALF:
332             if (is_romaji)
333                 allTables_.push_back(&romaji_half_comma_table);
334             else
335                 allTables_.push_back(&kana_half_comma_table);
336             break;
337         default:
338             break;
339         }
340     }
341 
342     if (is_romaji || is_kana) {
343         switch (bracketStyle_) {
344         case BracketStyle::JAPANESE:
345             if (is_romaji)
346                 allTables_.push_back(&romaji_ja_bracket_table);
347             else
348                 allTables_.push_back(&kana_ja_bracket_table);
349             break;
350         case BracketStyle::WIDE:
351             if (is_romaji)
352                 allTables_.push_back(&romaji_wide_bracket_table);
353             else
354                 allTables_.push_back(&kana_wide_bracket_table);
355             break;
356         default:
357             break;
358         }
359     }
360 
361     if (is_romaji || is_kana) {
362         switch (slashStyle_) {
363         case SlashStyle::JAPANESE:
364             if (is_romaji)
365                 allTables_.push_back(&romaji_ja_slash_table);
366             else
367                 allTables_.push_back(&kana_ja_slash_table);
368             break;
369         case SlashStyle::WIDE:
370             if (is_romaji)
371                 allTables_.push_back(&romaji_wide_slash_table);
372             else
373                 allTables_.push_back(&kana_wide_slash_table);
374             break;
375         default:
376             break;
377         }
378     }
379 
380     if (!fundamentalTable_) {
381         if (is_romaji) {
382             allTables_.push_back(&romaji_double_consonant_table);
383             allTables_.push_back(&romaji_table);
384         } else if (is_kana) {
385             create_voiced_consonant_table(voicedConsonantTable_, kana_table);
386             allTables_.push_back(&voicedConsonantTable_);
387             allTables_.push_back(&kana_table);
388         } else if (is_nicola) {
389             allTables_.push_back(&nicola_table);
390         }
391     } else {
392         if (is_romaji) {
393             allTables_.push_back(&romaji_double_consonant_table);
394             allTables_.push_back(fundamentalTable_);
395         } else if (is_kana) {
396             create_voiced_consonant_table(voicedConsonantTable_,
397                                           *fundamentalTable_);
398             allTables_.push_back(&voicedConsonantTable_);
399             allTables_.push_back(fundamentalTable_);
400         } else if (is_nicola) {
401             allTables_.push_back(fundamentalTable_);
402         }
403     }
404 }
405