1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * SPDX-FileCopyrightText: 2005 Takuro Ashie
4 * SPDX-FileCopyrightText: 2012 CSSlayer <wengxt@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include <fcitx-utils/utf8.h>
10 #include <limits>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <unistd.h>
14
15 #include "default_tables.h"
16 #include "utils.h"
17 #include <fcitx-utils/stringutils.h>
18
utf8_string_substr(const std::string & s,size_t start,size_t len)19 std::string util::utf8_string_substr(const std::string &s, size_t start,
20 size_t len) {
21 auto iter = fcitx::utf8::nextNChar(s.begin(), start);
22 auto end = fcitx::utf8::nextNChar(iter, len);
23 std::string result(iter, end);
24 return result;
25 }
26
match_key_event(const fcitx::KeyList & hotkey,const fcitx::Key & _key,fcitx::KeyStates ignore_mask)27 bool util::match_key_event(const fcitx::KeyList &hotkey, const fcitx::Key &_key,
28 fcitx::KeyStates ignore_mask) {
29 fcitx::Key key = fcitx::Key(_key.sym(), _key.states() & ~ignore_mask);
30 return key.checkKeyList(hotkey);
31 }
32
split_string(std::string & str,std::vector<std::string> & str_list,char * delim,int num)33 void util::split_string(std::string &str, std::vector<std::string> &str_list,
34 char *delim, int num) {
35 std::string::size_type start = 0, end;
36
37 for (int i = 0; (num > 0 && i < num) || start < str.length(); i++) {
38 end = str.find(delim, start);
39 if ((num > 0 && i == num - 1) || (end == std::string::npos))
40 end = str.length();
41
42 if (start < str.length()) {
43 str_list.push_back(str.substr(start, end - start));
44 start = end + strlen(delim);
45 } else {
46 str_list.push_back(std::string());
47 }
48 }
49 }
50
convert_to_wide(const std::string & str)51 std::string util::convert_to_wide(const std::string &str) {
52 std::string wide;
53 for (unsigned int i = 0; i < str.length(); i++) {
54 int c = str[i];
55 char cc[2];
56 cc[0] = c;
57 cc[1] = '\0';
58 bool found = false;
59
60 for (unsigned int j = 0; fcitx_anthy_wide_table[j].code; j++) {
61 if (fcitx_anthy_wide_table[j].code &&
62 *fcitx_anthy_wide_table[j].code == c) {
63 wide += fcitx_anthy_wide_table[j].wide;
64 found = true;
65 break;
66 }
67 }
68
69 if (!found)
70 wide += cc;
71 }
72 return wide;
73 }
74
convert_to_half(const std::string & str)75 std::string util::convert_to_half(const std::string &str) {
76 std::string half;
77 for (unsigned int i = 0; i < fcitx::utf8::length(str); i++) {
78 std::string wide = util::utf8_string_substr(str, i, 1);
79 bool found = false;
80
81 for (unsigned int j = 0; fcitx_anthy_wide_table[j].code; j++) {
82 if (fcitx_anthy_wide_table[j].wide &&
83 wide == fcitx_anthy_wide_table[j].wide) {
84 half += fcitx_anthy_wide_table[j].code;
85 found = true;
86 break;
87 }
88 }
89
90 if (!found)
91 half += wide;
92 }
93 return half;
94 }
95
convert_to_katakana(const std::string & hira,bool half)96 std::string util::convert_to_katakana(const std::string &hira, bool half) {
97 std::string kata;
98 for (unsigned int i = 0; i < fcitx::utf8::length(hira); i++) {
99 std::string tmpwide;
100 bool found = false;
101
102 HiraganaKatakanaRule *table = fcitx_anthy_hiragana_katakana_table;
103
104 for (unsigned int j = 0; table[j].hiragana; j++) {
105 tmpwide = table[j].hiragana;
106 if (util::utf8_string_substr(hira, i, 1) == tmpwide) {
107 if (half)
108 kata += table[j].half_katakana;
109 else
110 kata += table[j].katakana;
111 found = true;
112 break;
113 }
114 }
115
116 if (!found)
117 kata += util::utf8_string_substr(hira, i, 1);
118 }
119 return kata;
120 }
121
key_is_keypad(const fcitx::Key & key)122 bool util::key_is_keypad(const fcitx::Key &key) {
123 switch (key.sym()) {
124 case FcitxKey_KP_Equal:
125 case FcitxKey_KP_Multiply:
126 case FcitxKey_KP_Add:
127 case FcitxKey_KP_Separator:
128 case FcitxKey_KP_Subtract:
129 case FcitxKey_KP_Decimal:
130 case FcitxKey_KP_Divide:
131 case FcitxKey_KP_0:
132 case FcitxKey_KP_1:
133 case FcitxKey_KP_2:
134 case FcitxKey_KP_3:
135 case FcitxKey_KP_4:
136 case FcitxKey_KP_5:
137 case FcitxKey_KP_6:
138 case FcitxKey_KP_7:
139 case FcitxKey_KP_8:
140 case FcitxKey_KP_9:
141 return true;
142 default:
143 return false;
144 }
145 }
146
keypad_to_string(const fcitx::KeyEvent & key)147 std::string util::keypad_to_string(const fcitx::KeyEvent &key) {
148 char raw[2];
149
150 switch (key.rawKey().sym()) {
151 case FcitxKey_KP_Equal:
152 raw[0] = '=';
153 break;
154
155 case FcitxKey_KP_Multiply:
156 raw[0] = '*';
157 break;
158
159 case FcitxKey_KP_Add:
160 raw[0] = '+';
161 break;
162
163 case FcitxKey_KP_Separator:
164 raw[0] = ',';
165 break;
166
167 case FcitxKey_KP_Subtract:
168 raw[0] = '-';
169 break;
170
171 case FcitxKey_KP_Decimal:
172 raw[0] = '.';
173 break;
174
175 case FcitxKey_KP_Divide:
176 raw[0] = '/';
177 break;
178
179 case FcitxKey_KP_0:
180 case FcitxKey_KP_1:
181 case FcitxKey_KP_2:
182 case FcitxKey_KP_3:
183 case FcitxKey_KP_4:
184 case FcitxKey_KP_5:
185 case FcitxKey_KP_6:
186 case FcitxKey_KP_7:
187 case FcitxKey_KP_8:
188 case FcitxKey_KP_9:
189 raw[0] = '0' + key.rawKey().sym() - FcitxKey_KP_0;
190 break;
191
192 default:
193 raw[0] = util::get_ascii_code(key);
194 break;
195 }
196
197 raw[1] = '\0';
198 return raw;
199 }
200
launch_program(std::string command)201 void util::launch_program(std::string command) {
202 if (command.empty())
203 return;
204
205 /* split string */
206 auto array = fcitx::stringutils::split(command, FCITX_WHITESPACE);
207
208 if (array.size() <= 0)
209 return;
210
211 fcitx::startProcess(array);
212 }
213
surrounding_get_safe_delta(uint from,uint to,int32_t * delta)214 bool util::surrounding_get_safe_delta(uint from, uint to, int32_t *delta) {
215 const int64_t kInt32AbsMax =
216 llabs(static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
217 const int64_t kInt32AbsMin =
218 llabs(static_cast<int64_t>(std::numeric_limits<int32_t>::min()));
219 const int64_t kInt32SafeAbsMax = std::min(kInt32AbsMax, kInt32AbsMin);
220
221 const int64_t diff = static_cast<int64_t>(from) - static_cast<int64_t>(to);
222 if (llabs(diff) > kInt32SafeAbsMax) {
223 return false;
224 }
225
226 *delta = static_cast<int32_t>(diff);
227 return true;
228 }
229
230 // Returns true if |surrounding_text| contains |selected_text|
231 // from |cursor_pos| to |*anchor_pos|.
232 // Otherwise returns false.
search_anchor_pos_forward(const std::string & surrounding_text,const std::string & selected_text,size_t selected_chars_len,uint cursor_pos,uint * anchor_pos)233 static bool search_anchor_pos_forward(const std::string &surrounding_text,
234 const std::string &selected_text,
235 size_t selected_chars_len,
236 uint cursor_pos, uint *anchor_pos) {
237
238 size_t len = fcitx::utf8::length(surrounding_text);
239 if (len < cursor_pos) {
240 return false;
241 }
242
243 size_t offset =
244 fcitx::utf8::ncharByteLength(surrounding_text.begin(), cursor_pos);
245
246 if (surrounding_text.compare(offset, selected_text.size(), selected_text) !=
247 0) {
248 return false;
249 }
250 *anchor_pos = cursor_pos + selected_chars_len;
251 return true;
252 }
253
254 // Returns true if |surrounding_text| contains |selected_text|
255 // from |*anchor_pos| to |cursor_pos|.
256 // Otherwise returns false.
search_anchor_pos_backward(const std::string & surrounding_text,const std::string & selected_text,size_t selected_chars_len,uint cursor_pos,uint * anchor_pos)257 bool search_anchor_pos_backward(const std::string &surrounding_text,
258 const std::string &selected_text,
259 size_t selected_chars_len, uint cursor_pos,
260 uint *anchor_pos) {
261 if (cursor_pos < selected_chars_len) {
262 return false;
263 }
264
265 // Skip |iter| to (potential) anchor pos.
266 const uint skip_count = cursor_pos - selected_chars_len;
267 if (skip_count > cursor_pos) {
268 return false;
269 }
270 size_t offset =
271 fcitx::utf8::ncharByteLength(surrounding_text.begin(), skip_count);
272
273 if (surrounding_text.compare(offset, selected_text.size(), selected_text) !=
274 0) {
275 return false;
276 }
277 *anchor_pos = skip_count;
278 return true;
279 }
280
surrounding_get_anchor_pos_from_selection(const std::string & surrounding_text,const std::string & selected_text,uint cursor_pos,uint * anchor_pos)281 bool util::surrounding_get_anchor_pos_from_selection(
282 const std::string &surrounding_text, const std::string &selected_text,
283 uint cursor_pos, uint *anchor_pos) {
284 if (surrounding_text.empty()) {
285 return false;
286 }
287
288 if (selected_text.empty()) {
289 return false;
290 }
291
292 const size_t selected_chars_len = fcitx::utf8::length(selected_text);
293
294 if (search_anchor_pos_forward(surrounding_text, selected_text,
295 selected_chars_len, cursor_pos, anchor_pos)) {
296 return true;
297 }
298
299 return search_anchor_pos_backward(surrounding_text, selected_text,
300 selected_chars_len, cursor_pos,
301 anchor_pos);
302 }
303
selection_keys()304 const fcitx::KeyList &util::selection_keys() {
305 const static fcitx::KeyList selectionKeys{
306 fcitx::Key(FcitxKey_1), fcitx::Key(FcitxKey_2), fcitx::Key(FcitxKey_3),
307 fcitx::Key(FcitxKey_4), fcitx::Key(FcitxKey_5), fcitx::Key(FcitxKey_6),
308 fcitx::Key(FcitxKey_7), fcitx::Key(FcitxKey_8), fcitx::Key(FcitxKey_9),
309 fcitx::Key(FcitxKey_0)};
310 return selectionKeys;
311 }
312