diff options
author | Reuben Thomas <rrt@sc3d.org> | 2017-03-03 13:44:20 +0000 |
---|---|---|
committer | Reuben Thomas <rrt@sc3d.org> | 2017-03-03 14:31:14 +0000 |
commit | f3ea75348680074ef982808a6c301fecfdbd1518 (patch) | |
tree | 9815c8c55ddf73b0fc209508963bd6897db33110 /providers | |
parent | 6ce0987cef5af3d32f2ca7d8c35e4da3bbaf7b9c (diff) | |
download | enchant-f3ea75348680074ef982808a6c301fecfdbd1518.tar.gz |
Simplify code layout: move providers into a single directory
Move READMEs from individual providers into comments at the top of the
relevant source file.
Diffstat (limited to 'providers')
-rw-r--r-- | providers/AppleSpell.config | 13 | ||||
-rw-r--r-- | providers/Makefile.am | 58 | ||||
-rw-r--r-- | providers/applespell_checker.h | 49 | ||||
-rw-r--r-- | providers/applespell_checker.mm | 450 | ||||
-rw-r--r-- | providers/aspell_provider.c | 282 | ||||
-rw-r--r-- | providers/hspell_provider.c | 296 | ||||
-rw-r--r-- | providers/hunspell_checker.cpp | 551 | ||||
-rw-r--r-- | providers/libenchant_hunspell.rc | 37 | ||||
-rw-r--r-- | providers/uspell_provider.cpp | 455 | ||||
-rw-r--r-- | providers/voikko_provider.c | 197 | ||||
-rw-r--r-- | providers/zemberek.cpp | 121 | ||||
-rw-r--r-- | providers/zemberek.h | 51 | ||||
-rw-r--r-- | providers/zemberek_provider.cpp | 158 |
13 files changed, 2718 insertions, 0 deletions
diff --git a/providers/AppleSpell.config b/providers/AppleSpell.config new file mode 100644 index 0000000..92933b3 --- /dev/null +++ b/providers/AppleSpell.config @@ -0,0 +1,13 @@ +de_DE de Deutsch +en_US en English +en_AU en_AU Australian English +en_CA en_CA Canadian English +en_GB en_GB British English +es_ES es Español +fr_FR fr Français +it_IT it Italiano +nl_NL nl Nederlands +pt_PT pt Português +pt_BR pt_BR Português do Brasil +sv_SE sv Svenska +hu_HU hu Magyar (MySpellX) diff --git a/providers/Makefile.am b/providers/Makefile.am new file mode 100644 index 0000000..f241e0e --- /dev/null +++ b/providers/Makefile.am @@ -0,0 +1,58 @@ +# FIXME: Build and test AppleSpell back-end +EXTRA_DIST = \ + applespell_checker.h \ + applespell_checker.mm \ + AppleSpell.config \ + libenchant_hunspell.rc + +provider_LTLIBRARIES = +providerdir = $(pkglibdir) + +# FIXME: WARN_C/CXXFLAGS should be set once, per language +AM_CPPFLAGS = -I$(top_srcdir) $(ISYSTEM)$(top_builddir)/lib $(ISYSTEM)$(top_srcdir)/lib -I$(top_srcdir)/src $(ENCHANT_CFLAGS) -D_ENCHANT_BUILD=1 +AM_LDFLAGS = -module -avoid-version -no-undefined + +if WITH_ASPELL +provider_LTLIBRARIES += libenchant_aspell.la +endif +libenchant_aspell_la_CPPFLAGS = $(AM_CPPFLAGS) $(WARN_CFLAGS) +libenchant_aspell_la_LIBADD = $(ENCHANT_LIBS) $(ASPELL_LIBS) $(top_builddir)/src/libenchant.la +libenchant_aspell_la_SOURCES = aspell_provider.c + +if WITH_HSPELL +provider_LTLIBRARIES += libenchant_hspell.la +endif +libenchant_hspell_la_CPPFLAGS = $(AM_CPPFLAGS) $(WARN_CFLAGS) +libenchant_hspell_la_LIBADD = $(ENCHANT_LIBS) $(HSPELL_LIBS) $(top_builddir)/src/libenchant.la +libenchant_hspell_la_SOURCES = hspell_provider.c + +if WITH_HUNSPELL +provider_LTLIBRARIES += libenchant_hunspell.la +endif +libenchant_hunspell_la_CPPFLAGS = $(AM_CPPFLAGS) $(WARN_CXXFLAGS) $(HUNSPELL_CFLAGS) +libenchant_hunspell_la_LIBADD = $(ENCHANT_LIBS) $(HUNSPELL_LIBS) $(top_builddir)/src/libenchant.la +libenchant_hunspell_la_SOURCES = hunspell_checker.cpp + +if WITH_USPELL +provider_LTLIBRARIES += libenchant_uspell.la +endif +libenchant_uspell_la_CPPFLAGS = $(AM_CPPFLAGS) $(WARN_CXXFLAGS) $(USPELL_CFLAGS) +libenchant_uspell_la_LIBADD = $(ENCHANT_LIBS) $(USPELL_LIBS) $(top_builddir)/src/libenchant.la +libenchant_uspell_la_SOURCES = uspell_provider.cpp + +if WITH_VOIKKO +provider_LTLIBRARIES += libenchant_voikko.la +endif +libenchant_voikko_la_CPPFLAGS = $(AM_CPPFLAGS) $(WARN_CFLAGS) $(VOIKKO_CFLAGS) +libenchant_voikko_la_LIBADD = $(ENCHANT_LIBS) $(VOIKKO_LIBS) $(top_builddir)/src/libenchant.la +libenchant_voikko_la_SOURCES = voikko_provider.c + +if WITH_ZEMBEREK +provider_LTLIBRARIES += libenchant_zemberek.la +endif +libenchant_zemberek_la_CPPFLAGS = $(AM_CPPFLAGS) $(WARN_CXXFLAGS) $(ZEMBEREK_CFLAGS) +libenchant_zemberek_la_LIBADD = $(ENCHANT_LIBS) $(ZEMBEREK_LIBS) $(top_builddir)/src/libenchant.la +libenchant_zemberek_la_SOURCES =\ + zemberek.cpp \ + zemberek.h \ + zemberek_provider.cpp diff --git a/providers/applespell_checker.h b/providers/applespell_checker.h new file mode 100644 index 0000000..98dbdf7 --- /dev/null +++ b/providers/applespell_checker.h @@ -0,0 +1,49 @@ +/* enchant + * Copyright (C) 2004 Remi Payette + * Copyright (C) 2004 Francis James Franklin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02110-1301, USA. + */ + +#import <Cocoa/Cocoa.h> + +#include "enchant-provider.h" + +class AppleSpellChecker +{ + public: + AppleSpellChecker(); + + ~AppleSpellChecker(); + + void parseConfigFile (const char * configFile); + + bool checkWord (const char * word, size_t len, NSString * lang); + char ** suggestWord (const char * const word, size_t len, size_t * nsug, NSString * lang); + + NSString * requestDictionary (const char * const code); + private: + NSString * dictionaryForCode (NSString * code); + + NSSpellChecker * m_checker; + NSMutableDictionary * m_languages; +}; + +typedef struct +{ + AppleSpellChecker * AppleSpell; + NSString * DictionaryName; +} AppleSpellDictionary; diff --git a/providers/applespell_checker.mm b/providers/applespell_checker.mm new file mode 100644 index 0000000..67688a4 --- /dev/null +++ b/providers/applespell_checker.mm @@ -0,0 +1,450 @@ +// FIXME: Use @autoreleasepool +/* enchant + * Copyright (C) 2004 Remi Payette + * Copyright (C) 2004 Francis James Franklin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02110-1301, USA. + */ + +#include <glib.h> +#include <gmodule.h> + +#include "applespell_checker.h" + +AppleSpellChecker::AppleSpellChecker() +{ + // NSLog (@"AppleSpellChecker::AppleSpellChecker"); + + m_checker = [NSSpellChecker sharedSpellChecker]; + + m_languages = [[NSMutableDictionary alloc] initWithCapacity:16]; +} + +AppleSpellChecker::~AppleSpellChecker() +{ + // NSLog (@"AppleSpellChecker::~AppleSpellChecker"); + + if (m_languages) + { + [m_languages release]; + m_languages = 0; + } +} + +void AppleSpellChecker::parseConfigFile (const char * configFile) +{ + if (!m_languages || !configFile) + return; + + // NSLog (@"AppleSpellChecker::parseConfigFile: file=\"%s\"", configFile); + + if (FILE * in = fopen (configFile, "r")) + { + char line[1024]; + char code[1024]; + char name[1024]; + char lang[1024]; + + while (fgets (line, sizeof(line), in)) + if (sscanf (line, "%s %s %s", code, name, lang) == 3) + { + NSString * key = [[NSString alloc] initWithUTF8String:code]; + NSString * value = [[NSString alloc] initWithUTF8String:name]; + NSString * language = [[NSString alloc] initWithUTF8String:lang]; + + if (key && value) + { + // NSLog (@"AppleSpellChecker: %@ -> %@ (%@)", key, value, language); + [m_languages setObject:value forKey:key]; + } + + if (key) + [key release]; + if (value) + [value release]; + if (language) + [language release]; + } + fclose (in); + } +} + +NSString * AppleSpellChecker::dictionaryForCode (NSString * code) +{ + if (!m_languages) + return 0; + + return [m_languages objectForKey:code]; +} + +bool AppleSpellChecker::checkWord (const char * word, size_t len, NSString * lang) +{ + // NSLog(@"AppleSpellChecker::checkWord: lang=\"%@\"", lang); + + if (!m_checker || !lang) + return false; + + NSString * str = [[NSString alloc] initWithBytes:word length:len encoding:NSUTF8StringEncoding]; + if (!str) + return false; + + // NSLog (@"AppleSpellChecker::checkWord: word=\"%@\"", str); + + [m_checker setLanguage:lang]; + + NSRange result = [m_checker checkSpellingOfString:str startingAt:0]; + + [str release]; + + return (result.length ? true : false); +} + +char ** AppleSpellChecker::suggestWord (const char * const word, size_t len, size_t * nsug, NSString * lang) +{ + // NSLog (@"AppleSpellChecker::suggestWord: lang=\"%@\"", lang); + + if (!m_checker || !word || !len || !nsug || !lang) + return 0; + + *nsug = 0; + + [m_checker setLanguage:lang]; + + NSString * str = [[NSString alloc] initWithBytes:word length:len encoding:NSUTF8StringEncoding]; + if (!str) + return 0; + + // NSLog (@"AppleSpellChecker::suggestWord: word=\"%@\"", str); + + NSArray * result = [m_checker guessesForWord:str]; + + [str release]; + + char ** sug = 0; + + if (unsigned int count = [result count]) + { + sug = g_new0 (char *, static_cast<size_t>(count) + 1); + if (sug) + { + for (unsigned int i = 0; i < count; i++) + { + str = [result objectAtIndex:i]; + + sug[*nsug] = g_strdup ([str UTF8String]); + + if (sug[*nsug]) + *nsug = *nsug + 1; + } + } + } + return sug; +} + +NSString * AppleSpellChecker::requestDictionary (const char * const code) +{ + // NSLog (@"AppleSpellChecker::requestDictionary: code=\"%s\"", code); + + if (!m_checker || !code) + return 0; + + NSString * dictionary = dictionaryForCode ([NSString stringWithUTF8String:code]); + if (dictionary) + { + NSString * language = [m_checker language]; + // NSLog (@"AppleSpellChecker::requestDictionary: ld language=\"%@\", new language=\"%@\"", language, dictionary); + if (![m_checker setLanguage:dictionary]) + { + // NSLog (@"AppleSpellChecker::requestDictionary: failed to set new language!"); + dictionary = 0; + } + if (language) + [m_checker setLanguage:language]; + } + return dictionary; +} + +/* + * Enchant + */ + +static char ** appleSpell_dict_suggest (EnchantDict * me, const char * const word, size_t len, size_t * out_n_suggs) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"appleSpell_dict_suggest word=\"%s\"", word); + + if (!me || !word || !len || !out_n_suggs) + { + if (pool) [pool release]; + return 0; + } + + char ** result = 0; + + if (AppleSpellDictionary * ASD = static_cast<AppleSpellDictionary *>(me->user_data)) + { + result = ASD->AppleSpell->suggestWord (word, len, out_n_suggs, ASD->DictionaryName); + } + + if (pool) [pool release]; + return result; +} + +static int appleSpell_dict_check (EnchantDict * me, const char * const word, size_t len) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"appleSpell_dict_check"); + + if (!me || !word || !len) + { + if (pool) [pool release]; + return 0; + } + + int result = 0; + + if (AppleSpellDictionary * ASD = static_cast<AppleSpellDictionary *>(me->user_data)) + { + result = ASD->AppleSpell->checkWord (word, len, ASD->DictionaryName); + } + + if (pool) [pool release]; + return result; +} + +static EnchantDict * appleSpell_provider_request_dict (EnchantProvider * me, const char * const tag) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"appleSpell_provider_request_dict"); + + if (!me || !tag) + { + if (pool) [pool release]; + return 0; + } + + AppleSpellChecker * checker = static_cast<AppleSpellChecker *>(me->user_data); + if (!checker) + { + if (pool) [pool release]; + return 0; + } + + EnchantDict * dict = g_new0 (EnchantDict, 1); + if (!dict) + { + if (pool) [pool release]; + return 0; + } + + dict->check = appleSpell_dict_check; + dict->suggest = appleSpell_dict_suggest; + + AppleSpellDictionary * ASD = g_new0 (AppleSpellDictionary, 1); + if (!ASD) + { + g_free (dict); + if (pool) [pool release]; + return 0; + } + + ASD->AppleSpell = checker; + ASD->DictionaryName = checker->requestDictionary (tag); + + if (ASD->DictionaryName) + { + [ASD->DictionaryName retain]; + // NSLog (@"appleSpell_provider_request_dict: providing dictionary \"%@\"", ASD->DictionaryName); + dict->user_data = (void *) ASD; + } + else + { + g_free (ASD); + g_free (dict); + dict = 0; + } + + if (pool) [pool release]; + return dict; +} + +static void appleSpell_provider_dispose_dict (EnchantProvider * me, EnchantDict * dict) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"appleSpell_provider_dispose_dict"); + + if (dict) + { + AppleSpellDictionary * ASD = static_cast<AppleSpellDictionary *>(dict->user_data); + if (ASD) + { + [ASD->DictionaryName release]; + g_free (ASD); + } + g_free (dict); + } + if (pool) [pool release]; +} + +static int appleSpell_provider_dictionary_exists (EnchantProvider * me, const char * const tag) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"appleSpell_provider_dictionary_exists: tag=\"%s\"", tag); + + int result = 0; + + AppleSpellChecker * checker = static_cast<AppleSpellChecker *>(me->user_data); + if (checker) + result = (checker->requestDictionary (tag) ? 1 : 0); + + if (pool) [pool release]; + return result; +} + +static void appleSpell_provider_dispose (EnchantProvider * me) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"appleSpell_provider_dispose"); + + if (me) + { + AppleSpellChecker * checker = static_cast<AppleSpellChecker *>(me->user_data); + if (checker) + delete checker; + + g_free (me); + } + if (pool) [pool release]; +} + +static const char * appleSpell_provider_identify (EnchantProvider * me) +{ + return "AppleSpell"; +} + +static const char * appleSpell_provider_describe (EnchantProvider * me) +{ + return "AppleSpell Provider"; +} + +static void appleSpell_provider_free_string_list (EnchantProvider * me, char **str_list) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"appleSpell_provider_free_suggestions"); + + if (str_list) + g_strfreev (str_list); + + if (pool) [pool release]; +} + +extern "C" { + ENCHANT_MODULE_EXPORT (EnchantProvider *) + init_enchant_provider (void) + { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"init_enchant_provider"); + + EnchantProvider * provider = g_new0 (EnchantProvider, 1); + if (!provider) + { + if (pool) [pool release]; + return 0; + } + + provider->dispose = appleSpell_provider_dispose; + provider->request_dict = appleSpell_provider_request_dict; + provider->dispose_dict = appleSpell_provider_dispose_dict; + provider->dictionary_exists = appleSpell_provider_dictionary_exists; + provider->identify = appleSpell_provider_identify; + provider->describe = appleSpell_provider_describe; + provider->free_string_list = appleSpell_provider_free_string_list; + + AppleSpellChecker * checker = 0; + try + { + checker = new AppleSpellChecker; + } + catch (...) + { + checker = 0; + } + if (checker) + { + provider->user_data = (void *) checker; + } + else + { + g_free (provider); + provider = 0; + } + + if (pool) [pool release]; + return provider; + } + + static bool s_bReloadSelf = true; + + ENCHANT_MODULE_EXPORT (void) + configure_enchant_provider (EnchantProvider * me, const char * module_dir) + { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // NSLog (@"configure_enchant_provider"); + + if (!me || !module_dir) + { + if (pool) [pool release]; + return; + } + + AppleSpellChecker * checker = static_cast<AppleSpellChecker *>(me->user_data); + if (checker) + { + if (s_bReloadSelf) + if (gchar * moduleFile = g_build_filename (module_dir, "AppleSpell.so", NULL)) + { + /* ugly hack :-( + * Darwin linker doesn't like unloading Obj-C modules; + * reload once to suppress unloading... + */ + g_module_open (moduleFile, (GModuleFlags) 0); + + g_free (moduleFile); + + s_bReloadSelf = false; + } + + if (gchar * configFile = g_build_filename (module_dir, "AppleSpell.config", NULL)) + { + checker->parseConfigFile (configFile); + + g_free (configFile); + } + } + + if (pool) [pool release]; + return; + } +} diff --git a/providers/aspell_provider.c b/providers/aspell_provider.c new file mode 100644 index 0000000..1838857 --- /dev/null +++ b/providers/aspell_provider.c @@ -0,0 +1,282 @@ +/* enchant + * Copyright (C) 2003,2004 Dom Lachowicz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +/* + * This is the GNU Aspell Enchant Backend. + * GNU Aspell is by Kevin Atkinson. See http://aspell.net/ + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <aspell.h> + +#include "enchant.h" +#include "enchant-provider.h" +#include "unused-parameter.h" + + +ENCHANT_MODULE_EXPORT(void) + configure_enchant_provider(EnchantProvider * me, const char *dir_name); + +ENCHANT_MODULE_EXPORT (EnchantProvider *) + init_enchant_provider (void); + +static int +aspell_dict_check (EnchantDict * me, const char *const word, size_t len) +{ + AspellSpeller *manager; + int val; + char *normalizedWord; + + manager = (AspellSpeller *) me->user_data; + + normalizedWord = g_utf8_normalize (word, len, G_NORMALIZE_NFC); + val = aspell_speller_check (manager, normalizedWord, strlen(normalizedWord)); + g_free(normalizedWord); + + if (val == 0) + return 1; + else if (val > 0) + return 0; + else { + enchant_dict_set_error (me, aspell_speller_error_message (manager)); + return -1; + } +} + +static char ** +aspell_dict_suggest (EnchantDict * me, const char *const word, + size_t len, size_t * out_n_suggs) +{ + AspellSpeller *manager; + + const AspellWordList *word_list; + AspellStringEnumeration *suggestions; + char *normalizedWord; + + char **sugg_arr = NULL; + size_t n_suggestions, i; + const char *sugg; + + manager = (AspellSpeller *) me->user_data; + + normalizedWord = g_utf8_normalize (word, len, G_NORMALIZE_NFC); + word_list = aspell_speller_suggest (manager, normalizedWord, strlen(normalizedWord)); + g_free(normalizedWord); + + if (word_list) + { + suggestions = aspell_word_list_elements (word_list); + if (suggestions) + { + n_suggestions = aspell_word_list_size (word_list); + *out_n_suggs = n_suggestions; + + if (n_suggestions) + { + sugg_arr = g_new0 (char *, n_suggestions + 1); + + for (i = 0; i < n_suggestions; i++) + { + sugg = aspell_string_enumeration_next (suggestions); + if (sugg) + sugg_arr[i] = g_strdup (sugg); + } + } + delete_aspell_string_enumeration (suggestions); + } + } + + return sugg_arr; +} + +static void +aspell_dict_add_to_personal (EnchantDict * me, + const char *const word, size_t len) +{ + AspellSpeller *manager; + + manager = (AspellSpeller *) me->user_data; + aspell_speller_add_to_personal (manager, word, len); + aspell_speller_save_all_word_lists (manager); +} + +static void +aspell_dict_add_to_session (EnchantDict * me, + const char *const word, size_t len) +{ + AspellSpeller *manager; + + manager = (AspellSpeller *) me->user_data; + aspell_speller_add_to_session (manager, word, len); +} + +static void +aspell_dict_store_replacement (EnchantDict * me, + const char *const mis, size_t mis_len, + const char *const cor, size_t cor_len) +{ + AspellSpeller *manager; + + manager = (AspellSpeller *) me->user_data; + aspell_speller_store_replacement (manager, mis, mis_len, + cor, cor_len); + aspell_speller_save_all_word_lists (manager); +} + +static EnchantDict * +aspell_provider_request_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, const char *const tag) +{ + EnchantDict *dict; + AspellSpeller *manager; + AspellConfig *spell_config; + AspellCanHaveError *spell_error; + + spell_config = new_aspell_config (); + aspell_config_replace (spell_config, "language-tag", tag); + aspell_config_replace (spell_config, "encoding", "utf-8"); + + spell_error = new_aspell_speller (spell_config); + delete_aspell_config (spell_config); + + if (aspell_error_number (spell_error) != 0) + { + return NULL; + } + + manager = to_aspell_speller (spell_error); + + dict = g_new0 (EnchantDict, 1); + dict->user_data = (void *) manager; + dict->check = aspell_dict_check; + dict->suggest = aspell_dict_suggest; + dict->add_to_personal = aspell_dict_add_to_personal; + dict->add_to_session = aspell_dict_add_to_session; + dict->store_replacement = aspell_dict_store_replacement; + + return dict; +} + +static void +aspell_provider_dispose_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, EnchantDict * dict) +{ + AspellSpeller *manager; + + manager = (AspellSpeller *) dict->user_data; + delete_aspell_speller (manager); + + g_free (dict); +} + +static char ** +aspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER, + size_t * out_n_dicts) +{ + AspellConfig * spell_config; + AspellDictInfoList * dlist; + AspellDictInfoEnumeration * dels; + const AspellDictInfo * entry; + char ** out_list = NULL; + + spell_config = new_aspell_config (); + + dlist = get_aspell_dict_info_list (spell_config); + + *out_n_dicts = 0; + dels = aspell_dict_info_list_elements (dlist); + + /* TODO: Use aspell_dict_info_list_size() once it is implemented and returns non-zero. */ + while ( (entry = aspell_dict_info_enumeration_next(dels)) != 0) + (*out_n_dicts)++; + + if (*out_n_dicts) { + size_t i; + + out_list = g_new0 (char *, *out_n_dicts + 1); + dels = aspell_dict_info_list_elements (dlist); + + for (i = 0; i < *out_n_dicts; i++) { + entry = aspell_dict_info_enumeration_next (dels); + /* XXX: should this be entry->code or entry->name ? */ + out_list[i] = g_strdup (entry->code); + } + + delete_aspell_dict_info_enumeration (dels); + } + + delete_aspell_config (spell_config); + + return out_list; +} + +static void +aspell_provider_free_string_list (EnchantProvider * me _GL_UNUSED_PARAMETER, char **str_list) +{ + g_strfreev (str_list); +} + +static void +aspell_provider_dispose (EnchantProvider * me) +{ + g_free (me); +} + +static const char * +aspell_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "aspell"; +} + +static const char * +aspell_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "Aspell Provider"; +} + +EnchantProvider * +init_enchant_provider (void) +{ + EnchantProvider *provider; + + provider = g_new0 (EnchantProvider, 1); + provider->dispose = aspell_provider_dispose; + provider->request_dict = aspell_provider_request_dict; + provider->dispose_dict = aspell_provider_dispose_dict; + provider->identify = aspell_provider_identify; + provider->describe = aspell_provider_describe; + provider->list_dicts = aspell_provider_list_dicts; + provider->free_string_list = aspell_provider_free_string_list; + + return provider; +} diff --git a/providers/hspell_provider.c b/providers/hspell_provider.c new file mode 100644 index 0000000..d1ee395 --- /dev/null +++ b/providers/hspell_provider.c @@ -0,0 +1,296 @@ +/* enchant + * Copyright (C) 2003 Yaacov Zamir + * Copyright (C) 2004 Dom Lachowicz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz and Yaacov Zamir + * give permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +/* + * Hspell was written by Nadav Har'El and Dan Kenigsberg. + * See: http://www.ivrix.org.il/projects/spell-checker/ + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <hspell.h> + +#include "enchant.h" +#include "enchant-provider.h" +#include "unused-parameter.h" + +/** + * hspell helper functions + */ + +/** + * is hebrew + * return TRUE if iso hebrew ( must be null terminated ) + */ +static int is_hebrew (const char *const iso_word, gsize len) +{ + gsize i; + + for ( i = 0; (i < len) && (iso_word[i]); i++ ) + { + /* if not a hebrew alphabet or " ` ' using iso-8859-8 encoding */ + if ( (iso_word[i] < (char)224 || iso_word[i] > (char)250 ) && /* alef to tav */ + (iso_word[i] < (char)146 || iso_word[i] > (char)148 ) && /* ` etc... */ + ( iso_word[i] !=(char)34 ) && /* " */ + ( iso_word[i] !=(char)39 ) ) /* ' */ + return FALSE; + } + + return TRUE; +} + +/** + * convert struct corlist to **char + * the **char must be g_freed + */ +static gchar ** +corlist2strv (struct corlist *cl, size_t nb_sugg) +{ + size_t i; + gsize len; + char **sugg_arr = NULL; + const char *sugg; + + if (nb_sugg > 0) + { + sugg_arr = g_new0 (char *, nb_sugg + 1); + for (i = 0; i < nb_sugg; i++) + { + sugg = corlist_str (cl, i); + if (sugg) + sugg_arr[i] = g_convert (sugg, + strlen (sugg), + "utf-8", "iso8859-8", NULL, &len, NULL); + } + } + + return sugg_arr; +} + +/** + * end of helper functions + */ + +static int +hspell_dict_check (EnchantDict * me, const char *const word, size_t len) +{ + int res; + char *iso_word; + gsize length; + int preflen; + struct dict_radix *hspell_dict; + + hspell_dict = (struct dict_radix *)me->user_data; + + /* convert to iso 8859-8 */ + iso_word = g_convert (word, len, "iso8859-8", "utf-8", NULL, &length, NULL); + + /* check if hebrew ( if not hebrew give it the benefit of a doubt ) */ + if (iso_word == NULL || !is_hebrew (iso_word, length)) + { + g_free (iso_word); + return FALSE; + } + + /* check */ + res = hspell_check_word (hspell_dict, iso_word, &preflen); + + /* if not correct try gimatria */ + if (res != 1) + { + res = hspell_is_canonic_gimatria (iso_word); + if (res != 0) + res = 1; + } + + /* free the word */ + g_free (iso_word); + + return (res != 1); +} + +static char ** +hspell_dict_suggest (EnchantDict * me, const char *const word, + size_t len, size_t * out_n_suggs) +{ + gsize length; + char *iso_word; + char **sugg_arr = NULL; + struct corlist cl; + struct dict_radix *hspell_dict; + + hspell_dict = (struct dict_radix *)me->user_data; + + /* convert to iso 8859-8 */ + iso_word = g_convert (word, len, "iso8859-8", "utf-8", NULL, &length, NULL); + + /* check if hebrew ( if not hebrew cant do anything ) */ + if (iso_word == NULL || !is_hebrew (iso_word, length)) + { + g_free (iso_word); + return NULL; + } + + /* get suggestions */ + corlist_init (&cl); + hspell_trycorrect (hspell_dict, iso_word, &cl); + + /* set size of list */ + *out_n_suggs = corlist_n (&cl); + + /* convert suggestion list to strv list */ + sugg_arr = corlist2strv (&cl, *out_n_suggs); + + /* free the list */ + corlist_free (&cl); + + /* free the word */ + g_free (iso_word); + + return sugg_arr; +} + +static EnchantDict * +hspell_provider_request_dict (EnchantProvider * me, const char *const tag) +{ + EnchantDict *dict; + int dict_flag = 0; + struct dict_radix *hspell_dict = NULL; + + if(!((strlen(tag) >= 2) && tag[0] == 'h' && tag[1] == 'e')) + return NULL; + + /* try to set a new session */ + dict_flag = hspell_init (&hspell_dict, HSPELL_OPT_DEFAULT); + + if (dict_flag != 0 || !hspell_dict) + { + enchant_provider_set_error (me, "can't create new dict."); + return NULL; + } + + dict = g_new0 (EnchantDict, 1); + dict->user_data = (void *) hspell_dict; + dict->check = hspell_dict_check; + dict->suggest = hspell_dict_suggest; + + return dict; +} + +static void +hspell_provider_dispose_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, EnchantDict * dict) +{ + struct dict_radix *hspell_dict; + + hspell_dict = (struct dict_radix *)dict->user_data; + hspell_uninit (hspell_dict); + g_free (dict); +} + +/* test for the existence of, then return $prefix/share/hspell/hebrew.wgz */ + +static char ** +hspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER, + size_t * out_n_dicts) +{ + const char * dictionary_path; + char ** out_list = NULL; + *out_n_dicts = 0; + + dictionary_path = hspell_get_dictionary_path(); + + if(dictionary_path && *dictionary_path && g_file_test (dictionary_path, G_FILE_TEST_EXISTS)) { + *out_n_dicts = 1; + + out_list = g_new0 (char *, 2); + + out_list[0] = g_strdup ("he"); + } + + return out_list; +} + +static int +hspell_provider_dictionary_exists (struct str_enchant_provider * me, + const char *const tag) +{ + (void)me; + return (!strcmp ("he", tag) || !strcmp ("he_IL", tag)); +} + +static void +hspell_provider_free_string_list (EnchantProvider * me _GL_UNUSED_PARAMETER, char **str_list) +{ + g_strfreev (str_list); +} + +static void +hspell_provider_dispose (EnchantProvider * me) +{ + g_free (me); +} + +static const char * +hspell_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "hspell"; +} + +static const char * +hspell_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "Hspell Provider"; +} + +ENCHANT_MODULE_EXPORT (EnchantProvider *) + init_enchant_provider (void); + +EnchantProvider * +init_enchant_provider (void) +{ + EnchantProvider *provider; + + provider = g_new0 (EnchantProvider, 1); + provider->dispose = hspell_provider_dispose; + provider->request_dict = hspell_provider_request_dict; + provider->dispose_dict = hspell_provider_dispose_dict; + provider->dictionary_exists = hspell_provider_dictionary_exists; + provider->identify = hspell_provider_identify; + provider->describe = hspell_provider_describe; + provider->list_dicts = hspell_provider_list_dicts; + provider->free_string_list = hspell_provider_free_string_list; + + return provider; +} diff --git a/providers/hunspell_checker.cpp b/providers/hunspell_checker.cpp new file mode 100644 index 0000000..5a77f00 --- /dev/null +++ b/providers/hunspell_checker.cpp @@ -0,0 +1,551 @@ +/* enchant + * Copyright (C) 2003-2004 Joan Moratinos <jmo@softcatala.org>, Dom Lachowicz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +/* + * This is the Hunspell Enchant Backend. + * Hunspell is by László Németh. See: http://hunspell.github.io/ + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <string> +#include <vector> + +#include "enchant.h" +#include "enchant-provider.h" +#include "unused-parameter.h" + +#include <hunspell/hunspell.hxx> + +/* Some versions of hunspell (1.4.x) don't have this defined. */ +/* This is the defined value at that point */ +#ifndef MAXWORDLEN +#define MAXWORDLEN 176 +#endif + +#include <glib.h> + +/***************************************************************************/ + +class HunspellChecker +{ +public: + HunspellChecker(); + ~HunspellChecker(); + + bool checkWord (const char *word, size_t len); + char **suggestWord (const char* const word, size_t len, size_t *out_n_suggs); + + bool requestDictionary (const char * szLang); + +private: + GIConv m_translate_in; /* Selected translation from/to Unicode */ + GIConv m_translate_out; + Hunspell *hunspell; +}; + +/***************************************************************************/ + +static bool +g_iconv_is_valid(GIConv i) +{ + return (i != nullptr); +} + +HunspellChecker::HunspellChecker() +: m_translate_in(nullptr), m_translate_out(nullptr), hunspell(nullptr) +{ +} + +HunspellChecker::~HunspellChecker() +{ + delete hunspell; + if (g_iconv_is_valid (m_translate_in)) + g_iconv_close(m_translate_in); + if (g_iconv_is_valid(m_translate_out)) + g_iconv_close(m_translate_out); +} + +bool +HunspellChecker::checkWord(const char *utf8Word, size_t len) +{ + if (len > MAXWORDLEN || !g_iconv_is_valid(m_translate_in)) + return false; + + // the 8bit encodings use precomposed forms + char *normalizedWord = g_utf8_normalize (utf8Word, len, G_NORMALIZE_NFC); + char *in = normalizedWord; + char word8[MAXWORDLEN + 1]; + char *out = word8; + size_t len_in = strlen(in); + size_t len_out = sizeof( word8 ) - 1; + size_t result = g_iconv(m_translate_in, &in, &len_in, &out, &len_out); + g_free(normalizedWord); + if (static_cast<size_t>(-1) == result) + return false; + *out = '\0'; + if (hunspell->spell(word8)) + return true; + else + return false; +} + +char** +HunspellChecker::suggestWord(const char* const utf8Word, size_t len, size_t *nsug) +{ + if (len > MAXWORDLEN + || !g_iconv_is_valid(m_translate_in) + || !g_iconv_is_valid(m_translate_out)) + return nullptr; + + // the 8bit encodings use precomposed forms + char *normalizedWord = g_utf8_normalize (utf8Word, len, G_NORMALIZE_NFC); + char *in = normalizedWord; + char word8[MAXWORDLEN + 1]; + char *out = word8; + size_t len_in = strlen(in); + size_t len_out = sizeof(word8) - 1; + size_t result = g_iconv(m_translate_in, &in, &len_in, &out, &len_out); + g_free(normalizedWord); + if (static_cast<size_t>(-1) == result) + return nullptr; + + *out = '\0'; + char **sugMS; + *nsug = hunspell->suggest(&sugMS, word8); + if (*nsug > 0) { + char **sug = g_new0 (char *, *nsug + 1); + for (size_t i=0; i<*nsug; i++) { + in = sugMS[i]; + len_in = strlen(in); + len_out = MAXWORDLEN; + char *word = g_new0(char, len_out + 1); + out = word; + if (static_cast<size_t>(-1) == g_iconv(m_translate_out, &in, &len_in, &out, &len_out)) { + for (size_t j = i; j < *nsug; j++) + free(sugMS[j]); + free(sugMS); + + *nsug = i; + return sug; + } + *(out) = 0; + sug[i] = word; + free(sugMS[i]); + } + free(sugMS); + return sug; + } + else + return nullptr; +} + +static GSList * +hunspell_checker_get_dictionary_dirs () +{ + GSList *dirs = NULL; + + { + GSList *config_dirs, *iter; + + config_dirs = enchant_get_user_config_dirs (); + + for (iter = config_dirs; iter; iter = iter->next) + { + dirs = g_slist_append (dirs, g_build_filename (static_cast<const gchar *>(iter->data), + "hunspell", nullptr)); + } + + g_slist_free_full (config_dirs, free); + } + + { + const gchar* const * system_data_dirs = g_get_system_data_dirs (); + const gchar* const * iter; + + for (iter = system_data_dirs; *iter; iter++) + { + dirs = g_slist_append (dirs, g_build_filename (*iter, "hunspell", "dicts", nullptr)); + } + } + + /* Dynamically locate library and search for modules relative to it. */ + char * enchant_prefix = enchant_get_prefix_dir(); + if(enchant_prefix) + { + char * hunspell_prefix = g_build_filename(enchant_prefix, "share", "enchant", "hunspell", nullptr); + g_free(enchant_prefix); + dirs = g_slist_append (dirs, hunspell_prefix); + } + +#ifdef ENCHANT_HUNSPELL_DICT_DIR + dirs = g_slist_append (dirs, g_strdup (ENCHANT_HUNSPELL_DICT_DIR)); +#endif + + { + const gchar* hun_dir = g_getenv("DICPATH"); + if (hun_dir) + { + dirs = g_slist_append(dirs, strdup(hun_dir)); + } + } + + return dirs; +} + +static void +s_buildDictionaryDirs (std::vector<std::string> & dirs) +{ + GSList *hunspell_dirs, *iter; + + dirs.clear (); + + hunspell_dirs = hunspell_checker_get_dictionary_dirs (); + for (iter = hunspell_dirs; iter; iter = iter->next) + { + dirs.push_back (static_cast<const char *>(iter->data)); + } + + g_slist_free_full (hunspell_dirs, g_free); +} + +static void +s_buildHashNames (std::vector<std::string> & names, const char * dict) +{ + names.clear (); + + std::vector<std::string> dirs; + s_buildDictionaryDirs (dirs); + + char *dict_dic = g_strconcat(dict, ".dic", nullptr); + for (size_t i = 0; i < dirs.size(); i++) + { + char *tmp = g_build_filename (dirs[i].c_str(), dict_dic, nullptr); + names.push_back (tmp); + g_free (tmp); + } + + g_free(dict_dic); +} + +static bool +s_hasCorrespondingAffFile(const std::string & dicFile) +{ + std::string aff = dicFile; + aff.replace(aff.end()-3,aff.end(), "aff"); + return g_file_test(aff.c_str(), G_FILE_TEST_EXISTS) != 0; +} + +static bool is_plausible_dict_for_tag(const char *dir_entry, const char *tag) +{ + const char *dic_suffix = ".dic"; + size_t dic_suffix_len = strlen(dic_suffix); + size_t dir_entry_len = strlen(dir_entry); + size_t tag_len = strlen(tag); + + if (dir_entry_len - dic_suffix_len < tag_len) + return false; + if (strcmp(dir_entry+dir_entry_len-dic_suffix_len, dic_suffix) != 0) + return false; + if (strncmp (dir_entry, tag, tag_len) != 0) + return false; + //e.g. requested dict for "fi", + //reject "fil_PH.dic" + //allow "fi-FOO.dic", "fi_FOO.dic", "fi.dic", etc. + if (!ispunct(dir_entry[tag_len])) + return false; + return true; +} + +static char * +hunspell_request_dictionary (const char * tag) +{ + std::vector<std::string> names; + + s_buildHashNames (names, tag); + + for (size_t i = 0; i < names.size (); i++) { + if (g_file_test(names[i].c_str(), G_FILE_TEST_EXISTS)) { + if(s_hasCorrespondingAffFile(names[i])){ + return strdup (names[i].c_str()); + } + } + } + + std::vector<std::string> dirs; + s_buildDictionaryDirs (dirs); + + for (size_t i = 0; i < dirs.size(); i++) { + GDir *dir = g_dir_open (dirs[i].c_str(), 0, nullptr); + if (dir) { + const char *dir_entry; + while ((dir_entry = g_dir_read_name (dir)) != NULL) { + if (is_plausible_dict_for_tag(dir_entry, tag)) { + char *dict = g_build_filename (dirs[i].c_str(), + dir_entry, nullptr); + if(s_hasCorrespondingAffFile(dict)){ + g_dir_close (dir); + return dict; + } + } + } + + g_dir_close (dir); + } + } + + return NULL; +} + +bool +HunspellChecker::requestDictionary(const char *szLang) +{ + char *dic = NULL, *aff = NULL; + + dic = hunspell_request_dictionary (szLang); + if (!dic) + return false; + + aff = strdup(dic); + int len_dic = strlen(dic); + strcpy(aff+len_dic-3, "aff"); + if (g_file_test(aff, G_FILE_TEST_EXISTS)) + { + hunspell = new Hunspell(aff, dic); + } + free(dic); + free(aff); + if(hunspell == NULL){ + return false; + } + char *enc = hunspell->get_dic_encoding(); + + m_translate_in = g_iconv_open(enc, "UTF-8"); + m_translate_out = g_iconv_open("UTF-8", enc); + + return true; +} + +/* + * Enchant + */ + +static char ** +hunspell_dict_suggest (EnchantDict * me, const char *const word, + size_t len, size_t * out_n_suggs) +{ + HunspellChecker * checker; + + checker = static_cast<HunspellChecker *>(me->user_data); + return checker->suggestWord (word, len, out_n_suggs); +} + +static int +hunspell_dict_check (EnchantDict * me, const char *const word, size_t len) +{ + HunspellChecker * checker; + + checker = static_cast<HunspellChecker *>(me->user_data); + + if (checker->checkWord(word, len)) + return 0; + + return 1; +} + +static void +hunspell_provider_enum_dicts (const char * const directory, + std::vector<std::string> & out_dicts) +{ + GDir * dir = g_dir_open (directory, 0, nullptr); + if (dir) { + const char * entry; + + while ((entry = g_dir_read_name (dir)) != NULL) { + char * utf8_entry = g_filename_to_utf8 (entry, -1, nullptr, nullptr, nullptr); + if (utf8_entry) { + std::string dir_entry (utf8_entry); + g_free (utf8_entry); + + int hit = dir_entry.rfind (".dic"); + if (hit != -1) { + /* don't include hyphenation dictionaries + and require .aff file to be present*/ + if(dir_entry.compare (0, 5, "hyph_") != 0) + { + std::string name(dir_entry.substr (0, hit)); + std::string affFileName(name + ".aff"); + char * aff = g_build_filename(directory, affFileName.c_str(), nullptr); + if (g_file_test(aff, G_FILE_TEST_EXISTS)) + { + out_dicts.push_back (dir_entry.substr (0, hit)); + } + g_free(aff); + } + } + } + } + + g_dir_close (dir); + } +} + +extern "C" { + +ENCHANT_MODULE_EXPORT (EnchantProvider *) + init_enchant_provider (void); + +static char ** +hunspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER, + size_t * out_n_dicts) +{ + std::vector<std::string> dict_dirs, dicts; + char ** dictionary_list = NULL; + + s_buildDictionaryDirs (dict_dirs); + + for (size_t i = 0; i < dict_dirs.size(); i++) + { + hunspell_provider_enum_dicts (dict_dirs[i].c_str(), dicts); + } + + if (dicts.size () > 0) { + dictionary_list = g_new0 (char *, dicts.size() + 1); + + for (size_t i = 0; i < dicts.size(); i++) + dictionary_list[i] = g_strdup (dicts[i].c_str()); + } + + *out_n_dicts = dicts.size (); + return dictionary_list; +} + +static void +hunspell_provider_free_string_list (EnchantProvider * me _GL_UNUSED_PARAMETER, char **str_list) +{ + g_strfreev (str_list); +} + +static EnchantDict * +hunspell_provider_request_dict(EnchantProvider * me _GL_UNUSED_PARAMETER, const char *const tag) +{ + EnchantDict *dict; + HunspellChecker * checker; + + checker = new HunspellChecker(); + + if (!checker) + return NULL; + + if (!checker->requestDictionary(tag)) { + delete checker; + return NULL; + } + + dict = g_new0(EnchantDict, 1); + dict->user_data = (void *) checker; + dict->check = hunspell_dict_check; + dict->suggest = hunspell_dict_suggest; + // don't implement personal, session + + return dict; +} + +static void +hunspell_provider_dispose_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, EnchantDict * dict) +{ + HunspellChecker *checker; + + checker = (HunspellChecker *) dict->user_data; + delete checker; + + g_free (dict); +} + +static int +hunspell_provider_dictionary_exists (struct str_enchant_provider * me _GL_UNUSED_PARAMETER, + const char *const tag) +{ + std::vector <std::string> names; + + s_buildHashNames (names, tag); + for (size_t i = 0; i < names.size(); i++) { + if (g_file_test (names[i].c_str(), G_FILE_TEST_EXISTS)) + { + std::string aff(names[i]); + aff.replace(aff.end() - 3, aff.end(), "aff"); + if (g_file_test(aff.c_str(), G_FILE_TEST_EXISTS)) + return 1; + } + } + + return 0; +} + +static void +hunspell_provider_dispose (EnchantProvider * me) +{ + g_free (me); +} + +static const char * +hunspell_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "hunspell"; +} + +static const char * +hunspell_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "Hunspell Provider"; +} + +EnchantProvider * +init_enchant_provider (void) +{ + EnchantProvider *provider; + + provider = g_new0(EnchantProvider, 1); + provider->dispose = hunspell_provider_dispose; + provider->request_dict = hunspell_provider_request_dict; + provider->dispose_dict = hunspell_provider_dispose_dict; + provider->dictionary_exists = hunspell_provider_dictionary_exists; + provider->identify = hunspell_provider_identify; + provider->describe = hunspell_provider_describe; + provider->free_string_list = hunspell_provider_free_string_list; + provider->list_dicts = hunspell_provider_list_dicts; + + return provider; +} + +} // extern C linkage diff --git a/providers/libenchant_hunspell.rc b/providers/libenchant_hunspell.rc new file mode 100644 index 0000000..d7178bc --- /dev/null +++ b/providers/libenchant_hunspell.rc @@ -0,0 +1,37 @@ +//LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+LANGUAGE 0, 0
+
+10 VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "Libenchant Hunspell module\0"
+ VALUE "FileVersion", "1, 7, 0, 1\0"
+ VALUE "InternalName", "libenchant_hunspell\0"
+ VALUE "LegalCopyright", "Copyright \xA9 2003-2011 Joan Moratinos, Dom Lachowicz et al.\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "libenchant_hunspell.dll\0"
+ VALUE "PrivateBuild", "Dev version\0"
+ VALUE "ProductName", "libenchant\0"
+ VALUE "ProductVersion", "1, 7, 0\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/providers/uspell_provider.cpp b/providers/uspell_provider.cpp new file mode 100644 index 0000000..9ed0c88 --- /dev/null +++ b/providers/uspell_provider.cpp @@ -0,0 +1,455 @@ +/* enchant + * Copyright (C) 2003 Dom Lachowicz, Raphael Finkel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +/* + * Raphael Finkel <raphael@cs.uky.edu> is the primary author of Uspell. + * See: https://github.com/AbiWord/uspell + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <string> +#include <vector> + +#include <glib.h> + +#include "enchant.h" +#include "enchant-provider.h" + +#include <uspell/utf8convert.h> +#include <uspell/uniprops.h> +#include <uspell/uspell.h> + + +static const size_t MAXALTERNATIVE = 20; // we won't return more than this number of suggestions +static const size_t MAXCHARS = 100; // maximum number of bytes of utf8 or chars of UCS4 in a word + +static GSList * +uspell_checker_get_dictionary_dirs (EnchantBroker * broker) +{ + GSList *dirs = NULL; + + { + GSList *config_dirs, *iter; + + config_dirs = enchant_get_user_config_dirs (); + + for (iter = config_dirs; iter; iter = iter->next) + { + dirs = g_slist_append (dirs, g_build_filename ((const gchar *)iter->data, + "uspell", NULL)); + } + + g_slist_free_full (config_dirs, free); + } + + { + const gchar* const * system_data_dirs = g_get_system_data_dirs (); + const gchar* const * iter; + + for (iter = system_data_dirs; *iter; iter++) + { + dirs = g_slist_append (dirs, g_build_filename (*iter, "uspell", "dicts", NULL)); + } + } + + /* Dynamically locate library and search for modules relative to it. */ + char * enchant_prefix = enchant_get_prefix_dir(); + if(enchant_prefix) + { + char * uspell_prefix = g_build_filename(enchant_prefix, "share", "enchant", "uspell", NULL); + g_free(enchant_prefix); + dirs = g_slist_append (dirs, uspell_prefix); + } + +#ifdef ENCHANT_USPELL_DICT_DIR + dirs = g_slist_append (dirs, g_strdup (ENCHANT_USPELL_DICT_DIR)); +#endif + + return dirs; +} + +static int +uspell_dict_check (EnchantDict * me, const char *const word, size_t len) +{ + uSpell *manager; + wide_t buf1[MAXCHARS], buf2[MAXCHARS], *curBuf, *otherBuf, *tmpBuf; + utf8_t myWord[MAXCHARS]; + int length; + + if (len >= MAXCHARS) + return 1; // too long; can't be right + memcpy(reinterpret_cast<char *>(myWord), word, len); + myWord[len] = 0; + curBuf = buf1; + otherBuf = buf2; + manager = reinterpret_cast<uSpell *>(me->user_data); + + length = utf8_wide(curBuf, myWord, MAXCHARS); + if (manager->isSpelledRight(curBuf, length)) { + return 0; // correct the first time + } + if (manager->theFlags & uSpell::upperLower) { + toUpper(otherBuf, curBuf, length); + if (manager->isSpelledRight(otherBuf, length)) { + manager->acceptWord(myWord); + return 0; // correct if converted to all upper case + } + tmpBuf = curBuf; + curBuf = otherBuf; + otherBuf = tmpBuf; + } + if (manager->theFlags & uSpell::hasComposition) { + unPrecompose(otherBuf, &length, curBuf, length); + if (manager->isSpelledRight(otherBuf, length)) { + manager->acceptWord(myWord); + return 0; // correct if precomposed characters expanded, all upper + } + tmpBuf = curBuf; + curBuf = otherBuf; + otherBuf = tmpBuf; + } + if (manager->theFlags & uSpell::hasCompounds) { + if (manager->isSpelledRightMultiple(curBuf, length)) { + manager->acceptWord(myWord); + return 0; // correct as two words. Not right for all languages. + } + } + return 1; +} + +static char ** +uspell_dict_suggest (EnchantDict * me, const char *const word, + size_t len, size_t * out_n_suggs) +{ + uSpell *manager; + utf8_t myWord[MAXCHARS]; + + char **sugg_arr = NULL; + const utf8_t *sugg; + wide_t buf[MAXCHARS]; + int length; + unsigned int i; + utf8_t **list; + + if (len >= MAXCHARS) // no suggestions; the word is outlandish + return NULL; + memcpy(reinterpret_cast<char *>(myWord), word, len); + myWord[len] = 0; + manager = reinterpret_cast<uSpell *>(me->user_data); + + list = reinterpret_cast<utf8_t **>( + calloc(sizeof(char *), MAXALTERNATIVE)); + length = utf8_wide(buf, myWord, MAXCHARS); + *out_n_suggs = manager->showAlternatives(buf, length, + list, MAXALTERNATIVE); + + if (*out_n_suggs) + { + sugg_arr = g_new0 (char *, *out_n_suggs + 1); + for (i = 0; i < *out_n_suggs; i++) + { + sugg = list[i]; + if (sugg) + sugg_arr[i] = + g_strdup (reinterpret_cast<const gchar *>(sugg)); + free(list[i]); + } + } + free(list); + return sugg_arr; +} // uspell_dict_suggest + +static void +uspell_dict_add_to_session (EnchantDict * me, const char *const word, + size_t len) +{ + uSpell *manager; + wide_t buf[MAXCHARS]; + utf8_t myWord[MAXCHARS]; + int length, index; + + manager = reinterpret_cast<uSpell *>(me->user_data); + + manager->acceptWord((const utf8_t *)word); + if (len >= MAXCHARS) + return; // too long; can't reasonably convert + // see if we want to acceptWord(uppercase(myWord)) + if (!(manager->theFlags & uSpell::upperLower)) return; // non-case language + length = utf8_wide(buf, (const utf8_t *)word, MAXCHARS); + for (index = 0; index < length; index++) { + if (g_unichar_isupper(buf[index])) return; // case-sensitive word + buf[index] = g_unichar_toupper(buf[index]); + } + wide_utf8(myWord, MAXCHARS, buf, length); + manager->acceptWord(myWord); +} // uspell_dict_add_to_session + +typedef struct { + const char * language_tag; + const char * corresponding_uspell_file_name; + int language_flags; +} Mapping; + +static const Mapping mapping [] = { + {"he", "hebrew", 0}, + {"he_IL", "hebrew", 0}, + {"yi", "yiddish", uSpell::hasComposition}, + {"en_US", "american", uSpell::upperLower}, +}; + +static const size_t n_mappings = (sizeof(mapping)/sizeof(mapping[0])); + +static void +s_buildHashNames (std::vector<std::string> & names, EnchantBroker * broker, const char * tag) +{ + names.clear (); + + size_t mapIndex; + + for (mapIndex = 0; mapIndex < n_mappings; mapIndex++) { + if (!strcmp(tag, mapping[mapIndex].language_tag)) + break; + } + + if (mapIndex < n_mappings) { + + GSList *dirs, *iter; + char * dict = g_strdup_printf ("%s.uspell.dat", + mapping[mapIndex].corresponding_uspell_file_name); + + dirs = uspell_checker_get_dictionary_dirs (broker); + + for (iter = dirs; iter; iter = iter->next) + { + char *tmp; + + tmp = g_build_filename ((const char *)iter->data, dict, NULL); + names.push_back (tmp); + g_free (tmp); + } + + g_slist_free_full (dirs, g_free); + } +} + +static uSpell * +uspell_request_dict (const char * base, const char * mapping, const int flags) +{ + char *fileName, *transName, *filePart, *transPart; + + uSpell *manager; + + if (!base) + return NULL; + + filePart = g_strconcat(mapping, ".uspell.dat", NULL); + transPart = g_strconcat(mapping, ".uspell.trans", NULL); + fileName = g_build_filename (base, filePart, NULL); + transName = g_build_filename (base, transPart, NULL); + g_free(filePart); + g_free(transPart); + + try { + manager = new uSpell(fileName, transName, flags); + } + catch (...) { + manager = NULL; + } + + g_free (fileName); + g_free (transName); + + return manager; +} + +static uSpell * +uspell_request_manager (const char * dir, size_t mapIndex) +{ + uSpell * manager = NULL; + + manager = uspell_request_dict (dir, + mapping[mapIndex].corresponding_uspell_file_name, + mapping[mapIndex].language_flags); + + if (!manager) return NULL; + + // look for a supplementary private dictionary + const char *config_dir = g_get_user_config_dir(); + if (config_dir) { + gchar * auxFileName, * transPart; + transPart = g_strconcat (mapping[mapIndex].language_tag, ".dic", NULL); + auxFileName = g_build_filename (config_dir, transPart, NULL); + g_free (transPart); + + (void) manager->assimilateFile (auxFileName); + g_free (auxFileName); + } + + return manager; +} + +extern "C" { + +ENCHANT_MODULE_EXPORT (EnchantProvider *) + init_enchant_provider (void); + +static EnchantDict * +uspell_provider_request_dict (EnchantProvider * me, const char *const tag) +{ + EnchantDict *dict = NULL; + uSpell *manager = NULL; + size_t mapIndex; + bool found = false; + + GSList *dirs, *iter; + + for (mapIndex = 0; mapIndex < n_mappings && !found; mapIndex++) { + if (!strcmp(tag, mapping[mapIndex].language_tag)) + break; + } + + if (!found) + return NULL; + + dirs = uspell_checker_get_dictionary_dirs (me->owner); + + for (iter = dirs; iter && !manager; iter = iter->next) + { + manager = uspell_request_manager ((const char *)iter->data, mapIndex); + } + + g_slist_free_full (dirs, g_free); + + if (!manager) + return NULL; + + dict = g_new0 (EnchantDict, 1); + dict->user_data = manager; + dict->check = uspell_dict_check; + dict->suggest = uspell_dict_suggest; + dict->add_to_session = uspell_dict_add_to_session; + // don't use personal, session - let higher level implement that + + return dict; +} + +static int +uspell_provider_dictionary_exists (struct str_enchant_provider * me, + const char *const tag) +{ + std::vector <std::string> names; + + s_buildHashNames (names, me->owner, tag); + for (size_t i = 0; i < names.size(); i++) { + if (g_file_test (names[i].c_str(), G_FILE_TEST_EXISTS)) + return 1; + } + + return 0; +} + +static void +uspell_provider_dispose_dict (EnchantProvider * me, EnchantDict * dict) +{ + uSpell *manager = reinterpret_cast<uSpell *>(dict->user_data); + delete manager; + + g_free (dict); +} + +static char ** +uspell_provider_list_dictionaries (EnchantProvider * me, + size_t * out_n_dicts) +{ + size_t i, nb; + + nb = 0; + for (i = 0; i < n_mappings; i++) + if (uspell_provider_dictionary_exists (me, mapping[i].language_tag)) + nb++; + + *out_n_dicts = nb; + if (nb == 0) + return NULL; + + char ** out_dicts = g_new0 (char *, nb + 1); + for (i = 0; i < n_mappings; i++) + if (uspell_provider_dictionary_exists (me, mapping[i].language_tag)) + out_dicts[i] = g_strdup (mapping[i].language_tag); + + return out_dicts; +} + +static void +uspell_provider_free_string_list (EnchantProvider * me, char **str_list) +{ + g_strfreev (str_list); +} + +static void +uspell_provider_dispose (EnchantProvider * me) +{ + g_free (me); +} + +static const char * +uspell_provider_identify (EnchantProvider * me) +{ + return "uspell"; +} + +static const char * +uspell_provider_describe (EnchantProvider * me) +{ + return "Uspell Provider"; +} + +EnchantProvider * +init_enchant_provider (void) +{ + EnchantProvider *provider; + + provider = g_new0 (EnchantProvider, 1); + provider->dispose = uspell_provider_dispose; + provider->request_dict = uspell_provider_request_dict; + provider->dispose_dict = uspell_provider_dispose_dict; + provider->dictionary_exists = uspell_provider_dictionary_exists; + provider->identify = uspell_provider_identify; + provider->describe = uspell_provider_describe; + provider->list_dicts = uspell_provider_list_dictionaries; + provider->free_string_list = uspell_provider_free_string_list; + + return provider; +} + +} + diff --git a/providers/voikko_provider.c b/providers/voikko_provider.c new file mode 100644 index 0000000..8a3c6f5 --- /dev/null +++ b/providers/voikko_provider.c @@ -0,0 +1,197 @@ +/* FIXME: Use current voikko API, not deprecated */ +/* enchant + * Copyright (C) 2003,2004 Dom Lachowicz + * 2006-2007 Harri Pitkänen <hatapitk@iki.fi> + * 2006 Anssi Hannula <anssi.hannula@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <libvoikko/voikko.h> +#include "unused-parameter.h" + +#include "enchant.h" +#include "enchant-provider.h" + +/** + * Voikko is a Finnish spell checker. More information is available from: + * + * http://voikko.sourceforge.net/ + */ + +static int +voikko_dict_check (EnchantDict * me, const char *const word, size_t len _GL_UNUSED_PARAMETER) +{ + int result; + int voikko_handle; + + voikko_handle = (long) me->user_data; + result = voikko_spell_cstr(voikko_handle, word); + if (result == VOIKKO_SPELL_FAILED) + return 1; + else if (result == VOIKKO_SPELL_OK) + return 0; + else + return -1; +} + +static char ** +voikko_dict_suggest (EnchantDict * me, const char *const word, + size_t len _GL_UNUSED_PARAMETER, size_t * out_n_suggs) +{ + char **sugg_arr; + int voikko_handle; + + voikko_handle = (long) me->user_data; + sugg_arr = voikko_suggest_cstr(voikko_handle, word); + if (sugg_arr == NULL) + return NULL; + for (*out_n_suggs = 0; sugg_arr[*out_n_suggs] != NULL; (*out_n_suggs)++); + return sugg_arr; +} + +static EnchantDict * +voikko_provider_request_dict (EnchantProvider * me, const char *const tag) +{ + EnchantDict *dict; + const char * voikko_error; + int voikko_handle; + + /* Only Finnish is supported at the moment */ + if (strncmp(tag, "fi_FI", 6) != 0 && strncmp(tag, "fi", 3) != 0) + return NULL; + + voikko_error = voikko_init(&voikko_handle, "fi_FI", 0); + if (voikko_error) { + enchant_provider_set_error(me, voikko_error); + return NULL; + } + + dict = g_new0 (EnchantDict, 1); + dict->user_data = (void *)(long) voikko_handle; + dict->check = voikko_dict_check; + dict->suggest = voikko_dict_suggest; + + return dict; +} + +static void +voikko_provider_dispose_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, EnchantDict * dict) +{ + voikko_terminate((long) dict->user_data); + g_free (dict); +} + +static int +voikko_provider_dictionary_exists (struct str_enchant_provider * me _GL_UNUSED_PARAMETER, + const char *const tag) +{ + int voikko_handle; + + /* Only Finnish is supported */ + if (strncmp(tag, "fi", 3) != 0) + return 0; + + /* Check that a dictionary is actually available */ + if (voikko_init(&voikko_handle, "fi_FI", 0) == NULL) { + voikko_terminate(voikko_handle); + return 1; + } + else return 0; +} + + +static char ** +voikko_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER, + size_t * out_n_dicts) +{ + char ** out_list = NULL; + int voikko_handle; + *out_n_dicts = 0; + + if (voikko_init(&voikko_handle, "fi_FI", 0) == NULL) { + voikko_terminate(voikko_handle); + *out_n_dicts = 1; + out_list = g_new0 (char *, *out_n_dicts + 1); + out_list[0] = g_strdup("fi"); + } + + return out_list; +} + +static void +voikko_provider_free_string_list (EnchantProvider * me _GL_UNUSED_PARAMETER, + char **str_list) +{ + /* FIXME: suggestion list should be freed with voikkoFreeCstrArray */ + g_strfreev (str_list); +} + +static void +voikko_provider_dispose (EnchantProvider * me) +{ + g_free (me); +} + +static const char * +voikko_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "voikko"; +} + +static const char * +voikko_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "Voikko Provider"; +} + +ENCHANT_MODULE_EXPORT (EnchantProvider *) + init_enchant_provider (void); + +EnchantProvider * +init_enchant_provider (void) +{ + EnchantProvider *provider; + + provider = g_new0 (EnchantProvider, 1); + provider->dispose = voikko_provider_dispose; + provider->request_dict = voikko_provider_request_dict; + provider->dispose_dict = voikko_provider_dispose_dict; + provider->dictionary_exists = voikko_provider_dictionary_exists; + provider->identify = voikko_provider_identify; + provider->describe = voikko_provider_describe; + provider->list_dicts = voikko_provider_list_dicts; + provider->free_string_list = voikko_provider_free_string_list; + + return provider; +} diff --git a/providers/zemberek.cpp b/providers/zemberek.cpp new file mode 100644 index 0000000..b4be828 --- /dev/null +++ b/providers/zemberek.cpp @@ -0,0 +1,121 @@ +/* Copyright (C) 2006 Barış Metin <baris@pardus.org.tr> + * Copyright (C) 2007 Serkan Kaba <serkan_kaba@yahoo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +#include "zemberek.h" + +bool zemberek_service_is_running () +{ + DBusGConnection *connection; + DBusGProxy *proxy; + GError *Error = NULL; + + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, + &Error); + if (connection == NULL) { + g_error_free (Error); + return false; + } + proxy = dbus_g_proxy_new_for_name_owner (connection, + "net.zemberekserver.server.dbus", + "/net/zemberekserver/server/dbus/ZemberekDbus", + "net.zemberekserver.server.dbus.ZemberekDbusInterface", + &Error); + + dbus_g_connection_unref (connection); + if (proxy == NULL) { + return false; + } + + g_object_unref (proxy); + return true; +} + +Zemberek::Zemberek() + : connection(nullptr), proxy(nullptr) +{ + GError *Error = NULL; + + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, + &Error); + if (connection == NULL) { + g_error_free (Error); + throw "couldn't connect to the system bus"; + } + proxy = dbus_g_proxy_new_for_name (connection, + "net.zemberekserver.server.dbus", + "/net/zemberekserver/server/dbus/ZemberekDbus", + "net.zemberekserver.server.dbus.ZemberekDbusInterface"); + + if (proxy == NULL) { + throw "couldn't connect to the Zemberek service"; + } +} + + +Zemberek::~Zemberek() +{ + if(proxy) + g_object_unref (proxy); + if(connection) + dbus_g_connection_unref (connection); +} + + +int Zemberek::checkWord(const char* word) const +{ + gboolean result; + GError *Error = NULL; + if (!dbus_g_proxy_call (proxy, "kelimeDenetle", &Error, + G_TYPE_STRING,word,G_TYPE_INVALID, + G_TYPE_BOOLEAN, &result, G_TYPE_INVALID)) { + g_error_free (Error); + return -1; + } + else { + if (result) + return 0; + else + return 1; + } +} + + +char** Zemberek::suggestWord(const char* word, size_t *out_n_suggs) +{ + char** suggs; + GError *Error = NULL; + if (!dbus_g_proxy_call (proxy, "oner", &Error, + G_TYPE_STRING,word,G_TYPE_INVALID, + G_TYPE_STRV, &suggs,G_TYPE_INVALID)) { + g_error_free (Error); + return NULL; + } + *out_n_suggs = g_strv_length(suggs); + return suggs; +} diff --git a/providers/zemberek.h b/providers/zemberek.h new file mode 100644 index 0000000..53dbf6e --- /dev/null +++ b/providers/zemberek.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2006 Barış Metin <baris@pardus.org.tr> + * Copyright (C) 2007 Serkan Kaba <serkan_kaba@yahoo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +#ifndef ZEMBEREK_H +#define ZEMBEREK_H + +#include <dbus/dbus-glib.h> +#include <glib.h> + +class Zemberek +{ +public: + Zemberek(); + ~Zemberek(); + + int checkWord(const char* word) const; + char** suggestWord(const char* word, size_t *out_n_suggs); + +private: + DBusGConnection *connection; + DBusGProxy *proxy; +}; + +bool zemberek_service_is_running (); +#endif diff --git a/providers/zemberek_provider.cpp b/providers/zemberek_provider.cpp new file mode 100644 index 0000000..47adafe --- /dev/null +++ b/providers/zemberek_provider.cpp @@ -0,0 +1,158 @@ +/* Copyright (C) 2006 Barış Metin <baris@pardus.org.tr> + * Copyright (C) 2007 Serkan Kaba <serkan_kaba@yahoo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +#include "config.h" + +#include <glib.h> +#include <string.h> + +#include "enchant.h" +#include "enchant-provider.h" +#include "unused-parameter.h" + +#include "zemberek.h" + + +extern "C" { + +ENCHANT_MODULE_EXPORT(EnchantProvider *) + init_enchant_provider(void); + +static int +zemberek_dict_check (EnchantDict * me, const char *const word, size_t len _GL_UNUSED_PARAMETER) +{ + Zemberek *checker; + checker = (Zemberek *) me->user_data; + return checker->checkWord(word); +} + +static char** +zemberek_dict_suggest (EnchantDict * me, const char *const word, + size_t len _GL_UNUSED_PARAMETER, size_t * out_n_suggs) +{ + Zemberek *checker; + checker = (Zemberek *) me->user_data; + return checker->suggestWord (word, out_n_suggs); +} + +static void +zemberek_provider_dispose(EnchantProvider *me) +{ + g_free(me); +} + +static EnchantDict* +zemberek_provider_request_dict(EnchantProvider *me _GL_UNUSED_PARAMETER, const char *tag) +{ + if (!((strcmp(tag, "tr") == 0) || (strncmp(tag, "tr_", 3) == 0))) + return NULL; // only handle turkish + + try + { + Zemberek* checker = new Zemberek(); + + EnchantDict* dict = g_new0(EnchantDict, 1); + dict->user_data = (void *) checker; + dict->check = zemberek_dict_check; + dict->suggest = zemberek_dict_suggest; + + return dict; + } + catch(...) + { + // will fail if zemberek service isn't running + return NULL; + } +} + +static void +zemberek_provider_dispose_dict (EnchantProvider * me _GL_UNUSED_PARAMETER, EnchantDict * dict) +{ + Zemberek *checker; + checker = (Zemberek *) dict->user_data; + delete checker; + g_free (dict); +} + +static const char * +zemberek_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "zemberek"; +} + +static const char * +zemberek_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER) +{ + return "Zemberek Provider"; +} + +static void +zemberek_provider_free_string_list (EnchantProvider * me _GL_UNUSED_PARAMETER, char **str_list) +{ + g_strfreev (str_list); +} + +static char ** +zemberek_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER, + size_t * out_n_dicts) +{ + if (!zemberek_service_is_running ()) + { + *out_n_dicts = 0; + return NULL; + } + else + { + char ** out_list = NULL; + *out_n_dicts = 1; + out_list = g_new0 (char *, 2); + out_list[0] = g_strdup ("tr"); + + return out_list; + } +} + +EnchantProvider * +init_enchant_provider(void) +{ + EnchantProvider *provider; + + provider = g_new0(EnchantProvider, 1); + provider->dispose = zemberek_provider_dispose; + provider->request_dict = zemberek_provider_request_dict; + provider->dispose_dict = zemberek_provider_dispose_dict; + provider->identify = zemberek_provider_identify; + provider->describe = zemberek_provider_describe; + provider->list_dicts = zemberek_provider_list_dicts; + provider->free_string_list = zemberek_provider_free_string_list; + + return provider; +} + +} |