1 /***************************************************************************
2 * Copyright (C) 2012~2012 by Yichao Yu *
3 * yyc1992@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 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 *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 #include "fcitx/fcitx.h"
22 #include "config.h"
23
24 #include "fcitx/ime.h"
25 #include "fcitx/instance.h"
26 #include "fcitx/context.h"
27 #include "fcitx/module.h"
28 #include "fcitx/frontend.h"
29 #include "fcitx-config/xdg.h"
30 #include "fcitx-utils/log.h"
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <time.h>
34
35 #include "spell-internal.h"
36 #include "spell-enchant.h"
37 #include <dlfcn.h>
38
39 static void *_enchant_handle = NULL;
40 static void *(*_enchant_broker_init)() = NULL;
41 static char **(*_enchant_dict_suggest)(void *dict, const char *str,
42 ssize_t len, size_t *out_n) = NULL;
43 static void (*_enchant_dict_free_string_list)(void *dict,
44 char **str_list) = NULL;
45 static void (*_enchant_broker_free_dict)(void *broker, void *dict) = NULL;
46 static void (*_enchant_broker_free)(void *broker) = NULL;
47 static void *(*_enchant_broker_request_dict)(void *broker,
48 const char *const tag) = NULL;
49 static void (*_enchant_broker_set_ordering)(void *broker,
50 const char *const tag,
51 const char *const ordering) = NULL;
52 static void (*_enchant_dict_add)(void *dict, const char *const word,
53 ssize_t len) = NULL;
54
55 static boolean
SpellEnchantLoadLib()56 SpellEnchantLoadLib()
57 {
58 if (_enchant_handle)
59 return true;
60 _enchant_handle = dlopen(ENCHANT_LIBRARY_FILENAME, RTLD_NOW | RTLD_NODELETE | RTLD_GLOBAL);
61 if (!_enchant_handle)
62 goto fail;
63 #define ENCHANT_LOAD_SYMBOL(sym) do { \
64 _##sym = dlsym(_enchant_handle, #sym);\
65 if (!_##sym) \
66 goto fail; \
67 } while(0)
68 ENCHANT_LOAD_SYMBOL(enchant_broker_init);
69 ENCHANT_LOAD_SYMBOL(enchant_dict_suggest);
70 ENCHANT_LOAD_SYMBOL(enchant_dict_free_string_list);
71 ENCHANT_LOAD_SYMBOL(enchant_broker_free_dict);
72 ENCHANT_LOAD_SYMBOL(enchant_broker_free);
73 ENCHANT_LOAD_SYMBOL(enchant_broker_request_dict);
74 ENCHANT_LOAD_SYMBOL(enchant_broker_set_ordering);
75 ENCHANT_LOAD_SYMBOL(enchant_dict_add);
76 return true;
77 fail:
78 if (_enchant_handle) {
79 dlclose(_enchant_handle);
80 _enchant_handle = NULL;
81 }
82 return false;
83 }
84
85 boolean
SpellEnchantInit(FcitxSpell * spell)86 SpellEnchantInit(FcitxSpell *spell)
87 {
88 if (spell->broker)
89 return true;
90 if (!SpellEnchantLoadLib())
91 return false;
92 spell->broker = _enchant_broker_init();
93 spell->cur_enchant_provider = EP_Default;
94 if (!spell->broker)
95 return false;
96 if (spell->dictLang)
97 SpellEnchantLoadDict(spell, spell->dictLang);
98 return true;
99 }
100
101 SpellHint*
SpellEnchantHintWords(FcitxSpell * spell,unsigned int len_limit)102 SpellEnchantHintWords(FcitxSpell *spell, unsigned int len_limit)
103 {
104 SpellHint *res = NULL;
105 if (!SpellEnchantInit(spell))
106 return NULL;
107 if (!spell->enchant_dict || spell->enchant_saved_lang)
108 return NULL;
109 char **suggestions = NULL;
110 size_t number = 0;
111 if (!*spell->current_str)
112 return NULL;
113 suggestions = _enchant_dict_suggest(spell->enchant_dict, spell->current_str,
114 strlen(spell->current_str), &number);
115 if (!suggestions)
116 return NULL;
117 number = number > len_limit ? len_limit : number;
118 res = SpellHintList(number, suggestions, NULL);
119 _enchant_dict_free_string_list(spell->enchant_dict, suggestions);
120 return res;
121 }
122
123 boolean
SpellEnchantCheck(FcitxSpell * spell)124 SpellEnchantCheck(FcitxSpell *spell)
125 {
126 if (!SpellEnchantInit(spell))
127 return false;
128 if (spell->enchant_dict && !spell->enchant_saved_lang)
129 return true;
130 return false;
131 }
132
133 void
SpellEnchantDestroy(FcitxSpell * spell)134 SpellEnchantDestroy(FcitxSpell *spell)
135 {
136 if (spell->broker) {
137 if (spell->enchant_dict)
138 _enchant_broker_free_dict(spell->broker, spell->enchant_dict);
139 _enchant_broker_free(spell->broker);
140 }
141 if (spell->enchant_saved_lang)
142 free(spell->enchant_saved_lang);
143 /* if (spell->enchantLanguages) */
144 /* fcitx_utils_free_string_list(spell->enchantLanguages); */
145 }
146
147 boolean
SpellEnchantLoadDict(FcitxSpell * spell,const char * lang)148 SpellEnchantLoadDict(FcitxSpell *spell, const char *lang)
149 {
150 void *enchant_dict;
151 if (!SpellEnchantInit(spell))
152 return false;
153 if (!spell->broker)
154 return false;
155 if (spell->enchant_saved_lang &&
156 !strcmp(spell->enchant_saved_lang, lang)) {
157 free(spell->enchant_saved_lang);
158 spell->enchant_saved_lang = NULL;
159 return true;
160 }
161 enchant_dict = _enchant_broker_request_dict(spell->broker, lang);
162 if (enchant_dict) {
163 if (spell->enchant_saved_lang) {
164 free(spell->enchant_saved_lang);
165 spell->enchant_saved_lang = NULL;
166 }
167 if (spell->enchant_dict)
168 _enchant_broker_free_dict(spell->broker, spell->enchant_dict);
169 spell->enchant_dict = enchant_dict;
170 return true;
171 }
172 if (!spell->enchant_dict || !spell->dictLang)
173 return false;
174 if (spell->enchant_saved_lang)
175 return false;
176 spell->enchant_saved_lang = strdup(spell->dictLang);
177 return false;
178 }
179
180 void
SpellEnchantApplyConfig(FcitxSpell * spell)181 SpellEnchantApplyConfig(FcitxSpell *spell)
182 {
183 if (!SpellEnchantInit(spell))
184 return;
185 if (!spell->broker) {
186 spell->broker = _enchant_broker_init();
187 spell->cur_enchant_provider = EP_Default;
188 if (!spell->broker)
189 return;
190 }
191 if (spell->cur_enchant_provider == spell->config.enchant_provider)
192 return;
193 if (spell->config.enchant_provider == EP_Default) {
194 if (spell->enchant_saved_lang) {
195 free(spell->enchant_saved_lang);
196 spell->enchant_saved_lang = NULL;
197 }
198 if (spell->enchant_dict) {
199 _enchant_broker_free_dict(spell->broker, spell->enchant_dict);
200 spell->enchant_dict = NULL;
201 }
202 _enchant_broker_free(spell->broker);
203 spell->broker = _enchant_broker_init();
204 spell->cur_enchant_provider = EP_Default;
205 if (!spell->broker)
206 return;
207 }
208 switch (spell->config.enchant_provider) {
209 case EP_Aspell:
210 _enchant_broker_set_ordering(spell->broker, "*",
211 "aspell,myspell,ispell");
212 break;
213 case EP_Myspell:
214 _enchant_broker_set_ordering(spell->broker, "*",
215 "myspell,aspell,ispell");
216 break;
217 default:
218 break;
219 }
220 spell->cur_enchant_provider = spell->config.enchant_provider;
221 if (!spell->enchant_dict && spell->dictLang && spell->dictLang[0]) {
222 spell->enchant_dict = _enchant_broker_request_dict(spell->broker,
223 spell->dictLang);
224 }
225 }
226
227 void
SpellEnchantAddPersonal(FcitxSpell * spell,const char * new_word)228 SpellEnchantAddPersonal(FcitxSpell *spell, const char *new_word)
229 {
230 if (!SpellEnchantInit(spell))
231 return;
232 if (spell->enchant_dict && !spell->enchant_saved_lang) {
233 _enchant_dict_add(spell->enchant_dict, new_word,
234 strlen(new_word));
235 return;
236 }
237 }
238