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