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
)
313 res
= mc_aspell_config_replace (global_speller
->config
, "lang", spell_language
);
316 error
= mc_new_aspell_speller (global_speller
->config
);
318 if (mc_aspell_error_number (error
) == 0)
319 global_speller
->speller
= mc_to_aspell_speller (error
);
322 edit_error_dialog (_("Error"), mc_aspell_error_message (error
));
323 mc_delete_aspell_can_have_error (error
);
328 /* --------------------------------------------------------------------------------------------- */
330 * Deinitialization of Aspell support.
336 if (global_speller
== NULL
)
339 if (global_speller
->speller
!= NULL
)
340 mc_delete_aspell_speller (global_speller
->speller
);
342 if (global_speller
->config
!= NULL
)
343 mc_delete_aspell_config (global_speller
->config
);
345 g_free (global_speller
);
346 global_speller
= NULL
;
348 g_module_close (spell_module
);
352 /* --------------------------------------------------------------------------------------------- */
354 * Get array of available languages.
356 * @param lang_list Array of languages. Must be cleared before use
357 * @return language list length
361 aspell_get_lang_list (GArray
* lang_list
)
363 AspellDictInfoList
*dlist
;
364 AspellDictInfoEnumeration
*elem
;
365 const AspellDictInfo
*entry
;
368 if (spell_module
== NULL
)
371 /* the returned pointer should _not_ need to be deleted */
372 dlist
= mc_get_aspell_dict_info_list (global_speller
->config
);
373 elem
= mc_aspell_dict_info_list_elements (dlist
);
375 while ((entry
= mc_aspell_dict_info_enumeration_next (elem
)) != NULL
)
377 if (entry
->name
!= NULL
)
381 tmp
= g_strdup (entry
->name
);
382 g_array_append_val (lang_list
, tmp
);
387 mc_delete_aspell_dict_info_enumeration (elem
);
392 /* --------------------------------------------------------------------------------------------- */
394 * Clear the array of languages.
396 * @param array Array of languages
400 aspell_array_clean (GArray
* array
)
406 for (i
= 0; i
< array
->len
; ++i
)
410 tmp
= g_array_index (array
, char *, i
);
413 g_array_free (array
, TRUE
);
417 /* --------------------------------------------------------------------------------------------- */
419 * Get the current language name.
421 * @return language name
425 aspell_get_lang (void)
429 code
= mc_aspell_config_retrieve (global_speller
->config
, "lang");
430 return spell_decode_lang (code
);
433 /* --------------------------------------------------------------------------------------------- */
437 * @param lang Language name
438 * @return FALSE or error
442 aspell_set_lang (const char *lang
)
447 AspellCanHaveError
*error
;
448 const char *spell_codeset
;
450 g_free (spell_language
);
451 spell_language
= g_strdup (lang
);
454 if (mc_global
.source_codepage
> 0)
455 spell_codeset
= get_codepage_id (mc_global
.source_codepage
);
458 spell_codeset
= str_detect_termencoding ();
460 res
= mc_aspell_config_replace (global_speller
->config
, "lang", lang
);
461 res
= mc_aspell_config_replace (global_speller
->config
, "encoding", spell_codeset
);
463 /* the returned pointer should _not_ need to be deleted */
464 if (global_speller
->speller
!= NULL
)
465 mc_delete_aspell_speller (global_speller
->speller
);
467 global_speller
->speller
= NULL
;
469 error
= mc_new_aspell_speller (global_speller
->config
);
470 if (mc_aspell_error (error
) != 0)
472 mc_delete_aspell_can_have_error (error
);
476 global_speller
->speller
= mc_to_aspell_speller (error
);
481 /* --------------------------------------------------------------------------------------------- */
485 * @param word Word for spell check
486 * @param word_size Word size (in bytes)
487 * @return FALSE if word is not in the dictionary
491 aspell_check (const char *word
, const int word_size
)
495 if (word
!= NULL
&& global_speller
!= NULL
&& global_speller
->speller
!= NULL
)
496 res
= mc_aspell_speller_check (global_speller
->speller
, word
, word_size
);
501 /* --------------------------------------------------------------------------------------------- */
503 * Examine dictionaries and suggest possible words that may repalce the incorrect word.
505 * @param suggest array of words to iterate through
506 * @param word Word for spell check
507 * @param word_size Word size (in bytes)
508 * @return count of suggests for the word
512 aspell_suggest (GArray
* suggest
, const char *word
, const int word_size
)
514 unsigned int size
= 0;
516 if (word
!= NULL
&& global_speller
!= NULL
&& global_speller
->speller
!= NULL
)
518 const AspellWordList
*wordlist
;
520 wordlist
= mc_aspell_speller_suggest (global_speller
->speller
, word
, word_size
);
521 if (wordlist
!= NULL
)
523 AspellStringEnumeration
*elements
= NULL
;
526 elements
= mc_aspell_word_list_elements (wordlist
);
527 size
= mc_aspell_word_list_size (wordlist
);
529 for (i
= 0; i
< size
; i
++)
531 const char *cur_sugg_word
;
533 cur_sugg_word
= g_strdup (mc_aspell_string_enumeration_next (elements
));
534 if (cur_sugg_word
!= NULL
)
535 g_array_append_val (suggest
, cur_sugg_word
);
538 mc_delete_aspell_string_enumeration (elements
);
545 /* --------------------------------------------------------------------------------------------- */
547 * Add word to personal dictionary.
549 * @param word Word for spell check
550 * @param word_size Word size (in bytes)
551 * @return FALSE or error
554 aspell_add_to_dict (const char *word
, int word_size
)
556 mc_aspell_speller_add_to_personal (global_speller
->speller
, word
, word_size
);
558 if (mc_aspell_speller_error (global_speller
->speller
) != 0)
560 edit_error_dialog (_("Error"), mc_aspell_speller_error_message (global_speller
->speller
));
564 mc_aspell_speller_save_all_word_lists (global_speller
->speller
);
566 if (mc_aspell_speller_error (global_speller
->speller
) != 0)
568 edit_error_dialog (_("Error"), mc_aspell_speller_error_message (global_speller
->speller
));
575 /* --------------------------------------------------------------------------------------------- */