5 The Free Software Foundation, Inc.
8 Ilia Maslakov <il.smind@gmail.com>, 2012
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #include "lib/charsets.h"
36 #include "lib/strutil.h"
38 #include "src/setup.h"
40 #include "edit-impl.h"
43 /*** global variables ****************************************************************************/
45 /*** file scope macro definitions ****************************************************************/
47 /*** file scope type declarations ****************************************************************/
49 typedef struct aspell_struct
52 AspellSpeller
*speller
;
55 /*** file scope variables ************************************************************************/
57 static GModule
*spell_module
= NULL
;
58 static spell_t
*global_speller
= NULL
;
60 static struct AspellConfig
*(*mc_new_aspell_config
) (void);
61 static int (*mc_aspell_config_replace
) (struct AspellConfig
* ths
, const char *key
,
63 static struct AspellCanHaveError
*(*mc_new_aspell_speller
) (struct AspellConfig
* config
);
64 static unsigned int (*mc_aspell_error_number
) (const struct AspellCanHaveError
* ths
);
65 static const char *(*mc_aspell_speller_error_message
) (const struct AspellSpeller
* ths
);
66 const struct AspellError
*(*mc_aspell_speller_error
) (const struct AspellSpeller
* ths
);
68 static struct AspellSpeller
*(*mc_to_aspell_speller
) (struct AspellCanHaveError
* obj
);
69 static int (*mc_aspell_speller_check
) (struct AspellSpeller
* ths
, const char *word
, int word_size
);
70 static const struct AspellWordList
*(*mc_aspell_speller_suggest
) (struct AspellSpeller
* ths
,
71 const char *word
, int word_size
);
72 static struct AspellStringEnumeration
*(*mc_aspell_word_list_elements
) (const struct AspellWordList
74 static const char *(*mc_aspell_config_retrieve
) (struct AspellConfig
* ths
, const char *key
);
75 static void (*mc_delete_aspell_speller
) (struct AspellSpeller
* ths
);
76 static void (*mc_delete_aspell_config
) (struct AspellConfig
* ths
);
77 static void (*mc_delete_aspell_can_have_error
) (struct AspellCanHaveError
* ths
);
78 static const char *(*mc_aspell_error_message
) (const struct AspellCanHaveError
* ths
);
79 static void (*mc_delete_aspell_string_enumeration
) (struct AspellStringEnumeration
* ths
);
80 static struct AspellDictInfoEnumeration
*(*mc_aspell_dict_info_list_elements
)
81 (const struct AspellDictInfoList
* ths
);
82 static struct AspellDictInfoList
*(*mc_get_aspell_dict_info_list
) (struct AspellConfig
* config
);
83 static const struct AspellDictInfo
*(*mc_aspell_dict_info_enumeration_next
)
84 (struct AspellDictInfoEnumeration
* ths
);
85 static const char *(*mc_aspell_string_enumeration_next
) (struct AspellStringEnumeration
* ths
);
86 static void (*mc_delete_aspell_dict_info_enumeration
) (struct AspellDictInfoEnumeration
* ths
);
87 static unsigned int (*mc_aspell_word_list_size
) (const struct AspellWordList
* ths
);
88 static const struct AspellError
*(*mc_aspell_error
) (const struct AspellCanHaveError
* ths
);
89 static int (*mc_aspell_speller_add_to_personal
) (struct AspellSpeller
* ths
, const char *word
,
91 static int (*mc_aspell_speller_save_all_word_lists
) (struct AspellSpeller
* ths
);
107 {"en_GB", "British English"},
108 {"en_CA", "Canadian English"},
109 {"en_US", "American English"},
118 {"pt", "Portuguese"},
128 /*** file scope functions ************************************************************************/
129 /* --------------------------------------------------------------------------------------------- */
131 * Found the language name by language code. For example: en_US -> American English.
133 * @param code Short name of the language (ru, en, pl, uk, etc...)
134 * @return language name
138 spell_decode_lang (const char *code
)
142 for (i
= 0; spell_codes_map
[i
].code
!= NULL
; i
++)
144 if (strcmp (spell_codes_map
[i
].code
, code
) == 0)
145 return spell_codes_map
[i
].name
;
151 /* --------------------------------------------------------------------------------------------- */
153 * Checks if aspell library and symbols are available.
155 * @return FALSE or error
159 spell_available (void)
161 gchar
*spell_module_fname
;
162 gboolean ret
= FALSE
;
164 if (spell_module
!= NULL
)
167 spell_module_fname
= g_module_build_path (NULL
, "libaspell");
168 spell_module
= g_module_open (spell_module_fname
, G_MODULE_BIND_LAZY
);
170 g_free (spell_module_fname
);
172 if (spell_module
== NULL
)
175 if (!g_module_symbol (spell_module
, "new_aspell_config", (void *) &mc_new_aspell_config
))
178 if (!g_module_symbol (spell_module
, "aspell_dict_info_list_elements",
179 (void *) &mc_aspell_dict_info_list_elements
))
182 if (!g_module_symbol (spell_module
, "aspell_dict_info_enumeration_next",
183 (void *) &mc_aspell_dict_info_enumeration_next
))
186 if (!g_module_symbol (spell_module
, "new_aspell_speller", (void *) &mc_new_aspell_speller
))
189 if (!g_module_symbol (spell_module
, "aspell_error_number", (void *) &mc_aspell_error_number
))
192 if (!g_module_symbol (spell_module
, "aspell_speller_error_message",
193 (void *) &mc_aspell_speller_error_message
))
196 if (!g_module_symbol (spell_module
, "aspell_speller_error", (void *) &mc_aspell_speller_error
))
199 if (!g_module_symbol (spell_module
, "aspell_error", (void *) &mc_aspell_error
))
202 if (!g_module_symbol (spell_module
, "to_aspell_speller", (void *) &mc_to_aspell_speller
))
205 if (!g_module_symbol (spell_module
, "aspell_speller_check", (void *) &mc_aspell_speller_check
))
209 (spell_module
, "aspell_speller_suggest", (void *) &mc_aspell_speller_suggest
))
213 (spell_module
, "aspell_word_list_elements", (void *) &mc_aspell_word_list_elements
))
216 if (!g_module_symbol (spell_module
, "aspell_string_enumeration_next",
217 (void *) &mc_aspell_string_enumeration_next
))
221 (spell_module
, "aspell_config_replace", (void *) &mc_aspell_config_replace
))
224 if (!g_module_symbol (spell_module
, "aspell_error_message", (void *) &mc_aspell_error_message
))
228 (spell_module
, "delete_aspell_speller", (void *) &mc_delete_aspell_speller
))
231 if (!g_module_symbol (spell_module
, "delete_aspell_config", (void *) &mc_delete_aspell_config
))
234 if (!g_module_symbol (spell_module
, "delete_aspell_string_enumeration",
235 (void *) &mc_delete_aspell_string_enumeration
))
238 if (!g_module_symbol (spell_module
, "get_aspell_dict_info_list",
239 (void *) &mc_get_aspell_dict_info_list
))
242 if (!g_module_symbol (spell_module
, "delete_aspell_can_have_error",
243 (void *) &mc_delete_aspell_can_have_error
))
246 if (!g_module_symbol (spell_module
, "delete_aspell_dict_info_enumeration",
247 (void *) &mc_delete_aspell_dict_info_enumeration
))
251 (spell_module
, "aspell_config_retrieve", (void *) &mc_aspell_config_retrieve
))
255 (spell_module
, "aspell_word_list_size", (void *) &mc_aspell_word_list_size
))
258 if (!g_module_symbol (spell_module
, "aspell_speller_add_to_personal",
259 (void *) &mc_aspell_speller_add_to_personal
))
262 if (!g_module_symbol (spell_module
, "aspell_speller_save_all_word_lists",
263 (void *) &mc_aspell_speller_save_all_word_lists
))
271 g_module_close (spell_module
);
277 /* --------------------------------------------------------------------------------------------- */
278 /*** public functions ****************************************************************************/
279 /* --------------------------------------------------------------------------------------------- */
281 * Initialization of Aspell support.
287 AspellCanHaveError
*error
= NULL
;
289 if (strcmp (spell_language
, "NONE") == 0)
292 if (global_speller
!= NULL
)
295 global_speller
= g_try_malloc (sizeof (spell_t
));
296 if (global_speller
== NULL
)
299 if (!spell_available ())
301 g_free (global_speller
);
302 global_speller
= NULL
;
306 global_speller
->config
= mc_new_aspell_config ();
307 global_speller
->speller
= NULL
;
309 if (spell_language
!= NULL
)
310 mc_aspell_config_replace (global_speller
->config
, "lang", spell_language
);
312 error
= mc_new_aspell_speller (global_speller
->config
);
314 if (mc_aspell_error_number (error
) == 0)
315 global_speller
->speller
= mc_to_aspell_speller (error
);
318 edit_error_dialog (_("Error"), mc_aspell_error_message (error
));
319 mc_delete_aspell_can_have_error (error
);
324 /* --------------------------------------------------------------------------------------------- */
326 * Deinitialization of Aspell support.
332 if (global_speller
== NULL
)
335 if (global_speller
->speller
!= NULL
)
336 mc_delete_aspell_speller (global_speller
->speller
);
338 if (global_speller
->config
!= NULL
)
339 mc_delete_aspell_config (global_speller
->config
);
341 g_free (global_speller
);
342 global_speller
= NULL
;
344 g_module_close (spell_module
);
348 /* --------------------------------------------------------------------------------------------- */
350 * Get array of available languages.
352 * @param lang_list Array of languages. Must be cleared before use
353 * @return language list length
357 aspell_get_lang_list (GArray
* lang_list
)
359 AspellDictInfoList
*dlist
;
360 AspellDictInfoEnumeration
*elem
;
361 const AspellDictInfo
*entry
;
364 if (spell_module
== NULL
)
367 /* the returned pointer should _not_ need to be deleted */
368 dlist
= mc_get_aspell_dict_info_list (global_speller
->config
);
369 elem
= mc_aspell_dict_info_list_elements (dlist
);
371 while ((entry
= mc_aspell_dict_info_enumeration_next (elem
)) != NULL
)
373 if (entry
->name
!= NULL
)
377 tmp
= g_strdup (entry
->name
);
378 g_array_append_val (lang_list
, tmp
);
383 mc_delete_aspell_dict_info_enumeration (elem
);
388 /* --------------------------------------------------------------------------------------------- */
390 * Clear the array of languages.
392 * @param array Array of languages
396 aspell_array_clean (GArray
* array
)
402 for (i
= 0; i
< array
->len
; ++i
)
406 tmp
= g_array_index (array
, char *, i
);
409 g_array_free (array
, TRUE
);
413 /* --------------------------------------------------------------------------------------------- */
415 * Get the current language name.
417 * @return language name
421 aspell_get_lang (void)
425 code
= mc_aspell_config_retrieve (global_speller
->config
, "lang");
426 return spell_decode_lang (code
);
429 /* --------------------------------------------------------------------------------------------- */
433 * @param lang Language name
434 * @return FALSE or error
438 aspell_set_lang (const char *lang
)
442 AspellCanHaveError
*error
;
443 const char *spell_codeset
;
445 g_free (spell_language
);
446 spell_language
= g_strdup (lang
);
449 if (mc_global
.source_codepage
> 0)
450 spell_codeset
= get_codepage_id (mc_global
.source_codepage
);
453 spell_codeset
= str_detect_termencoding ();
455 mc_aspell_config_replace (global_speller
->config
, "lang", lang
);
456 mc_aspell_config_replace (global_speller
->config
, "encoding", spell_codeset
);
458 /* the returned pointer should _not_ need to be deleted */
459 if (global_speller
->speller
!= NULL
)
460 mc_delete_aspell_speller (global_speller
->speller
);
462 global_speller
->speller
= NULL
;
464 error
= mc_new_aspell_speller (global_speller
->config
);
465 if (mc_aspell_error (error
) != 0)
467 mc_delete_aspell_can_have_error (error
);
471 global_speller
->speller
= mc_to_aspell_speller (error
);
476 /* --------------------------------------------------------------------------------------------- */
480 * @param word Word for spell check
481 * @param word_size Word size (in bytes)
482 * @return FALSE if word is not in the dictionary
486 aspell_check (const char *word
, const int word_size
)
490 if (word
!= NULL
&& global_speller
!= NULL
&& global_speller
->speller
!= NULL
)
491 res
= mc_aspell_speller_check (global_speller
->speller
, word
, word_size
);
496 /* --------------------------------------------------------------------------------------------- */
498 * Examine dictionaries and suggest possible words that may repalce the incorrect word.
500 * @param suggest array of words to iterate through
501 * @param word Word for spell check
502 * @param word_size Word size (in bytes)
503 * @return count of suggests for the word
507 aspell_suggest (GArray
* suggest
, const char *word
, const int word_size
)
509 unsigned int size
= 0;
511 if (word
!= NULL
&& global_speller
!= NULL
&& global_speller
->speller
!= NULL
)
513 const AspellWordList
*wordlist
;
515 wordlist
= mc_aspell_speller_suggest (global_speller
->speller
, word
, word_size
);
516 if (wordlist
!= NULL
)
518 AspellStringEnumeration
*elements
= NULL
;
521 elements
= mc_aspell_word_list_elements (wordlist
);
522 size
= mc_aspell_word_list_size (wordlist
);
524 for (i
= 0; i
< size
; i
++)
526 const char *cur_sugg_word
;
528 cur_sugg_word
= g_strdup (mc_aspell_string_enumeration_next (elements
));
529 if (cur_sugg_word
!= NULL
)
530 g_array_append_val (suggest
, cur_sugg_word
);
533 mc_delete_aspell_string_enumeration (elements
);
540 /* --------------------------------------------------------------------------------------------- */
542 * Add word to personal dictionary.
544 * @param word Word for spell check
545 * @param word_size Word size (in bytes)
546 * @return FALSE or error
549 aspell_add_to_dict (const char *word
, int word_size
)
551 mc_aspell_speller_add_to_personal (global_speller
->speller
, word
, word_size
);
553 if (mc_aspell_speller_error (global_speller
->speller
) != 0)
555 edit_error_dialog (_("Error"), mc_aspell_speller_error_message (global_speller
->speller
));
559 mc_aspell_speller_save_all_word_lists (global_speller
->speller
);
561 if (mc_aspell_speller_error (global_speller
->speller
) != 0)
563 edit_error_dialog (_("Error"), mc_aspell_speller_error_message (global_speller
->speller
));
570 /* --------------------------------------------------------------------------------------------- */