summaryrefslogtreecommitdiff
path: root/providers
diff options
context:
space:
mode:
authorReuben Thomas <rrt@sc3d.org>2017-03-03 13:44:20 +0000
committerReuben Thomas <rrt@sc3d.org>2017-03-03 14:31:14 +0000
commitf3ea75348680074ef982808a6c301fecfdbd1518 (patch)
tree9815c8c55ddf73b0fc209508963bd6897db33110 /providers
parent6ce0987cef5af3d32f2ca7d8c35e4da3bbaf7b9c (diff)
downloadenchant-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.config13
-rw-r--r--providers/Makefile.am58
-rw-r--r--providers/applespell_checker.h49
-rw-r--r--providers/applespell_checker.mm450
-rw-r--r--providers/aspell_provider.c282
-rw-r--r--providers/hspell_provider.c296
-rw-r--r--providers/hunspell_checker.cpp551
-rw-r--r--providers/libenchant_hunspell.rc37
-rw-r--r--providers/uspell_provider.cpp455
-rw-r--r--providers/voikko_provider.c197
-rw-r--r--providers/zemberek.cpp121
-rw-r--r--providers/zemberek.h51
-rw-r--r--providers/zemberek_provider.cpp158
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;
+}
+
+}