1 /* suggestions.c
2 * Artha - Free cross-platform open thesaurus
3 * Copyright (C) 2009, 2010 Sundaram Ramaswamy, legends2k@yahoo.com
4 *
5 * Artha 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 * Artha 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 Artha; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20
21 /*
22 * Dynamic loading of libenchant's functions for spell checks.
23 */
24
25
26 #include <string.h>
27 #include <sys/types.h>
28 #include <gmodule.h>
29 #include "suggestions.h"
30 #include "wni.h"
31
32 #ifdef _WIN32
33 # define ENCHANT_FILE "libenchant.dll"
34 #else
35 # define ENCHANT_FILE "libenchant.so.1"
36 #endif
37 #define DICT_TAG_MAX_LENGTH 7
38
39 // Global variables
40
41 GModule *mod_enchant = NULL;
42 EnchantBroker *enchant_broker = NULL;
43 EnchantDict *enchant_dict = NULL;
44
45 const gchar* dict_lang_tag = "en";
46
suggestions_get(const gchar * lemma)47 GSList* suggestions_get(const gchar *lemma)
48 {
49 GSList *suggestions_list = NULL;
50
51 // check if Enchant broker and English dictionary are initialized
52 if(enchant_broker && enchant_dict)
53 {
54 if(enchant_dict_check(enchant_dict, lemma, -1))
55 {
56 size_t suggestions_count = 0;
57 gchar **suggestions = enchant_dict_suggest(enchant_dict, lemma, -1, &suggestions_count);
58
59 for(size_t i = 0; i < suggestions_count; i++)
60 {
61 if(wni_request_nyms(suggestions[i], NULL, (WNIRequestFlags) 0, FALSE))
62 {
63 suggestions_list = g_slist_append(suggestions_list, g_strdup(suggestions[i]));
64 }
65 }
66
67 if(suggestions)
68 enchant_dict_free_string_list(enchant_dict, suggestions);
69 }
70 }
71
72 return suggestions_list;
73 }
74
75 /*
76 checks if the passed LANG (code) is a form of the language we're interested in; this
77 is to know if the lang is the same, omitting the locale e.g. en_IN is suitable for 'en'
78 */
is_lang_suitable(const gchar * lang_code)79 static gboolean is_lang_suitable(const gchar *lang_code)
80 {
81 if(strlen(lang_code) >= strlen(dict_lang_tag))
82 {
83 if(lang_code[0] == dict_lang_tag[0] && lang_code[1] == dict_lang_tag[1] &&
84 ('_' == lang_code[2] || '\0' == lang_code[2] || '-' == lang_code[2]))
85 return TRUE;
86 }
87
88 return FALSE;
89 }
90
find_dictionary(const char * const lang_tag,const char * const provider_name,const char * const provider_desc,const char * const provider_file,void * user_data)91 static void find_dictionary(const char * const lang_tag, const char * const provider_name,
92 const char * const provider_desc,
93 const char * const provider_file,
94 void * user_data)
95 {
96 gchar *str_dict_tag = user_data;
97
98 if(str_dict_tag[0] == '\0')
99 {
100 if(is_lang_suitable(lang_tag))
101 {
102 g_snprintf(str_dict_tag, DICT_TAG_MAX_LENGTH, "%s", lang_tag);
103 G_MESSAGE("Alternative dict '%s' selected!\n", lang_tag);
104 }
105 }
106 }
107
try_sys_lang(gchar * copy_dict_tag,guint8 max_length)108 static gboolean try_sys_lang(gchar *copy_dict_tag, guint8 max_length)
109 {
110 const gchar *sys_lang = g_getenv("LANG");
111 gchar *temp_str = NULL;
112
113 if(sys_lang)
114 {
115 if(is_lang_suitable(sys_lang))
116 {
117 g_strlcpy(copy_dict_tag, sys_lang, max_length);
118
119 /* some machines have not only the lang but also the char encoding
120 e.g. "en_IN.UTF-8"; keep only the language "en_IN" and truncate
121 the encoding "UTF-8", if present */
122 temp_str = g_strstr_len(copy_dict_tag, -1, ".");
123 if(temp_str) *temp_str = '\0';
124
125 return TRUE;
126 }
127 }
128
129 return FALSE;
130 }
131
suggestions_init()132 gboolean suggestions_init()
133 {
134 gchar dict_tag[DICT_TAG_MAX_LENGTH] = "";
135
136 if(g_module_supported() && (mod_enchant = g_module_open(ENCHANT_FILE, G_MODULE_BIND_LAZY)))
137 {
138 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_broker_init), (gpointer *) &enchant_broker_init);
139 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_broker_free), (gpointer *) &enchant_broker_free);
140 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_broker_list_dicts), (gpointer *) &enchant_broker_list_dicts);
141 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_broker_dict_exists), (gpointer *) &enchant_broker_dict_exists);
142 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_broker_request_dict), (gpointer *) &enchant_broker_request_dict);
143 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_broker_free_dict), (gpointer *) &enchant_broker_free_dict);
144 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_dict_check), (gpointer *) &enchant_dict_check);
145 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_dict_suggest), (gpointer *) &enchant_dict_suggest);
146 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_dict_free_string_list), (gpointer *) &enchant_dict_free_string_list);
147
148 // in older version of Enchant, enchant_dict_free_string_list might be absent, they will have the
149 // now deprecated function enchant_dict_free_suggestions
150 if(NULL == enchant_dict_free_string_list)
151 g_module_symbol(mod_enchant, G_STRINGIFY(enchant_dict_free_string_list), (gpointer *) &enchant_dict_free_string_list);
152
153 // check if we have obtained the essential function pointers
154 if(NULL != enchant_broker_init && NULL != enchant_broker_free && NULL != enchant_broker_dict_exists &&
155 NULL != enchant_broker_request_dict && NULL != enchant_broker_free_dict && NULL != enchant_dict_check &&
156 NULL != enchant_dict_suggest && NULL != enchant_dict_free_string_list)
157 {
158 enchant_broker = enchant_broker_init();
159 if(enchant_broker)
160 {
161 /* if the sys. lang is suitable, copy that
162 else copy the default lang tag */
163 if(try_sys_lang(dict_tag, DICT_TAG_MAX_LENGTH))
164 {
165 if(enchant_broker_dict_exists(enchant_broker, dict_tag))
166 {
167 enchant_dict = enchant_broker_request_dict(enchant_broker, dict_tag);
168 return TRUE;
169 }
170
171 G_MESSAGE("Suggestions: Couldn't get '%s' dict. Looking for alternatives...\n", dict_lang_tag);
172 }
173
174 g_strlcpy(dict_tag, dict_lang_tag, DICT_TAG_MAX_LENGTH);
175
176 /* if the req. dict. doesn't exist and if list dict func. exists then try to enumerate
177 the dictionaries and see if a compatible one can be found */
178 if(!enchant_broker_dict_exists(enchant_broker, dict_tag) && enchant_broker_list_dicts)
179 {
180 G_MESSAGE("Suggestions: Couldn't get '%s' dict. Looking for alternatives...\n", dict_lang_tag);
181
182 dict_tag[0] = '\0';
183 enchant_broker_list_dicts(enchant_broker, find_dictionary, dict_tag);
184 }
185
186 if(dict_tag[0] != '\0')
187 {
188 enchant_dict = enchant_broker_request_dict(enchant_broker, dict_tag);
189 G_MESSAGE("Suggestions module successfully loaded");
190 return TRUE;
191 }
192 }
193 }
194 }
195
196 if(enchant_broker)
197 {
198 enchant_broker_free(enchant_broker);
199 enchant_broker = NULL;
200 }
201
202 if(mod_enchant)
203 {
204 g_module_close(mod_enchant);
205 mod_enchant = NULL;
206 }
207
208 G_MESSAGE("Failed to load suggestions module");
209
210 return FALSE;
211 }
212
suggestions_uninit()213 gboolean suggestions_uninit()
214 {
215 gboolean free_success = FALSE;
216
217 if(enchant_dict)
218 {
219 enchant_broker_free_dict(enchant_broker, enchant_dict);
220 enchant_dict = NULL;
221 }
222
223 if(enchant_broker)
224 {
225 enchant_broker_free(enchant_broker);
226 enchant_broker = NULL;
227 }
228
229 if(mod_enchant)
230 {
231 free_success = g_module_close(mod_enchant);
232 mod_enchant = NULL;
233 }
234
235 return free_success;
236 }
237
238