diff -uNr myspell.orig/src/Makefile.in myspell/src/Makefile.in --- myspell.orig/src/Makefile.in 2006-06-30 00:23:45.000000000 +0300 +++ myspell/src/Makefile.in 2006-11-18 18:36:58.000000000 +0200 @@ -66,6 +66,8 @@ suggestmgr.cpp \ csutil.cpp \ myspell.cpp \ + myspellsoikko.cpp \ + myspellvoikko.cpp \ mozMySpell.cpp \ mozMySpellFactory.cpp \ $(NULL) diff -uNr myspell.orig/src/mozMySpell.cpp myspell/src/mozMySpell.cpp --- myspell.orig/src/mozMySpell.cpp 2006-06-30 01:16:17.000000000 +0300 +++ myspell/src/mozMySpell.cpp 2007-06-02 09:20:03.000000000 +0300 @@ -70,12 +70,27 @@ #include "nsICharsetConverterManager.h" #include "nsUnicharUtilCIID.h" #include "nsUnicharUtils.h" +#include "nsIConsoleService.h" +#include "nsTextFormatter.h" #include "nsCRT.h" #include static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID); +#if defined(__linux__) +#define SOIKKO_NAME "libsoikko.so" + +#elif defined(WIN32) +#define SOIKKO_NAME "libsoikko.dll" + +#else +#error "System not supported." +#endif + +#define SOIKKO_DICT_NAME "Suomi (Soikko)" +#define VOIKKO_DICT_NAME "Suomi (Voikko)" + NS_IMPL_ISUPPORTS3(mozMySpell, mozISpellCheckingEngine, nsIObserver, @@ -84,6 +99,16 @@ nsresult mozMySpell::Init() { + static PRBool theFirstCall = PR_TRUE; + if (theFirstCall) { + nsString msg; + nsCOMPtr aConsoleService = do_GetService("@mozilla.org/consoleservice;1"); + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Extended MySpell with support for Finnish language spellcheckers Soikko and Voikko.").get()); + aConsoleService->LogStringMessage(msg.get()); + theFirstCall = PR_FALSE; + } + if (!mDictionaries.Init()) return NS_ERROR_OUT_OF_MEMORY; @@ -121,70 +146,106 @@ */ NS_IMETHODIMP mozMySpell::SetDictionary(const PRUnichar *aDictionary) { - NS_ENSURE_ARG_POINTER(aDictionary); - - if (mDictionary.Equals(aDictionary)) - return NS_OK; - - nsIFile* affFile = mDictionaries.GetWeak(nsDependentString(aDictionary)); - if (!affFile) - return NS_ERROR_FILE_NOT_FOUND; - - nsCAutoString dictFileName, affFileName; - - // XXX This isn't really good. nsIFile->NativePath isn't safe for all - // character sets on Windows. - // A better way would be to QI to nsILocalFile, and get a filehandle - // from there. Only problem is that myspell wants a path - - nsresult rv = affFile->GetNativePath(affFileName); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv; + NS_ENSURE_ARG_POINTER(aDictionary); - dictFileName = affFileName; - PRInt32 dotPos = dictFileName.RFindChar('.'); - if (dotPos == -1) - return NS_ERROR_FAILURE; - - dictFileName.SetLength(dotPos); - dictFileName.AppendLiteral(".dic"); - - // SetDictionary can be called multiple times, so we might have a - // valid mMySpell instance which needs cleaned up. - delete mMySpell; - - mDictionary = aDictionary; - - mMySpell = new MySpell(affFileName.get(), - dictFileName.get()); - if (!mMySpell) - return NS_ERROR_OUT_OF_MEMORY; + if (haveVoikko && voikkoDictName.Equals(aDictionary)) { + // SetDictionary can be called multiple times, so we might have a + // valid mMySpell instance which needs cleaned up. + delete mMySpell; + + mDictionary = aDictionary; + + mMySpell = new MySpellVoikko(); + if (!mMySpell) + return NS_ERROR_OUT_OF_MEMORY; + } else if (haveSoikko && soikkoDictName.Equals(aDictionary)) { + nsCAutoString soikkoLibFileName; + nsCAutoString soikkoDictFileName; + nsCAutoString soikkoHypFileName; + + rv = soikkoLib->GetNativePath(soikkoLibFileName); + NS_ENSURE_SUCCESS(rv, rv); + + rv = soikkoDict->GetNativePath(soikkoDictFileName); + NS_ENSURE_SUCCESS(rv, rv); + + rv = soikkoHyp->GetNativePath(soikkoHypFileName); + NS_ENSURE_SUCCESS(rv, rv); + + // SetDictionary can be called multiple times, so we might have a + // valid mMySpell instance which needs cleaned up. + delete mMySpell; + + mDictionary = aDictionary; + + mMySpell = new MySpellSoikko(soikkoLibFileName.get(), soikkoDictFileName.get(), + soikkoHypFileName.get()); + if (!mMySpell) + return NS_ERROR_OUT_OF_MEMORY; + } else { + if (mDictionary.Equals(aDictionary)) + return NS_OK; + + nsIFile* affFile = mDictionaries.GetWeak(nsDependentString(aDictionary)); + if (!affFile) + return NS_ERROR_FILE_NOT_FOUND; + + nsCAutoString dictFileName, affFileName; + + // XXX This isn't really good. nsIFile->NativePath isn't safe for all + // character sets on Windows. + // A better way would be to QI to nsILocalFile, and get a filehandle + // from there. Only problem is that myspell wants a path + + nsresult rv = affFile->GetNativePath(affFileName); + NS_ENSURE_SUCCESS(rv, rv); + + dictFileName = affFileName; + PRInt32 dotPos = dictFileName.RFindChar('.'); + if (dotPos == -1) + return NS_ERROR_FAILURE; + + dictFileName.SetLength(dotPos); + dictFileName.AppendLiteral(".dic"); + + // SetDictionary can be called multiple times, so we might have a + // valid mMySpell instance which needs cleaned up. + delete mMySpell; + + mDictionary = aDictionary; + + mMySpell = new MySpell(affFileName.get(), + dictFileName.get()); + if (!mMySpell) + return NS_ERROR_OUT_OF_MEMORY; + } - nsCOMPtr ccm = - do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr ccm = + do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); - rv = ccm->GetUnicodeDecoder(mMySpell->get_dic_encoding(), + rv = ccm->GetUnicodeDecoder(mMySpell->get_dic_encoding(), getter_AddRefs(mDecoder)); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_SUCCESS(rv, rv); - rv = ccm->GetUnicodeEncoder(mMySpell->get_dic_encoding(), + rv = ccm->GetUnicodeEncoder(mMySpell->get_dic_encoding(), getter_AddRefs(mEncoder)); - NS_ENSURE_SUCCESS(rv, rv); - + NS_ENSURE_SUCCESS(rv, rv); - if (mEncoder) - mEncoder->SetOutputErrorBehavior(mEncoder->kOnError_Signal, nsnull, '?'); + if (mEncoder) + mEncoder->SetOutputErrorBehavior(mEncoder->kOnError_Signal, nsnull, '?'); - PRInt32 pos = mDictionary.FindChar('-'); - if (pos == -1) - pos = mDictionary.FindChar('_'); - - if (pos == -1) - mLanguage.Assign(mDictionary); - else - mLanguage = Substring(mDictionary, 0, pos); + PRInt32 pos = mDictionary.FindChar('-'); + if (pos == -1) + pos = mDictionary.FindChar('_'); + + if (pos == -1) + mLanguage.Assign(mDictionary); + else + mLanguage = Substring(mDictionary, 0, pos); - return NS_OK; + return NS_OK; } /* readonly attribute wstring language; */ @@ -268,11 +329,13 @@ NS_IMETHODIMP mozMySpell::GetDictionaryList(PRUnichar ***aDictionaries, PRUint32 *aCount) { + int numDict = mDictionaries.Count() + (haveVoikko ? 1 : 0) + (haveSoikko ? 1 : 0); + if (!aDictionaries || !aCount) return NS_ERROR_NULL_POINTER; AppendNewStruct ans = { - (PRUnichar**) NS_Alloc(sizeof(PRUnichar*) * mDictionaries.Count()), + (PRUnichar**) NS_Alloc(sizeof(PRUnichar*) * numDict), 0, PR_FALSE }; @@ -289,6 +352,14 @@ return NS_ERROR_OUT_OF_MEMORY; } + if (haveVoikko) { + ans.dics[ans.count++] = ToNewUnicode(voikkoDictName); + } + + if (haveSoikko) { + ans.dics[ans.count++] = ToNewUnicode(soikkoDictName); + } + *aDictionaries = ans.dics; *aCount = ans.count; @@ -302,6 +373,9 @@ nsresult rv; + haveVoikko = PR_FALSE; + haveSoikko = PR_FALSE; + nsCOMPtr dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); if (!dirSvc) @@ -337,6 +411,15 @@ if (dictDir) LoadDictionariesFromDir(dictDir); } + + do { + MySpellVoikko spell; + if (spell) { + haveVoikko = PR_TRUE; + voikkoDictName = NS_LITERAL_STRING(VOIKKO_DICT_NAME); + } + } while(0); + } void @@ -365,8 +448,62 @@ nsCOMPtr file; while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file) { nsAutoString leafName; + nsAutoString path; + file->GetLeafName(leafName); - if (!StringEndsWith(leafName, NS_LITERAL_STRING(".dic"))) + file->GetPath(path); + + if (leafName.Equals(NS_LITERAL_STRING("soikko"))) { + PRBool isDir, fileTest; + nsCOMPtr soikkoLib, soikkoDict, soikkoHyp; + file->IsDirectory(&isDir); + if (!isDir) + continue; + + rv = file->Clone(getter_AddRefs(soikkoLib)); + if (NS_FAILED(rv)) + return; + soikkoLib->Append(NS_LITERAL_STRING(SOIKKO_NAME)); + rv = soikkoLib->Exists(&fileTest); + if (NS_FAILED(rv) || !check) + continue; + + rv = file->Clone(getter_AddRefs(soikkoDict)); + if (NS_FAILED(rv)) + return; + soikkoDict->Append(NS_LITERAL_STRING("soikko-sp.fi_FI.dic")); + rv = soikkoDict->Exists(&fileTest); + if (NS_FAILED(rv) || !check) + continue; + + rv = file->Clone(getter_AddRefs(soikkoHyp)); + if (NS_FAILED(rv)) + return; + soikkoHyp->Append(NS_LITERAL_STRING("soikko-hy.fi_FI.dic")); + rv = soikkoDict->Exists(&fileTest); + if (NS_FAILED(rv) || !check) + continue; + + haveSoikko = PR_TRUE; + this->soikkoLib = soikkoLib; + this->soikkoDict = soikkoDict; + this->soikkoHyp = soikkoHyp; + this->soikkoDictName = ToNewUnicode(NS_LITERAL_STRING(SOIKKO_DICT_NAME)); + + nsString msg; + nsCAutoString soikkoDirName; + nsCOMPtr aConsoleService = do_GetService( "@mozilla.org/consoleservice;1" ); + rv = file->GetNativePath(soikkoDirName); + if (NS_FAILED(rv)) + return; + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING("Soikko found at %s.").get(), + soikkoDirName.get()); + aConsoleService->LogStringMessage(msg.get()); + + continue; + } + + if (!StringEndsWith(leafName, NS_LITERAL_STRING(".dic"))) continue; nsAutoString dict(leafName); @@ -403,7 +540,7 @@ rv = mEncoder->Convert(aStr, &inLength, *aDst, &outLength); if (NS_SUCCEEDED(rv)) - (*aDst)[outLength] = '\0'; + (*aDst)[outLength] = '\0'; return rv; } @@ -422,9 +559,9 @@ *aResult = mMySpell->spell(charsetWord); - if (!*aResult && mPersonalDictionary) + if (!*aResult && mPersonalDictionary) rv = mPersonalDictionary->Check(aWord, mLanguage.get(), aResult); - + return rv; } @@ -437,7 +574,7 @@ nsresult rv; *aSuggestionCount = 0; - + nsXPIDLCString charsetWord; rv = ConvertCharset(aWord, getter_Copies(charsetWord)); NS_ENSURE_SUCCESS(rv, rv); @@ -445,12 +582,12 @@ char ** wlst; *aSuggestionCount = mMySpell->suggest(&wlst, charsetWord); - if (*aSuggestionCount) { - *aSuggestions = (PRUnichar **)nsMemory::Alloc(*aSuggestionCount * sizeof(PRUnichar *)); + if (*aSuggestionCount) { + *aSuggestions = (PRUnichar **)nsMemory::Alloc(*aSuggestionCount * sizeof(PRUnichar *)); if (*aSuggestions) { PRUint32 index = 0; for (index = 0; index < *aSuggestionCount && NS_SUCCEEDED(rv); ++index) { - // Convert the suggestion to utf16 + // Convert the suggestion to utf16 PRInt32 inLength = nsCRT::strlen(wlst[index]); PRInt32 outLength; rv = mDecoder->GetMaxLength(wlst[index], inLength, &outLength); @@ -462,7 +599,7 @@ rv = mDecoder->Convert(wlst[index], &inLength, (*aSuggestions)[index], &outLength); if (NS_SUCCEEDED(rv)) (*aSuggestions)[index][outLength] = 0; - } + } else rv = NS_ERROR_OUT_OF_MEMORY; } @@ -474,7 +611,7 @@ else // if (*aSuggestions) rv = NS_ERROR_OUT_OF_MEMORY; } - + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aSuggestionCount, wlst); return rv; } diff -uNr myspell.orig/src/mozMySpell.h myspell/src/mozMySpell.h --- myspell.orig/src/mozMySpell.h 2006-06-30 00:46:59.000000000 +0300 +++ myspell/src/mozMySpell.h 2007-06-02 09:22:34.000000000 +0300 @@ -94,17 +94,26 @@ nsresult ConvertCharset(const PRUnichar* aStr, char ** aDst); protected: - + nsCOMPtr mPersonalDictionary; - nsCOMPtr mEncoder; - nsCOMPtr mDecoder; + nsCOMPtr mEncoder; + nsCOMPtr mDecoder; // Hashtable matches dictionary name to .aff file nsInterfaceHashtable mDictionaries; nsString mDictionary; nsString mLanguage; - MySpell *mMySpell; + MySpellBase *mMySpell; + + PRBool haveSoikko; + nsString soikkoDictName; + nsCOMPtr soikkoLib; + nsCOMPtr soikkoDict; + nsCOMPtr soikkoHyp; + + PRBool haveVoikko; + nsString voikkoDictName; }; #endif diff -uNr myspell.orig/src/myspell.hxx myspell/src/myspell.hxx --- myspell.orig/src/myspell.hxx 2005-01-13 08:20:57.000000000 +0200 +++ myspell/src/myspell.hxx 2006-12-01 19:17:38.000000000 +0200 @@ -5,13 +5,25 @@ #include "affixmgr.hxx" #include "suggestmgr.hxx" #include "csutil.hxx" +#include "nspr.h" #define NOCAP 0 #define INITCAP 1 #define ALLCAP 2 #define HUHCAP 3 -class MySpell +class MySpellBase +{ +public: + MySpellBase (void) {} + virtual ~MySpellBase () {}; + + virtual int suggest (char ***slst, const char * word) = 0; + virtual int spell (const char *) = 0; + virtual char * get_dic_encoding() = 0; +}; + +class MySpell : public MySpellBase { AffixMgr* pAMgr; HashMgr* pHMgr; @@ -22,15 +34,72 @@ public: MySpell(const char * affpath, const char * dpath); - ~MySpell(); + virtual ~MySpell(); - int suggest(char*** slst, const char * word); - int spell(const char *); - char * get_dic_encoding(); + virtual int suggest(char*** slst, const char * word); + virtual int spell(const char *); + virtual char * get_dic_encoding(); private: int cleanword(char *, const char *, int *, int *); char * check(const char *); }; +class MySpellSoikko : public MySpellBase +{ + /** I am hiding implementation from user here */ + struct spellcheck_funct; + + bool is_ok; + + /** The dynamically loadable library handle */ + PRLibrary * dl_handle; + + struct spellcheck_funct * funct; + + /** Spell checker handle */ + void * speller_handle; + + char * soikkoDir; + + char * library; + char * dictionary; + char * encoding; + +public: + MySpellSoikko (const char * soikkoLib, const char *soikkoDict, const char *soikkoHyp); + + virtual ~MySpellSoikko(); + + virtual int suggest(char *** slst, const char * word); + + virtual int spell(const char *); + + virtual char *get_dic_encoding(); + + operator bool() const { return is_ok; } +}; + + +class MySpellVoikko : public MySpellBase +{ + bool is_ok; + + /// Is the loaded library properly initialized + bool initialized_; + +public: + MySpellVoikko (void); + + virtual ~MySpellVoikko (); + + virtual int suggest (char *** slst, const char * word); + + virtual int spell (const char *); + + virtual char * get_dic_encoding(); + + operator bool () const { return is_ok; } +}; + #endif diff -uNr myspell.orig/src/myspellsoikko.cpp myspell/src/myspellsoikko.cpp --- myspell.orig/src/myspellsoikko.cpp 1970-01-01 02:00:00.000000000 +0200 +++ myspell/src/myspellsoikko.cpp 2006-12-05 20:24:03.000000000 +0200 @@ -0,0 +1,268 @@ +#include "license.readme" +#include "myspell.hxx" +#include "tm_openoffice.hxx" + +#include "nsReadableUtils.h" +#include "nsXPIDLString.h" +#include "nsISimpleEnumerator.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "mozISpellI18NManager.h" +#include "nsICharsetConverterManager.h" +#include "nsIConsoleService.h" +#include "nsTextFormatter.h" +#include "nsUnicharUtilCIID.h" +#include "nsUnicharUtils.h" +#include "nsCRT.h" + +#include +#include +#include +#include + +/* Version check */ +#define IS_VERSION_ACCEPTABLE(ver) ((ver) < 0x00020000) + +#if defined(__linux__) +#define SOIKKO_LIB_NAME "libsoikko.so" +#elif defined(WIN32) +#define SOIKKO_LIB_NAME "libsoikko.dll" +#else +#error System not supported +#endif + +#define SOIKKO_DICT_NAME "soikko-sp.fi_FI.dic" + +struct MySpellSoikko::spellcheck_funct +{ + /** The initialization function of the loaded library */ + version_func_type * version_func_; + + init_func_type * init_func_; + + /// The termination function of the loaded library + terminate_func_type* terminate_func_; + + /// The dictionary open function of the loaded library + open_func_type* open_func_; + + /// The spell checking function of the loaded library + check_func_type* check_func_; + + /// The suggestion generation function of the loaded library + suggest_func_type* suggest_func_; + + /// The encoding specification function of the loaded library + encoding_func_type* encoding_func_; + + /// The option setting function of the loaded library + option_func_type* option_func_; +}; + + +namespace +{ + + template + PRBool LoadSymbol(FunctType *funct, PRLibrary *library, const char *symbol_name) + { + union { FunctType funct; void *addr; } tmp; + tmp.addr = PR_FindSymbol(library, symbol_name); + if (tmp.addr) { + *funct = tmp.funct; + return PR_TRUE; + } else { + nsString msg; + nsCOMPtr aConsoleService = do_GetService( "@mozilla.org/consoleservice;1" ); + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING("Failed to load symbol %s.").get(), + symbol_name); + aConsoleService->LogStringMessage(msg.get()); + return PR_FALSE; + } + } + +} + +MySpellSoikko::MySpellSoikko (const char * soikkoLib, const char *soikkoDict, const char *soikkoHyp) + : is_ok (false) + , dl_handle (0) + , funct (0) + , speller_handle (0) + , library (0) + , dictionary (0) + , encoding ("ISO8859-1") +{ + library = strdup(soikkoLib); + dictionary = strdup(soikkoDict); + (void)soikkoHyp; + + nsString msg; + nsCOMPtr aConsoleService = do_GetService("@mozilla.org/consoleservice;1"); + + dl_handle = PR_LoadLibrary (library); + if (dl_handle == 0) { + nsTextFormatter::ssprintf(msg, + NS_LITERAL_STRING("Failed to load Soikko shared library %s").get(), + library); + aConsoleService->LogStringMessage(msg.get()); + return; + } + + funct = new struct spellcheck_funct; + + if (!LoadSymbol(&funct->version_func_, dl_handle, "Tm_version")) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Failed to get Soikko library version function 'TM_version' address").get(), library); + aConsoleService->LogStringMessage(msg.get()); + return; + } + + // Check the version + int version = (*funct->version_func_)(); + if (!IS_VERSION_ACCEPTABLE(version)) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Wrong Soikko version %d.").get(), version); + aConsoleService->LogStringMessage(msg.get()); + return; + } + + PRBool symbolsLoaded = PR_TRUE; + + symbolsLoaded &= LoadSymbol(&funct->init_func_, dl_handle, "Tm_init"); + symbolsLoaded &= LoadSymbol(&funct->terminate_func_, dl_handle, "Tm_terminate"); + symbolsLoaded &= LoadSymbol(&funct->open_func_, dl_handle, "Tm_open"); + symbolsLoaded &= LoadSymbol(&funct->check_func_, dl_handle, "Tm_check_buffer"); + symbolsLoaded &= LoadSymbol(&funct->suggest_func_, dl_handle, "Tm_suggest"); + symbolsLoaded &= LoadSymbol(&funct->encoding_func_, dl_handle, "Tm_set_encoding"); + symbolsLoaded &= LoadSymbol(&funct->option_func_, dl_handle, "Tm_set_option"); + + if (!symbolsLoaded) { + return; + } + + int status = (*funct->init_func_)(&speller_handle); + if (status != 0) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Failed to initialize Soikko shared library %s. Return code is %d").get(), + library, status); + aConsoleService->LogStringMessage(msg.get()); + return; + } + + status = (*funct->open_func_) (speller_handle, dictionary); + if (status != 0) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Failed to openSoikko dictionary %s. Return code is %d").get(), + dictionary, status); + aConsoleService->LogStringMessage(msg.get()); + return; + } + + status = (*funct->encoding_func_) (speller_handle, encoding); + if (status != 0) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Failed to set encoding %s for Soikko. Return code is %d").get(), + encoding, status); + aConsoleService->LogStringMessage(msg.get()); + return; + } + + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "%s successfully loaded and initialized.").get(), + library); + aConsoleService->LogStringMessage(msg.get()); + + is_ok = true; +} + + + + +MySpellSoikko::~MySpellSoikko () +{ + is_ok = false; + + if (funct) + { + if (funct->terminate_func_ && speller_handle) + (*funct->terminate_func_)(speller_handle); + delete funct; + } + + if (dl_handle) + { + PR_UnloadLibrary (dl_handle); + } + + free (library); + free (dictionary); +} + + + +int MySpellSoikko::suggest (char *** slst, const char * word) +{ + const int maxSug = 25; + const int sugBufferSize = 2048; + int ns = 0, status; + char ** wlst = (char **) calloc(maxSug, sizeof(char *)); + char * p; + char buf [sugBufferSize]; + + *slst = 0; + if (!wlst) return 0; + if (!is_ok) return 0; + + status = (*funct->suggest_func_) (speller_handle, word, strlen(word), + buf, sugBufferSize, &ns); + + if (status==0) { + int i; + p = buf; + if (ns>maxSug) ns=maxSug; + for (i=0; icheck_func_)(speller_handle, &in, &out); + if (status != 0) return 0; + + return 1; +} + + +char * MySpellSoikko::get_dic_encoding() +{ + return encoding; +} diff -uNr myspell.orig/src/myspellvoikko.cpp myspell/src/myspellvoikko.cpp --- myspell.orig/src/myspellvoikko.cpp 1970-01-01 02:00:00.000000000 +0200 +++ myspell/src/myspellvoikko.cpp 2006-12-08 20:11:53.000000000 +0200 @@ -0,0 +1,269 @@ +#include "license.readme" +#include "myspell.hxx" +#include "voikko.h" + +#include "nsReadableUtils.h" +#include "nsXPIDLString.h" +#include "nsISimpleEnumerator.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "mozISpellI18NManager.h" +#include "nsICharsetConverterManager.h" +#include "nsIConsoleService.h" +#include "nsTextFormatter.h" +#include "nsUnicharUtilCIID.h" +#include "nsUnicharUtils.h" +#include "nsCRT.h" +#include "prlock.h" + +#include +#include +#include +#include + +namespace +{ + + const char *encoding = "UTF-8"; + +#if defined(__linux__) + const char *library = "libvoikko.so.1"; +#elif defined(WIN32) + const char *library = "libvoikko-1.dll"; +#else + #error System not supported +#endif + + typedef const char * (*initvoikko_t)(int *, const char *, int); + + typedef int (*setsopt_t)(int, int, const char *); + + typedef int (*setbopt_t)(int, int, int); + + typedef int (*spell_t)(int, const char *); + + typedef char ** (*suggest_t)(int, const char *); + + typedef int (*terminate_voikko_t)(int); + + + // Only one user can use voikko at the time, so we have only one copy and locking + + PRLock *voikko_lock = NULL; + + bool libvoikko_init_tried = false; + + bool libvoikko_initialized = false; + + PRLibrary *voikko_lib = NULL; + + int voikko_users = 0; + + int voikkohandle; + + /// The initialization function of the loaded library + initvoikko_t init_func_; + + /// The termination function of the loaded library + terminate_voikko_t terminate_func_; + + /// The spell checking function of the loaded library + spell_t check_func_; + + /// The suggestion generation function of the loaded library + suggest_t suggest_func_; + + /// The option setting functions of the loaded library + setsopt_t string_option_func_; + setbopt_t boolean_option_func_; + + struct VoikkoLock + { + VoikkoLock(void) + { + PR_Lock(voikko_lock); + } + + ~VoikkoLock() + { + PR_Unlock(voikko_lock); + } + }; + + struct VoikkoPluginInit + { + VoikkoPluginInit(void) + { + voikko_lock = PR_NewLock(); + voikko_users = 0; + + voikko_lib = PR_LoadLibrary (library); + } + + ~VoikkoPluginInit() + { + if (libvoikko_initialized) + { + (*terminate_func_)(voikkohandle); + } + + if (voikko_lib) + { + PR_UnloadLibrary (voikko_lib); + } + + PR_DestroyLock(voikko_lock); + } + }; + + VoikkoPluginInit voikko_init_0_; + + template + bool LoadSymbol(FunctType *funct, const char *symbol_name) + { + union { FunctType funct; void *addr; } tmp; + tmp.addr = PR_FindSymbol(voikko_lib, symbol_name); + if (tmp.addr) { + *funct = tmp.funct; + return true; + } else { + nsString msg; + nsCOMPtr aConsoleService = do_GetService( "@mozilla.org/consoleservice;1" ); + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING("Failed to load symbol %s from %s.").get(), + symbol_name, library); + aConsoleService->LogStringMessage(msg.get()); + return false; + } + } + + bool LibvoikkoInit(void) + { + VoikkoLock lock; + if (libvoikko_init_tried) return libvoikko_initialized; + + libvoikko_init_tried = true; + + nsString msg; + nsCOMPtr aConsoleService = + do_GetService( "@mozilla.org/consoleservice;1" ); + + if (voikko_lib == 0) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING("%s is not available.").get(), library); + aConsoleService->LogStringMessage(msg.get()); + return false; + } + + bool symbols_ok = LoadSymbol(&init_func_, "voikko_init") + && LoadSymbol(&terminate_func_, "voikko_terminate") + && LoadSymbol(&check_func_, "voikko_spell_cstr") + && LoadSymbol(&suggest_func_, "voikko_suggest_cstr") + && LoadSymbol(&string_option_func_, "voikko_set_string_option") + && LoadSymbol(&boolean_option_func_, "voikko_set_bool_option"); + + if (!symbols_ok) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Failed to find at least one required symbol in %s.").get(), + library); + aConsoleService->LogStringMessage(msg.get()); + PR_UnloadLibrary (voikko_lib); + voikko_lib = NULL; + return false; + } + + const char* error = init_func_(&voikkohandle, "fi_FI", 0); + if (error != 0) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Failed to initialize libvoikko: %s.").get(), + error); + aConsoleService->LogStringMessage(msg.get()); + PR_UnloadLibrary (voikko_lib); + voikko_lib = NULL; + return false; + } + + boolean_option_func_(voikkohandle, VOIKKO_OPT_IGNORE_DOT, 1); + boolean_option_func_(voikkohandle, VOIKKO_OPT_IGNORE_NUMBERS, 1); + boolean_option_func_(voikkohandle, VOIKKO_OPT_IGNORE_UPPERCASE, 1); + + int status = string_option_func_(voikkohandle, VOIKKO_OPT_ENCODING, encoding); + if (!status) { + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "Failed to set encoding %s for libvoikko.").get(), + encoding); + aConsoleService->LogStringMessage(msg.get()); + return false; + } + + nsTextFormatter::ssprintf(msg, NS_LITERAL_STRING( + "%s is successfully loaded and initialized.").get(), + library); + aConsoleService->LogStringMessage(msg.get()); + + libvoikko_initialized = true; + return true; + } + + int check (const char * str) + { + int status; + VoikkoLock lock; + // Always return spell-check failure if not initialized properly (should never happen...). + if (!libvoikko_initialized) return 0; + + status = (*check_func_)(voikkohandle, str); + return status ? 1 : 0; + } + + char **get_suggestions (const char * word) + { + char **vsuggestions = NULL; + VoikkoLock lock; + if (!libvoikko_initialized) return NULL; + vsuggestions = (*suggest_func_) (voikkohandle, word); + return vsuggestions; + } + +} + +MySpellVoikko::MySpellVoikko (void) + : is_ok (false) +{ + if (LibvoikkoInit()) + { + is_ok = true; + } + + initialized_ = true; +} + +MySpellVoikko::~MySpellVoikko() +{ +} + +int MySpellVoikko::suggest (char *** slst, const char * word) +{ + int ns = 0; + *slst = get_suggestions(word); + if (*slst != NULL) + { + while ((*slst)[ns] != NULL) ns++; + } + return ns; +} + + +int MySpellVoikko::spell (const char * str) +{ + int status; + + // Always return spell-check failure if not initialized properly. + if (!is_ok) return 0; + status = check(str); + return status ? 1 : 0; +} + + +char * MySpellVoikko::get_dic_encoding() +{ + return (char*) encoding; +} diff -uNr myspell.orig/src/tm_openoffice.hxx myspell/src/tm_openoffice.hxx --- myspell.orig/src/tm_openoffice.hxx 1970-01-01 02:00:00.000000000 +0200 +++ myspell/src/tm_openoffice.hxx 2006-12-01 19:17:38.000000000 +0200 @@ -0,0 +1,40 @@ +/* + * TM API definitions for OpenOffice + */ + +#define TM_IGNORE_CAPS (1<<1) +#define TM_IGNORE_DIGITS (1<<2) + +struct tm_in_s { + const unsigned char *buf; + int buf_len; +}; +typedef struct tm_in_s tm_in_t; + +struct tm_out_s { + int status; + int err_start; + int err_len; + unsigned char *change; +}; +typedef struct tm_out_s tm_out_t; + +typedef int (version_func_type)(void); +typedef int (init_func_type)(void **speller_handle_ptr); +typedef int (terminate_func_type)(void *speller_handle); +typedef int (open_func_type)(void *speller_handle, + const char *dict_path); +typedef int (encoding_func_type)(void *speller_handle, + const char *encoding_name); +typedef int (option_func_type)(void *speller_handle, + const char *option_type, + const char *option_str); +typedef int (check_func_type)(void *speller_handle, + const tm_in_t *input, + tm_out_t *output); +typedef int (suggest_func_type) (void *speller_handle, + const char *word, + int word_length, + char *buffer, + int buffer_length, + int *returned_word_count); diff -uNr myspell.orig/src/voikko.h myspell/src/voikko.h --- myspell.orig/src/voikko.h 1970-01-01 02:00:00.000000000 +0200 +++ myspell/src/voikko.h 2006-12-01 19:17:38.000000000 +0200 @@ -0,0 +1,222 @@ +/* Libvoikko: Finnish spellchecker and hyphenator library + * Copyright (C) 2006 Harri Pitkänen + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *********************************************************************************/ + +/* This library should be used in the following manner: + * + * int handle; + * char * voikko_error = voikko_init(&handle, "fi_FI", 0); + * // check for errors + * // set options + * // use spell/suggest/hyphenate + * voikko_terminate(handle); + * + * This library is currently not MT safe (limitation in Malaga). If you need to use + * it in a threaded program you should use single mutex to protect all calls to this + * library. It may be necessary to set options and call spell/suggest/hyphenate in the + * same critical section. + * + * Currently Finnish is the only supported language. Acquiring more than one simultaneous + * handle is not possible in this version. + * + */ + +#ifndef VOIKKO_VOIKKO_H +#define VOIKKO_VOIKKO_H +#include + + +#undef BEGIN_C_DECLS +#undef END_C_DECLS +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else +# define BEGIN_C_DECLS /* empty */ +# define END_C_DECLS /* empty */ +#endif + + +/* Fixed limits */ +#define LIBVOIKKO_MAX_WORD_CHARS 255 +#define LIBVOIKKO_MAX_ANALYSIS_COUNT 31 + +/* Spellchecker return codes */ +#define VOIKKO_SPELL_FAILED 0 +#define VOIKKO_SPELL_OK 1 +#define VOIKKO_INTERNAL_ERROR 2 +#define VOIKKO_CHARSET_CONVERSION_FAILED 3 + +/* Boolean options */ + +/* Ignore dot at the end of the word (needed for use in some word processors) + * Default: false */ +#define VOIKKO_OPT_IGNORE_DOT 0 + +/* Ignore words containing numbers + * Default: false */ +#define VOIKKO_OPT_IGNORE_NUMBERS 1 + +/* Accept words that are written completely in uppercase letters without checking + * them at all. + * Default: false */ +#define VOIKKO_OPT_IGNORE_UPPERCASE 3 + +/* Accept words even when the first letter is in uppercase (start of sentence etc.) + * Default: true */ +#define VOIKKO_OPT_ACCEPT_FIRST_UPPERCASE 6 + +/* Accept words even when all of the letters are in uppercase. Note that this is + * not the same as VOIKKO_OPT_IGNORE_UPPERCASE: with this option the word is still + * checked, only case differences are ignored. + * Default: true */ +#define VOIKKO_OPT_ACCEPT_ALL_UPPERCASE 7 + +/* Do not insert hyphenation positions that are considered to be ugly but correct + * Default: false + * FIXME: This option is currently unimplemented */ +#define VOIKKO_OPT_NO_UGLY_HYPHENATION 4 + +/* Integer options */ + +/* There are two possible rules that can be applied when hyphenating compound words + * that can be split in more than one different way. We either take the intersection + * of (1) all possible hyphenations or (2) all hyphenations where the compound word + * has the minimal amount of parts (:= m) in it. The rule (1) is applied if and only + * if m > voikko_intersect_compound_level. + * Default: 1 */ +#define VOIKKO_INTERSECT_COMPOUND_LEVEL 5 + +/* String options */ +/* The encoding in which multibyte character strings are interpreteted and returned + * as results. + * Default: UTF-8 */ +#define VOIKKO_OPT_ENCODING 2 + + +#ifndef VOIKKO_DEFS_H +BEGIN_C_DECLS + +/** + * Initialises the library for use in the specified language. + * @param handle after succesful initialisation handle will contain a handle that + * refers to this particular instance of voikko + * @param langcode the language code, for example "fi_FI" + * @param cache_size size of the spellchecker cache. This can be -1 (no cache) or + * >= 0 ( size in bytes = 2^cache_size * (6544*sizeof(wchar_t) + 1008) ). + * TODO: This parameter is currently ignored (cache_size = 0 is assumed) + * @return null, if initialisation completed without error, otherwise a pointer + * to a string describing the error + */ +const char * voikko_init(int * handle, const char * langcode, int cache_size); + +/** + * Terminates an instance of voikko. + * @param handle voikko instance + * @return true, if termination succeeded, otherwise false + */ +int voikko_terminate(int handle); + +/** + * Sets a boolean option. + * @param handle voikko instance + * @param option option name + * @param value option value + * @return true if option was succesfully set, otherwise false + */ +int voikko_set_bool_option(int handle, int option, int value); + +/** + * Sets an integer option. + * @param handle voikko instance + * @param option option name + * @param value option value + * @return true if option was succesfully set, otherwise false + */ +int voikko_set_int_option(int handle, int option, int value); + +/** + * Sets a string option. + * @param handle voikko instance + * @param option option name + * @param value option value + * @return true if option was succesfully set, otherwise false + */ +int voikko_set_string_option(int handle, int option, const char * value); + +/** + * Checks the spelling of a character string in current multibyte encoding. + * @param handle voikko instance + * @param word word to check + * @return one of the spellchecker return codes + */ +int voikko_spell_cstr(int handle, const char * word); + +/** + * Checks the spelling of a wide character Unicode string + * @param handle voikko instance + * @param word word to check + * @return one of the spellchecker return codes + */ +int voikko_spell_ucs4(int handle, const wchar_t * word); + +/** + * Finds suggested correct spellings for given word in current multibyte encoding. + * @param handle voikko instance + * @param word word to find suggestions for + * @return null, if no suggestions could be generated. Otherwise returns a pointer to a + * null-terminated array of 0 or more strings containing the suggestions in the current + * multibyte encoding. Caller is assumed to free the strings and the array after use. + */ +char ** voikko_suggest_cstr(int handle, const char * word); + +/** + * Finds suggested correct spellings for given word in wide character Unicode string. + * @param handle voikko instance + * @param word word to find suggestions for + * @return null, if no suggestions could be generated. Otherwise returns a pointer to a + * null-terminated array of 0 or more strings containing the suggestions in wide character + * Unicode strings. Caller is assumed to free the strings and the array after use. + */ +wchar_t ** voikko_suggest_ucs4(int handle, const wchar_t * word); + +/** + * Hyphenates the given word in current multibyte encoding. + * @param handle voikko instance + * @param word word to hyphenate + * @return null-terminated character string containing the hyphenation using the following notation: + * ' ' = no hyphenation at this character, '-' = hyphenation point (character at this position + * is preserved in the hyphenated form), '=' = hyphentation point (character at this position + * is replaced by the hyphen.) Returns 0 on error. + */ +char * voikko_hyphenate_cstr(int handle, const char * word); + +/** + * Hyphenates the given word in wide character Unicode string. + * @param handle voikko instance + * @param word word to hyphenate + * @return null-terminated character string containing the hyphenation using the following notation: + * ' ' = no hyphenation at this character, '-' = hyphenation point (character at this position + * is preserved in the hyphenated form), '=' = hyphentation point (character at this position + * is replaced by the hyphen.) Returns 0 on error. + */ +char * voikko_hyphenate_ucs4(int handle, const wchar_t * word); + +END_C_DECLS +#endif + +#endif