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 "edit-impl.h"
41 /*** global variables ****************************************************************************/
43 /*** file scope macro definitions ****************************************************************/
45 /*** file scope type declarations ****************************************************************/
47 typedef struct aspell_struct
50 AspellSpeller
*speller
;
53 /*** file scope variables ************************************************************************/
55 static GModule
*spell_module
= NULL
;
56 static spell_t
*global_speller
= NULL
;
58 static struct AspellConfig
*(*mc_new_aspell_config
) (void);
59 static int (*mc_aspell_config_replace
) (struct AspellConfig
* ths
, const char *key
,
61 static struct AspellCanHaveError
*(*mc_new_aspell_speller
) (struct AspellConfig
* config
);
62 static unsigned int (*mc_aspell_error_number
) (const struct AspellCanHaveError
* ths
);
63 static const char *(*mc_aspell_speller_error_message
) (const struct AspellSpeller
* ths
);
64 const struct AspellError
*(*mc_aspell_speller_error
) (const struct AspellSpeller
* ths
);
66 static struct AspellSpeller
*(*mc_to_aspell_speller
) (struct AspellCanHaveError
* obj
);
67 static int (*mc_aspell_speller_check
) (struct AspellSpeller
* ths
, const char *word
, int word_size
);
68 static const struct AspellWordList
*(*mc_aspell_speller_suggest
) (struct AspellSpeller
* ths
,
69 const char *word
, int word_size
);
70 static struct AspellStringEnumeration
*(*mc_aspell_word_list_elements
) (const struct AspellWordList
72 static const char *(*mc_aspell_config_retrieve
) (struct AspellConfig
* ths
, const char *key
);
73 static void (*mc_delete_aspell_speller
) (struct AspellSpeller
* ths
);
74 static void (*mc_delete_aspell_config
) (struct AspellConfig
* ths
);
75 static void (*mc_delete_aspell_can_have_error
) (struct AspellCanHaveError
* ths
);
76 static const char *(*mc_aspell_error_message
) (const struct AspellCanHaveError
* ths
);
77 static void (*mc_delete_aspell_string_enumeration
) (struct AspellStringEnumeration
* ths
);
78 static struct AspellDictInfoEnumeration
*(*mc_aspell_dict_info_list_elements
)
79 (const struct AspellDictInfoList
* ths
);
80 static struct AspellDictInfoList
*(*mc_get_aspell_dict_info_list
) (struct AspellConfig
* config
);
81 static const struct AspellDictInfo
*(*mc_aspell_dict_info_enumeration_next
)
82 (struct AspellDictInfoEnumeration
* ths
);
83 static const char *(*mc_aspell_string_enumeration_next
) (struct AspellStringEnumeration
* ths
);
84 static void (*mc_delete_aspell_dict_info_enumeration
) (struct AspellDictInfoEnumeration
* ths
);
85 static unsigned int (*mc_aspell_word_list_size
) (const struct AspellWordList
* ths
);
86 static const struct AspellError
*(*mc_aspell_error
) (const struct AspellCanHaveError
* ths
);
87 static int (*mc_aspell_speller_add_to_personal
) (struct AspellSpeller
* ths
, const char *word
,
89 static int (*mc_aspell_speller_save_all_word_lists
) (struct AspellSpeller
* ths
);
105 {"en_GB", "British English"},
106 {"en_CA", "Canadian English"},
107 {"en_US", "American English"},
116 {"pt", "Portuguese"},
126 /*** file scope functions ************************************************************************/
127 /* --------------------------------------------------------------------------------------------- */
129 * Found the language name by language code. For example: en_US -> American English.
131 * @param code Short name of the language (ru, en, pl, uk, etc...)
132 * @returns the language name
136 spell_decode_lang (const char *code
)
140 for (i
= 0; spell_codes_map
[i
].code
!= NULL
; i
++)
142 if (strcmp (spell_codes_map
[i
].code
, code
) == 0)
143 return spell_codes_map
[i
].name
;
149 /* --------------------------------------------------------------------------------------------- */
151 * Checks if aspell library and symbols are available.
153 * @returns FALSE or error
157 spell_available (void)
159 gchar
*spell_module_fname
;
160 gboolean ret
= FALSE
;
162 if (spell_module
!= NULL
)
165 spell_module_fname
= g_module_build_path (NULL
, "libaspell");
166 spell_module
= g_module_open (spell_module_fname
, G_MODULE_BIND_LAZY
);
168 g_free (spell_module_fname
);
170 if (spell_module
== NULL
)
173 if (!g_module_symbol (spell_module
, "new_aspell_config", (void *) &mc_new_aspell_config
))
176 if (!g_module_symbol (spell_module
, "aspell_dict_info_list_elements",
177 (void *) &mc_aspell_dict_info_list_elements
))
180 if (!g_module_symbol (spell_module
, "aspell_dict_info_enumeration_next",
181 (void *) &mc_aspell_dict_info_enumeration_next
))
184 if (!g_module_symbol (spell_module
, "new_aspell_speller", (void *) &mc_new_aspell_speller
))
187 if (!g_module_symbol (spell_module
, "aspell_error_number", (void *) &mc_aspell_error_number
))
190 if (!g_module_symbol (spell_module
, "aspell_speller_error_message",
191 (void *) &mc_aspell_speller_error_message
))
194 if (!g_module_symbol (spell_module
, "aspell_speller_error", (void *) &mc_aspell_speller_error
))
197 if (!g_module_symbol (spell_module
, "aspell_error", (void *) &mc_aspell_error
))
200 if (!g_module_symbol (spell_module
, "to_aspell_speller", (void *) &mc_to_aspell_speller
))
203 if (!g_module_symbol (spell_module
, "aspell_speller_check", (void *) &mc_aspell_speller_check
))
207 (spell_module
, "aspell_speller_suggest", (void *) &mc_aspell_speller_suggest
))
211 (spell_module
, "aspell_word_list_elements", (void *) &mc_aspell_word_list_elements
))
214 if (!g_module_symbol (spell_module
, "aspell_string_enumeration_next",
215 (void *) &mc_aspell_string_enumeration_next
))
219 (spell_module
, "aspell_config_replace", (void *) &mc_aspell_config_replace
))
222 if (!g_module_symbol (spell_module
, "aspell_error_message", (void *) &mc_aspell_error_message
))
226 (spell_module
, "delete_aspell_speller", (void *) &mc_delete_aspell_speller
))
229 if (!g_module_symbol (spell_module
, "delete_aspell_config", (void *) &mc_delete_aspell_config
))
232 if (!g_module_symbol (spell_module
, "delete_aspell_string_enumeration",
233 (void *) &mc_delete_aspell_string_enumeration
))
236 if (!g_module_symbol (spell_module
, "get_aspell_dict_info_list",
237 (void *) &mc_get_aspell_dict_info_list
))
240 if (!g_module_symbol (spell_module
, "delete_aspell_can_have_error",
241 (void *) &mc_delete_aspell_can_have_error
))
244 if (!g_module_symbol (spell_module
, "delete_aspell_dict_info_enumeration",
245 (void *) &mc_delete_aspell_dict_info_enumeration
))
249 (spell_module
, "aspell_config_retrieve", (void *) &mc_aspell_config_retrieve
))
253 (spell_module
, "aspell_word_list_size", (void *) &mc_aspell_word_list_size
))
256 if (!g_module_symbol (spell_module
, "aspell_speller_add_to_personal",
257 (void *) &mc_aspell_speller_add_to_personal
))
260 if (!g_module_symbol (spell_module
, "aspell_speller_save_all_word_lists",
261 (void *) &mc_aspell_speller_save_all_word_lists
))
269 g_module_close (spell_module
);
275 /* --------------------------------------------------------------------------------------------- */
276 /*** public functions ****************************************************************************/
277 /* --------------------------------------------------------------------------------------------- */
279 * Initialization of Aspell support.
285 AspellCanHaveError
*error
= NULL
;
287 if (global_speller
!= NULL
)
290 global_speller
= g_try_malloc (sizeof (spell_t
));
291 if (global_speller
== NULL
)
294 if (!spell_available ())
296 g_free (global_speller
);
297 global_speller
= NULL
;
301 global_speller
->config
= mc_new_aspell_config ();
302 global_speller
->speller
= NULL
;
304 error
= mc_new_aspell_speller (global_speller
->config
);
306 if (mc_aspell_error_number (error
) == 0)
307 global_speller
->speller
= mc_to_aspell_speller (error
);
310 edit_error_dialog (_("Error"), mc_aspell_error_message (error
));
311 mc_delete_aspell_can_have_error (error
);
316 /* --------------------------------------------------------------------------------------------- */
318 * Deinitialization of Aspell support.
324 if (global_speller
== NULL
)
327 if (global_speller
->speller
!= NULL
)
328 mc_delete_aspell_speller (global_speller
->speller
);
330 if (global_speller
->config
!= NULL
)
331 mc_delete_aspell_config (global_speller
->config
);
333 g_free (global_speller
);
334 global_speller
= NULL
;
336 g_module_close (spell_module
);
340 /* --------------------------------------------------------------------------------------------- */
342 * Get array of available languages.
344 * @param lang_list Array of languages. Must be cleared before use
345 * @returns language list length
349 aspell_get_lang_list (GArray
* lang_list
)
351 AspellDictInfoList
*dlist
;
352 AspellDictInfoEnumeration
*elem
;
353 const AspellDictInfo
*entry
;
356 if (spell_module
== NULL
)
359 /* the returned pointer should _not_ need to be deleted */
360 dlist
= mc_get_aspell_dict_info_list (global_speller
->config
);
361 elem
= mc_aspell_dict_info_list_elements (dlist
);
363 while ((entry
= mc_aspell_dict_info_enumeration_next (elem
)) != NULL
)
365 if (entry
->name
!= NULL
)
369 tmp
= g_strdup (entry
->name
);
370 g_array_append_val (lang_list
, tmp
);
375 mc_delete_aspell_dict_info_enumeration (elem
);
380 /* --------------------------------------------------------------------------------------------- */
382 * Clear the array of languages.
384 * @param array Array of languages
388 aspell_array_clean (GArray
* array
)
394 for (i
= 0; i
< array
->len
; ++i
)
398 tmp
= g_array_index (array
, char *, i
);
401 g_array_free (array
, TRUE
);
405 /* --------------------------------------------------------------------------------------------- */
407 * Get the current language name.
409 * @returns Language name
413 aspell_get_lang (void)
417 code
= mc_aspell_config_retrieve (global_speller
->config
, "lang");
418 return spell_decode_lang (code
);
421 /* --------------------------------------------------------------------------------------------- */
425 * @param lang Language name
426 * @returns FALSE or error
430 aspell_set_lang (const char *lang
)
435 AspellCanHaveError
*error
;
436 const char *spell_codeset
;
439 if (mc_global
.source_codepage
> 0)
440 spell_codeset
= get_codepage_id (mc_global
.source_codepage
);
443 spell_codeset
= str_detect_termencoding ();
445 res
= mc_aspell_config_replace (global_speller
->config
, "lang", lang
);
446 res
= mc_aspell_config_replace (global_speller
->config
, "encoding", spell_codeset
);
448 /* the returned pointer should _not_ need to be deleted */
449 if (global_speller
->speller
!= NULL
)
450 mc_delete_aspell_speller (global_speller
->speller
);
452 global_speller
->speller
= NULL
;
454 error
= mc_new_aspell_speller (global_speller
->config
);
455 if (mc_aspell_error (error
) != 0)
457 mc_delete_aspell_can_have_error (error
);
461 global_speller
->speller
= mc_to_aspell_speller (error
);
466 /* --------------------------------------------------------------------------------------------- */
470 * @param word Word for spell check
471 * @param word_size Word size (in bytes)
472 * @returns FALSE if word is not in the dictionary
476 aspell_check (const char *word
, const int word_size
)
480 if (word
!= NULL
&& global_speller
!= NULL
&& global_speller
->speller
!= NULL
)
481 res
= mc_aspell_speller_check (global_speller
->speller
, word
, word_size
);
486 /* --------------------------------------------------------------------------------------------- */
488 * Examine dictionaries and suggest possible words that may repalce the incorrect word.
490 * @param suggest array of words to iterate through
491 * @param word Word for spell check
492 * @param word_size Word size (in bytes)
493 * @returns count of suggests for the word
497 aspell_suggest (GArray
* suggest
, const char *word
, const int word_size
)
499 unsigned int size
= 0;
501 if (word
!= NULL
&& global_speller
!= NULL
&& global_speller
->speller
!= NULL
)
503 const AspellWordList
*wordlist
;
505 wordlist
= mc_aspell_speller_suggest (global_speller
->speller
, word
, word_size
);
506 if (wordlist
!= NULL
)
508 AspellStringEnumeration
*elements
= NULL
;
511 elements
= mc_aspell_word_list_elements (wordlist
);
512 size
= mc_aspell_word_list_size (wordlist
);
514 for (i
= 0; i
< size
; i
++)
516 const char *cur_sugg_word
;
518 cur_sugg_word
= g_strdup (mc_aspell_string_enumeration_next (elements
));
519 if (cur_sugg_word
!= NULL
)
520 g_array_append_val (suggest
, cur_sugg_word
);
523 mc_delete_aspell_string_enumeration (elements
);
530 /* --------------------------------------------------------------------------------------------- */
532 * Add word to personal dictionary.
534 * @param word Word for spell check
535 * @param word_size Word size (in bytes)
536 * @returns FALSE or error
539 aspell_add_to_dict (const char *word
, int word_size
)
541 mc_aspell_speller_add_to_personal (global_speller
->speller
, word
, word_size
);
543 if (mc_aspell_speller_error (global_speller
->speller
) != 0)
545 edit_error_dialog (_("Error"), mc_aspell_speller_error_message (global_speller
->speller
));
549 mc_aspell_speller_save_all_word_lists (global_speller
->speller
);
551 if (mc_aspell_speller_error (global_speller
->speller
) != 0)
553 edit_error_dialog (_("Error"), mc_aspell_speller_error_message (global_speller
->speller
));
560 /* --------------------------------------------------------------------------------------------- */