1 /* enchant
2 * Copyright (C) 2003,2004 Dom Lachowicz
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 * In addition, as a special exception, Dom Lachowicz
20 * gives permission to link the code of this program with
21 * non-LGPL Spelling Provider libraries (eg: a MSFT Office
22 * spell checker backend) and distribute linked combinations including
23 * the two. You must obey the GNU Lesser General Public License in all
24 * respects for all of the code used other than said providers. If you modify
25 * this file, you may extend this exception to your version of the
26 * file, but you are not obligated to do so. If you do not wish to
27 * do so, delete this exception statement from your version.
28 */
29
30 /*
31 * This is the GNU Aspell Enchant Backend.
32 * GNU Aspell is by Kevin Atkinson. See http://aspell.net/
33 */
34
35 #include "config.h"
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <glib.h>
42 #include <aspell.h>
43
44 #include "enchant-provider.h"
45 #include "unused-parameter.h"
46
47
48 EnchantProvider *init_enchant_provider (void);
49
50 static int
aspell_dict_check(EnchantDict * me,const char * const word,size_t len)51 aspell_dict_check (EnchantDict * me, const char *const word, size_t len)
52 {
53 AspellSpeller *manager = (AspellSpeller *) me->user_data;
54
55 char *normalizedWord = g_utf8_normalize (word, len, G_NORMALIZE_NFC);
56 int val = aspell_speller_check (manager, normalizedWord, strlen(normalizedWord));
57 g_free(normalizedWord);
58
59 if (val == 0)
60 return 1;
61 else if (val > 0)
62 return 0;
63 else {
64 enchant_dict_set_error (me, aspell_speller_error_message (manager));
65 return -1;
66 }
67 }
68
69 static char **
aspell_dict_suggest(EnchantDict * me,const char * const word,size_t len,size_t * out_n_suggs)70 aspell_dict_suggest (EnchantDict * me, const char *const word,
71 size_t len, size_t * out_n_suggs)
72 {
73 AspellSpeller *manager = (AspellSpeller *) me->user_data;
74
75 char *normalizedWord = g_utf8_normalize (word, len, G_NORMALIZE_NFC);
76 const AspellWordList *word_list = aspell_speller_suggest (manager, normalizedWord, strlen(normalizedWord));
77 g_free(normalizedWord);
78
79 char **sugg_arr = NULL;
80 if (word_list)
81 {
82 AspellStringEnumeration *suggestions = aspell_word_list_elements (word_list);
83 if (suggestions)
84 {
85 size_t n_suggestions = aspell_word_list_size (word_list);
86 *out_n_suggs = n_suggestions;
87
88 if (n_suggestions)
89 {
90 sugg_arr = g_new0 (char *, n_suggestions + 1);
91
92 for (size_t i = 0; i < n_suggestions; i++)
93 {
94 const char *sugg = aspell_string_enumeration_next (suggestions);
95 if (sugg)
96 sugg_arr[i] = g_strdup (sugg);
97 }
98 }
99 delete_aspell_string_enumeration (suggestions);
100 }
101 }
102
103 return sugg_arr;
104 }
105
106 static void
aspell_dict_add_to_personal(EnchantDict * me,const char * const word,size_t len)107 aspell_dict_add_to_personal (EnchantDict * me,
108 const char *const word, size_t len)
109 {
110 AspellSpeller *manager = (AspellSpeller *) me->user_data;
111 aspell_speller_add_to_personal (manager, word, len);
112 aspell_speller_save_all_word_lists (manager);
113 }
114
115 static void
aspell_dict_add_to_session(EnchantDict * me,const char * const word,size_t len)116 aspell_dict_add_to_session (EnchantDict * me,
117 const char *const word, size_t len)
118 {
119 AspellSpeller *manager = (AspellSpeller *) me->user_data;
120 aspell_speller_add_to_session (manager, word, len);
121 }
122
123 static void
aspell_dict_store_replacement(EnchantDict * me,const char * const mis,size_t mis_len,const char * const cor,size_t cor_len)124 aspell_dict_store_replacement (EnchantDict * me,
125 const char *const mis, size_t mis_len,
126 const char *const cor, size_t cor_len)
127 {
128 AspellSpeller *manager = (AspellSpeller *) me->user_data;
129 aspell_speller_store_replacement (manager, mis, mis_len,
130 cor, cor_len);
131 aspell_speller_save_all_word_lists (manager);
132 }
133
134 static EnchantDict *
aspell_provider_request_dict(EnchantProvider * me _GL_UNUSED_PARAMETER,const char * const tag)135 aspell_provider_request_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, const char *const tag)
136 {
137 AspellConfig *spell_config = new_aspell_config ();
138 aspell_config_replace (spell_config, "language-tag", tag);
139 aspell_config_replace (spell_config, "encoding", "utf-8");
140
141 AspellCanHaveError *spell_error = new_aspell_speller (spell_config);
142 delete_aspell_config (spell_config);
143
144 if (aspell_error_number (spell_error) != 0)
145 {
146 delete_aspell_can_have_error(spell_error);
147 return NULL;
148 }
149
150 AspellSpeller *manager = to_aspell_speller (spell_error);
151
152 EnchantDict *dict = g_new0 (EnchantDict, 1);
153 dict->user_data = (void *) manager;
154 dict->check = aspell_dict_check;
155 dict->suggest = aspell_dict_suggest;
156 dict->add_to_personal = aspell_dict_add_to_personal;
157 dict->add_to_session = aspell_dict_add_to_session;
158 dict->store_replacement = aspell_dict_store_replacement;
159
160 return dict;
161 }
162
163 static void
aspell_provider_dispose_dict(EnchantProvider * me _GL_UNUSED_PARAMETER,EnchantDict * dict)164 aspell_provider_dispose_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, EnchantDict * dict)
165 {
166 AspellSpeller *manager = (AspellSpeller *) dict->user_data;
167 delete_aspell_speller (manager);
168
169 g_free (dict);
170 }
171
172 static char **
aspell_provider_list_dicts(EnchantProvider * me _GL_UNUSED_PARAMETER,size_t * out_n_dicts)173 aspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
174 size_t * out_n_dicts)
175 {
176 AspellConfig * spell_config = new_aspell_config ();
177 AspellDictInfoList * dlist = get_aspell_dict_info_list (spell_config);
178
179 *out_n_dicts = 0;
180 AspellDictInfoEnumeration * dels = aspell_dict_info_list_elements (dlist);
181
182 /* Note: aspell_dict_info_list_size() always returns zero: https://github.com/GNUAspell/aspell/issues/155 */
183 const AspellDictInfo * entry;
184 while ( (entry = aspell_dict_info_enumeration_next(dels)) != 0)
185 (*out_n_dicts)++;
186 delete_aspell_dict_info_enumeration (dels);
187
188 char ** out_list = NULL;
189
190 if (*out_n_dicts) {
191 out_list = g_new0 (char *, *out_n_dicts + 1);
192 dels = aspell_dict_info_list_elements (dlist);
193
194 for (size_t i = 0; i < *out_n_dicts; i++) {
195 entry = aspell_dict_info_enumeration_next (dels);
196 /* FIXME: should this be entry->code or entry->name ? */
197 out_list[i] = g_strdup (entry->code);
198 }
199
200 delete_aspell_dict_info_enumeration (dels);
201 }
202
203 delete_aspell_config (spell_config);
204
205 return out_list;
206 }
207
208 static void
aspell_provider_dispose(EnchantProvider * me)209 aspell_provider_dispose (EnchantProvider * me)
210 {
211 g_free (me);
212 }
213
214 static const char *
aspell_provider_identify(EnchantProvider * me _GL_UNUSED_PARAMETER)215 aspell_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER)
216 {
217 return "aspell";
218 }
219
220 static const char *
aspell_provider_describe(EnchantProvider * me _GL_UNUSED_PARAMETER)221 aspell_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER)
222 {
223 return "Aspell Provider";
224 }
225
226 EnchantProvider *
init_enchant_provider(void)227 init_enchant_provider (void)
228 {
229 EnchantProvider *provider = g_new0 (EnchantProvider, 1);
230 provider->dispose = aspell_provider_dispose;
231 provider->request_dict = aspell_provider_request_dict;
232 provider->dispose_dict = aspell_provider_dispose_dict;
233 provider->identify = aspell_provider_identify;
234 provider->describe = aspell_provider_describe;
235 provider->list_dicts = aspell_provider_list_dicts;
236
237 return provider;
238 }
239