1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2005 Takuro Ashie
4 * Copyright (C) 2012 CSSlayer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <string.h>
22 #include <sys/wait.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <fcitx-utils/utf8.h>
26 #include <limits>
27
28 #include "utils.h"
29 #include "default_tables.h"
30
31 size_t
util_utf8_string_length(const std::string & s)32 util_utf8_string_length(const std::string& s)
33 {
34 return fcitx_utf8_strlen(s.c_str());
35 }
36
37 std::string
util_utf8_string_substr(const std::string & s,size_t start,size_t len)38 util_utf8_string_substr(const std::string& s, size_t start, size_t len)
39 {
40 char* cs = strdup(s.c_str());
41 char* startp = fcitx_utf8_get_nth_char(cs, start);
42 char* endp = fcitx_utf8_get_nth_char(startp, len);
43 std::string result(startp, endp - startp);
44 free(cs);
45 return result;
46 }
47
48 bool
util_match_key_event(const FcitxHotkey * hotkey,const KeyEvent & key,uint32_t ignore_mask)49 util_match_key_event (const FcitxHotkey* hotkey, const KeyEvent &key,
50 uint32_t ignore_mask)
51 {
52 FcitxKeySym simpsym;
53 unsigned int simpstate;
54 FcitxHotkeyGetKey(key.sym, key.state, &simpsym, &simpstate);
55 return FcitxHotkeyIsHotKey(simpsym, simpstate & ~ignore_mask, hotkey);
56 }
57
58 void
util_split_string(std::string & str,std::vector<std::string> & str_list,char * delim,int num)59 util_split_string (std::string &str, std::vector<std::string> &str_list,
60 char *delim, int num)
61 {
62 std::string::size_type start = 0, end;
63
64 for (int i = 0; (num > 0 && i < num) || start < str.length (); i++) {
65 end = str.find (delim, start);
66 if ((num > 0 && i == num - 1) || (end == std::string::npos))
67 end = str.length ();
68
69 if (start < str.length ()) {
70 str_list.push_back (str.substr (start, end - start));
71 start = end + strlen (delim);
72 } else {
73 str_list.push_back (std::string ());
74 }
75 }
76 }
77
78 void
util_convert_to_wide(std::string & wide,const std::string & str)79 util_convert_to_wide (std::string & wide, const std::string & str)
80 {
81 for (unsigned int i = 0; i < str.length (); i++) {
82 int c = str[i];
83 char cc[2];
84 cc[0] = c;
85 cc[1] = '\0';
86 bool found = false;
87
88 for (unsigned int j = 0; fcitx_anthy_wide_table[j].code; j++) {
89 if ( fcitx_anthy_wide_table[j].code &&
90 *fcitx_anthy_wide_table[j].code == c)
91 {
92 wide += fcitx_anthy_wide_table[j].wide;
93 found = true;
94 break;
95 }
96 }
97
98 if (!found)
99 wide += cc;
100 }
101 }
102
103 void
util_convert_to_half(std::string & half,const std::string & str)104 util_convert_to_half (std::string & half, const std::string & str)
105 {
106 for (unsigned int i = 0; i < util_utf8_string_length(str); i++) {
107 std::string wide = util_utf8_string_substr(str, i, 1);
108 bool found = false;
109
110 for (unsigned int j = 0; fcitx_anthy_wide_table[j].code; j++) {
111 if (fcitx_anthy_wide_table[j].wide &&
112 wide == fcitx_anthy_wide_table[j].wide)
113 {
114 half += fcitx_anthy_wide_table[j].code;
115 found = true;
116 break;
117 }
118 }
119
120 if (!found)
121 half += wide;
122 }
123 }
124
125 void
util_convert_to_katakana(std::string & kata,const std::string & hira,bool half)126 util_convert_to_katakana (std::string & kata,
127 const std::string & hira,
128 bool half)
129 {
130 for (unsigned int i = 0; i < util_utf8_string_length(hira); i++) {
131 std::string tmpwide;
132 bool found = false;
133
134 HiraganaKatakanaRule *table = fcitx_anthy_hiragana_katakana_table;
135
136 for (unsigned int j = 0; table[j].hiragana; j++) {
137 tmpwide = table[j].hiragana;
138 if (util_utf8_string_substr(hira, i, 1) == tmpwide) {
139 if (half)
140 kata += table[j].half_katakana;
141 else
142 kata += table[j].katakana;
143 found = true;
144 break;
145 }
146 }
147
148 if (!found)
149 kata += util_utf8_string_substr(hira, i, 1);
150 }
151 }
152
153 bool
util_key_is_keypad(const KeyEvent & key)154 util_key_is_keypad (const KeyEvent &key)
155 {
156 switch (key.sym) {
157 case FcitxKey_KP_Equal:
158 case FcitxKey_KP_Multiply:
159 case FcitxKey_KP_Add:
160 case FcitxKey_KP_Separator:
161 case FcitxKey_KP_Subtract:
162 case FcitxKey_KP_Decimal:
163 case FcitxKey_KP_Divide:
164 case FcitxKey_KP_0:
165 case FcitxKey_KP_1:
166 case FcitxKey_KP_2:
167 case FcitxKey_KP_3:
168 case FcitxKey_KP_4:
169 case FcitxKey_KP_5:
170 case FcitxKey_KP_6:
171 case FcitxKey_KP_7:
172 case FcitxKey_KP_8:
173 case FcitxKey_KP_9:
174 return true;
175 default:
176 return false;
177 }
178 }
179
180 void
util_keypad_to_string(std::string & str,const KeyEvent & key)181 util_keypad_to_string (std::string &str, const KeyEvent &key)
182 {
183 char raw[2];
184
185 switch (key.sym) {
186 case FcitxKey_KP_Equal:
187 raw[0] = '=';
188 break;
189
190 case FcitxKey_KP_Multiply:
191 raw[0] = '*';
192 break;
193
194 case FcitxKey_KP_Add:
195 raw[0] = '+';
196 break;
197
198 case FcitxKey_KP_Separator:
199 raw[0] = ',';
200 break;
201
202 case FcitxKey_KP_Subtract:
203 raw[0] = '-';
204 break;
205
206 case FcitxKey_KP_Decimal:
207 raw[0] = '.';
208 break;
209
210 case FcitxKey_KP_Divide:
211 raw[0] = '/';
212 break;
213
214 case FcitxKey_KP_0:
215 case FcitxKey_KP_1:
216 case FcitxKey_KP_2:
217 case FcitxKey_KP_3:
218 case FcitxKey_KP_4:
219 case FcitxKey_KP_5:
220 case FcitxKey_KP_6:
221 case FcitxKey_KP_7:
222 case FcitxKey_KP_8:
223 case FcitxKey_KP_9:
224 raw[0] = '0' + key.sym - FcitxKey_KP_0;
225 break;
226
227 default:
228 if (isprint (key.get_ascii_code()))
229 raw[0] = key.get_ascii_code();
230 else
231 raw[0] = '\0';
232 break;
233 }
234
235 raw[1] = '\0';
236 str = raw;
237 }
238
239 void
util_launch_program(const char * command)240 util_launch_program (const char *command)
241 {
242 if (!command) return;
243
244 /* split string */
245 unsigned int len = strlen (command);
246 char tmp[len + 1];
247 strncpy (tmp, command, len);
248 tmp[len] = '\0';
249
250 char *str = tmp;
251 std::vector<char *> array;
252
253 for (unsigned int i = 0; i < len + 1; i++) {
254 if (!tmp[i] || isspace (tmp[i])) {
255 if (*str) {
256 tmp[i] = '\0';
257 array.push_back (str);
258 }
259 str = tmp + i + 1;
260 }
261 }
262
263 if (array.size () <= 0) return;
264 array.push_back (NULL);
265
266 char **args = (char**) fcitx_utils_malloc0(sizeof(char*) * array.size());
267 for (unsigned int i = 0; i < array.size (); i++)
268 args[i] = array[i];
269
270 fcitx_utils_start_process(args);
271
272 free(args);
273 }
274
util_surrounding_get_safe_delta(uint from,uint to,int32_t * delta)275 bool util_surrounding_get_safe_delta(uint from, uint to, int32_t *delta) {
276 const int64_t kInt32AbsMax =
277 llabs(static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
278 const int64_t kInt32AbsMin =
279 llabs(static_cast<int64_t>(std::numeric_limits<int32_t>::min()));
280 const int64_t kInt32SafeAbsMax =
281 std::min(kInt32AbsMax, kInt32AbsMin);
282
283 const int64_t diff = static_cast<int64_t>(from) - static_cast<int64_t>(to);
284 if (llabs(diff) > kInt32SafeAbsMax) {
285 return false;
286 }
287
288 *delta = static_cast<int32_t>(diff);
289 return true;
290 }
291
292 // Returns true if |surrounding_text| contains |selected_text|
293 // from |cursor_pos| to |*anchor_pos|.
294 // 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)295 static bool search_anchor_pos_forward(
296 const std::string &surrounding_text,
297 const std::string &selected_text,
298 size_t selected_chars_len,
299 uint cursor_pos,
300 uint *anchor_pos) {
301
302 size_t len = fcitx_utf8_strlen(surrounding_text.c_str());
303 if (len < cursor_pos) {
304 return false;
305 }
306
307 size_t offset = fcitx_utf8_get_nth_char(surrounding_text.c_str(), cursor_pos) - surrounding_text.c_str();
308
309 if (surrounding_text.compare(offset, selected_text.size(), selected_text) != 0) {
310 return false;
311 }
312 *anchor_pos = cursor_pos + selected_chars_len;
313 return true;
314 }
315
316 // Returns true if |surrounding_text| contains |selected_text|
317 // from |*anchor_pos| to |cursor_pos|.
318 // 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)319 bool search_anchor_pos_backward(
320 const std::string &surrounding_text,
321 const std::string &selected_text,
322 size_t selected_chars_len,
323 uint cursor_pos,
324 uint *anchor_pos) {
325 if (cursor_pos < selected_chars_len) {
326 return false;
327 }
328
329 // Skip |iter| to (potential) anchor pos.
330 const uint skip_count = cursor_pos - selected_chars_len;
331 if (skip_count > cursor_pos) {
332 return false;
333 }
334 size_t offset = fcitx_utf8_get_nth_char(surrounding_text.c_str(), skip_count) - surrounding_text.c_str();
335
336 if (surrounding_text.compare(offset, selected_text.size(), selected_text) != 0) {
337 return false;
338 }
339 *anchor_pos = skip_count;
340 return true;
341 }
342
util_surrounding_get_anchor_pos_from_selection(const std::string & surrounding_text,const std::string & selected_text,uint cursor_pos,uint * anchor_pos)343 bool util_surrounding_get_anchor_pos_from_selection(
344 const std::string &surrounding_text,
345 const std::string &selected_text,
346 uint cursor_pos,
347 uint *anchor_pos) {
348 if (surrounding_text.empty()) {
349 return false;
350 }
351
352 if (selected_text.empty()) {
353 return false;
354 }
355
356 const size_t selected_chars_len = fcitx_utf8_strlen(selected_text.c_str());
357
358 if (search_anchor_pos_forward(surrounding_text, selected_text,
359 selected_chars_len,
360 cursor_pos, anchor_pos)) {
361 return true;
362 }
363
364 return search_anchor_pos_backward(surrounding_text, selected_text,
365 selected_chars_len,
366 cursor_pos, anchor_pos);
367 }
368